指针数组:汇编的角度来理解数组与指针

时候,种东西用习惯了也就成了理所当然事,很少再去仔细深究,尽管你有时候并不是真理解它看看下面这个例子:

char str1=”abcdefg”

char *str2=”abcdefg”

这两条语句有区别吗?答案是当然有条是声明了变量条则是声明了个指针变量嘛可是到底区别在哪里呢在C语言里这样定义后变量和指针变量操作是例如:

(假设声明了串指针p)

将str1,str2地址附值给p:

p = str1;

p=str2;

操作str1和str2值:
str1[1]=’0’;

str2[1]=’0’;

或:

*(str1+1)=’0’;

*(str2+2)=’0’;



以上语句是正确



当然以下是不正确:

str1 = p

但以下是正确:

str2=p;



可见并不能把变量当成是指针变量,那么这两者之间到底有什么区别呢还是让汇编给我们解开这个谜底吧

个简单测试



{

char str1[10]="abcdefg";

char *str2 = "abcdefg";

char *p;



str1[1]='0';

str2[1]='1';





p = str1;

p = str2;



0;

}



保存为 t.c

用cl /FAs t.c编译后分析下生成t.asm内容(省略了些次要内容:





先来看看化str1汇编:

; 3 : char str1[10]="abcdefg";

mov eax, DWORD PTR $SG586

mov DWORD PTR _str1$[ebp], eax

mov ecx, DWORD PTR $SG586+4

mov DWORD PTR _str1$[ebp+4], ecx

xor edx, edx

mov WORD PTR _str1$[ebp+8], dx

在data segment中已经声明了$SG586 :

$SG586 DB 'abcdefg', 00H

可见对str1化就是将数据段$SG586拷贝到堆栈这样对str1操作是不会改变原数据段数据

再来看看str2化:

mov DWORD PTR _str2$[ebp], OFFSET $SG588

可见对于串指针来说过程是很简单只是将数据段中串对应地址拷贝到了堆栈中

再来看看用方式来对数据变量和指针变量操作:

; 7

: str1[1]='0';

mov BYTE PTR _str1$[ebp+1], 48 ; 00000030H

; 8 : str2[1]='1';

mov eax, DWORD PTR _str2$[ebp]

mov BYTE PTR [eax+1], 49 ; 00000031H

再来看看

p = str1;

p = str2;

区别 :

; 11 : p = str1;

lea ecx, DWORD PTR _str1$[ebp] ;取str1地址在堆栈中地址,就是_str1$[ebp]地址

mov DWORD PTR _p$[ebp], ecx

; 12 : p = str2;

mov edx, DWORD PTR _str2$[ebp] ;取str2地址在数据段中地址,在_str2$[ebp]地址所在内容中

mov DWORD PTR _p$[ebp], edx

可见取地址汇编也是不,对于数据来说个用lea个用mov

至于为什么
str1 = p

不可以



str2=p;

却可以到此也就应声而解了当然如果你硬是要对str1进行直接操作那也可以像这样子:

*((char**)str1) = p;

这样str1头四个字节值就是指针p值了

来说和指针区别主要在于:如果声明变量那么变量所有值都会拷贝到当前堆栈中去因而原数据段中保存值是不会变化而对于化了指针变量来说当前堆栈中保存值只是数据值而己从变量在堆栈中存储空间来看为str1分配存储空间为(str1),即10个字节,而为str2分配空间则只有(char*)在32位CPU系统中只有四个字节在64位CPU系统中有8个字节

C语言屏蔽了和指针差异使我们可以以共同方式来使用它们这就是高级语言给编程者带来极大好处但有时候这也会给我们带来些困惑对于不满足于表面现象人来说最好办法就是下到底层来看看它实现方式现在编程语言选择已经越来越多样化各种编程工具功能也越来越强大这些都极大提高了软件开发效率和质量但是无法否认点是只有理解细节而不满足于会用就行人在软件编程中才能更加如鱼得水
Tags:  指向数组的指针 二维数组指针 函数指针数组 指针数组

延伸阅读

最新评论

发表评论