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