c语言判断指针相等,[翻译]C语言中指针和数组是否相等?

这是一个简单的问题,但总是被忽略。特此翻译了一篇博客,讲的很清楚。这里是博客的原地址Are pointers and arrays equivalent in C?

C语言中指针和数组是否相等?

简短的答案:不相等。

详细的答案:这依赖于如何定义“相等”。指针运算和数组下标是相等的,其他方面指针和数组是不同的。

一个简单的例子展示相等性:

#include

int main()

{

char arr[] = "don't panic\n";

char* ptr = arr;

printf("%c %c\n", arr[4], ptr[4]);

printf("%c %c\n", *(arr+2), *(ptr+2));

return 0;

}

输出结果:

t t

n n

注意到下标在数组和指针中都能工作,相似地,指针运算在数组和指针中都能用。

他们如何是不同的?

在一个很重要和基本的方式中,考虑如下代码:

char array_place[100] = "dont't panic";

char* ptr_place = "don't panic";

int main()

{

char a = array_place[7];

char b = ptr_place[7];

return 0;

}

给a赋值时发生了什么?与给b赋值有什么不同?看一下编译器的分解是有用的:

(Visual C++ 2005,x86,Windows XP)

char a = array_place[7];

0041137E mov al,byte ptr [_array_place+7 (417007h)]

00411383 mov byte ptr [a],al

char b = ptr_place[7];

00411386 mov eax,dword ptr [_ptr_place (417064h)]

0041138B mov cl,byte ptr [eax+7]

0041138E mov byte ptr [b],cl

C语言中数组的语义指示数组名作为数组第一个元素的地址。因此,在给a赋值的过程中,数组的第8个字符被偏移为array_place[7]的值,移动结果地址的内容到寄存器al,然后再赋给a。

另一方面,指针的语义是十分不同的。指针仅仅是一个固定值,持有另一个内部变量的地址。因此,计算字符串第8个字符的偏移,CPU首先复制指针的值给一个寄存器,然后增加寄存器。这多出一个指令。

一个图形化的解释

右边那一列是内存地址,每个格子是内存中存储的内容。如图展示的是array_place的第一个单词。

注意到array_place是内存地址0x417000的一个简单标签,因此访问array_place[7]就是访问内存地址0x417007。如我们所看到的,编译器仅仅用0x417007代替array_place[7],不需要地址的计算。

而指针的工作方式是不同的:

ptr_place仅仅是一个变量,变量的值是一个地址。这个地址是一个字符串所在内存位置的第一个字符的地址,比较访问pointer_place[7]的分解列表能够很清楚理解编译为何如此生成编码。

C语言的变量名仅仅是一个标签

没有黑过编译器的程序员经常忽视指针,C语言的变量仅仅是内存空间的一个方便的数字字母组成的笔名。如果我们正在写代码,我们应该仅仅创建内存空间的标签,然后访问这些标签,代替硬编码内存值,后者是由编译器来做的。

实际上地址不是绝对的硬编码,因为存在载入和重分配。但这在我们的讨论之外,这里就不展开细节了。

标签是编译器在编译时分配的,从这里我们可以看出指针和数组的巨大不同。

在函数参数中数组被转换成指针

先看一段代码:

void foo(char arr_arg[], char* ptr_arg)

{

char a = arr_arg[7];

char b = ptr_arg[7];

}

问题:在这里访问a和b有什么不同吗?

回答:一点也没有!

这是编译器的展开:

char a = arr_arg[7];

00412DCE mov eax,dword ptr [arr_arg]

00412DD1 mov cl,byte ptr [eax+7]

00412DD4 mov byte ptr [a],cl

char b = ptr_arg[7];

00412DD7 mov eax,dword ptr [ptr_arg]

00412DDA mov cl,byte ptr [eax+7]

00412DDD mov byte ptr [b],cl

这是因为数组在函数的参数中总是倍转换成指针。

char arr_place[]的参数声明仅仅是char* arr_place的语法糖。

这里引用K&R2:

当数组名作为函数参数时,仅仅是初始化元素的位置。在调用函数时,参数是一个局部变量,数组名就是一个指针,一个存储内容为内存地址的变量。

如果这看起来很奇怪,再仔细想一想。回想一下前面的图。编译器在这里别无选择,数组名作为一个标签在编译时代替要表示的地址。但一个函数在编译时并没有调用,仅在运行时调用,此时在栈中倍看做是一个参数。编译器不能处理数组内部引用作为标签和把他们替换成地址,因为它不知道实际上数组在运行时传入什么。

你可能感兴趣的:(c语言判断指针相等)