我在程序下面写了。
#include<windows.h>
#include <stdio.h>
#include<tchar.h>
#define MAX_ARG 5
#define MAX_COMMAND_LINE 10
int _tmain(int argc, LPTSTR argv[]){
BOOL exitFlag = FALSE;
TCHAR command[MAX_COMMAND_LINE], *pc;
DWORD i, localArgc;
TCHAR argstr[MAX_ARG][MAX_COMMAND_LINE] = {"abcdef", "Dravid", "sachin", "ganguli" };
char name[10] = "Happy";
// Why argstr == argstr[0]
printf("%p %p n", name, name[0] ); // name != name[0]
printf("%p %p = %pn", argstr, argstr[0], *argstr);
// Why there is no difference if it increase left or right variable value?
TCHAR *place = malloc(10 * sizeof(TCHAR *));
place = argstr[0];
printf("%c %c n", *++place, *place ); // Incremented the left parameter
printf("%c %c n", *place, *++place ); // Incremented the right parameter
return 0;
}
1( 为什么 argstr == argstr[0] ?
2(在printf中,计算是从哪一侧(右/左(进行的?
TCHAR
> 为了清楚起见,如果argstr
声明为
char argstr[MAX_ARG][MAX_COMMAND_LINE] = {"abcdef", "Dravid", "sachin", "ganguli" };
那么它的类型可以用英语表示为"MAX_COMMAND_LINE
char
数组的MAX_ARG
数组"。 另一方面,argstr[0]
的类型是"MAX_COMMAND_LINE
char
数组"。 这两个对象甚至没有兼容的类型,因此它们不能相等。
据我所知,您提供的代码实际上并没有测试它们的相等性。 也就是说,它无处试图评估argstr == argstr[0]
. 如果是这样,并且编译器值得使用,那么它至少会警告操作数之间的类型不匹配。 但是,它可能仍接受代码,并且在运行时,比较的计算结果可能为 true。 为什么?
首先,您需要认识到,在几乎所有 C 上下文中,计算结果为数组的表达式都会衰减到指向数组第一个元素的指针。 特别是,由于argstr
和argstr[0]
都指定数组,因此表达式 argstr == argstr[0]
等效于 &argstr[0] == &argstr[0][0]
。
此外,C 要求数组的第一个元素与数组本身具有相同的地址——也就是说,数组在其第一个元素之前不能包含任何填充。 因此,argstr[0][0]
的地址与argstr[0]
的地址相同。 这就是为什么如果编译器接受argstr == argstr[0]
尽管类型不匹配,它很可能计算为 true。
您实际测试的是printf()
如何打印这两个指针。 您在这里再次遇到类型问题,因为printf()
的%p
字段描述符要求相应的参数具有类型 void *
,并且实际的相应参数具有不同的(指针(类型。 从形式上讲,由于这个原因,您的代码具有未定义的行为,但是在许多所有对象指针都具有相同表示形式的实现中,它可能会产生与此正确版本相同的结果:
printf("%p %p = %pn", (void *) argstr, (void *) argstr[0], (void *) *argstr);
尽管不能保证,但很有可能以相同的方式格式化每个指针,因为它们都表示相同的地址。
首先,根据您的声明,argstr
在内存中布局如下:
+---+
argstr: |'a'| argstr[0][0]
+---+
|'b'| argstr[0][1]
+---+
|'c'| argstr[0][2]
+---+
...
+---+
|'f'| argstr[0][5]
+---+
| 0 | argstr[0][6]
+---+
...
+---+
| ? | argstr[0][9]
+---+
|'D'| argstr[1][0]
+---+
|'r'| argstr[1][1]
+---+
...
+---+
| ? | argstr[1][9]
+---+
|'s'| argstr[2][0]
+---+
...
+---+
| ? | argstr[4][9]
+---+
所有 50 个数组元素按行主顺序依次排列(即,第一行的所有元素,后跟第二行的所有元素,依此类推(。 请注意,没有为任何地方的任何指针留出存储空间。 这意味着第一个子数组(&argstr[0][0]
(的第一个元素的地址与数组的第一个元素(&argstr[0]
(的地址相同,与数组(&argstr
(的地址相同。
除非它是sizeof
或一元&
运算符的操作数,或者字符串文本用于初始化声明中的另一个数组,否则类型为"T
的 N 元素数组"的表达式将被转换("衰减"(为"指向T
的指针"类型的表达式,并且表达式的值将是数组第一个元素的地址。
在printf
调用中,表达式argstr
的类型为"5 元素数组的 10 元素数组TCHAR
"。 由于它不是sizeof
或一元&
运算符的操作数,因此将其转换为类型为"指向 10 元素数组的 TCHAR
的指针"或 TCHAR (*)[10]
的表达式,并且表达式的值是第一个元素的地址 ( &argstr[0]
(。
在同一调用中,表达式argstr[0]
的类型为"10 元素数组TCHAR
"。 由于它不是sizeof
或一元&
运算符的操作数,因此将其转换为类型为"指向TCHAR
的指针"或TCHAR *
的表达式,并且表达式的值是第一个元素(&argstr[0][0]
(的地址。
管他呢? 为什么数组表达式的类型会变成指针?
数组下标运算符[]
是根据指针算法定义的:表达式 a[i]
定义为 *(a + i)
。 给定一个地址a
,从该地址偏移i
元素(不是字节(并取消引用结果。 这是从 C 派生的 B 编程语言的延续。 在 B 中,创建了一个单独的指针作为数组定义的一部分;该指针将绑定到数组名称并指向数组的第一个元素,因此在 B 中&argstr
和&argstr[0]
确实会有所不同。
Ritchie 在设计 C 时摆脱了数组指针,但他想保留 B 的数组语义,所以他创建了上面的数组转换规则。 在像 argstr[i][j]
这样的表达式中,子表达式 argstr
首先被转换为指针值,该指针值用 [i]
下标;这给了我们另一个数组表达式,该表达式被转换为一个新的指针表达式,该表达式下标为 [j]
.
综上所述,给定声明TCHAR argstr[5][10]
,以下所有内容都是正确的:
Expression Type Decays to Value
---------- ---- --------- -----
argstr TCHAR [5][10] TCHAR (*)[10] Address of argstr[0]
&argstr TCHAR (*)[5][10] n/a Address of argstr
*argstr TCHAR [10] TCHAR * Value of argstr[0]
argstr[i] TCHAR [10] TCHAR * Address of argstr[i][0]
&argstr[i] TCHAR (*)[10] n/a Address of argstr[i]
*argstr[i] TCHAR n/a Value of argstr[i][0]
argstr[i][j] TCHAR n/a Value of argstr[i][j]
&argstr[i][j] TCHAR * n/a Address of argstr[i][j]
argstr
、&argstr
、*argstr
、argstr[0]
、&argstr[0]
和&argstr[0][0]
都产生相同的值(数组第一个元素的地址(,但表达式的类型不同。
1( 为什么 argstr == argstr[0] ?
argstr 是一个多维数组。 argstr[0]
仍然是一个数组,因此是一个地址,并且由于argstr
数据以argstr[0]
开头,内存中的地址是相同的。
2(在printf中,计算是从哪一侧(右/左(进行的?
你不会想知道的。你正在做的事情真的很危险,而且不便携。只是不要。
PS:在:
printf("%p %p n", name, name[0] );
%p
不适用于name[0]
,它是字符,而不是指针。 printf 将字符的值转换为指针的无效值。不太有趣的:)
另一方面,下面的值将产生相同的值:
printf("%p %p n", name, &name[0] );
因为数组是通过内部使用指针进行内存分配在 C 中实现的。假设一个 2D int 数组int a[5][4];
.指针用于指示为数组 a.It 分配的内存块的第一个地址可通过 a 或 a[0] 访问,因此 argstr 和 argstr[0] 指向同一 block.so argstr == argstr[0]。由于最低可寻址内存单元是字节,因此 a 或 a[0] 指向whole allocated block
的第一个字节,即 (1byte * sizeof(datatype((,因为 4 字节表示整数。假设 a 的地址 = 1000000,所以 a 包含 1000000。在a中,5*5*sizeof(int(是分配的内存块的大小,其中:
- a[0
- ][0] 或 a 指向第一行中的第一个块,大小为 4 字节(sizeof(int((
- a[0][1] 或 *(a[0]+1( 或 *(a+1( 指向第一行中的第二个块,大小为 4 字节(sizeof(int((
- a[1][0] 或 *(a + 1*5 + 0( 指向第二行的第一个块,大小为 4 字节
- 等等。
正如您将注意到的,数组是按顺序分配的,因此要找到一行,我们需要将总行号乘以当前行号得到 a[1][0]。