问题的提出:
字符串指针初始化后,使用gets函数会出错!
#include<stdio.h>
int main()
{
char *ch="abcd";
gets(ch);
puts(ch);
return 0;
}
有关资料:(百度知道)
**************************************************************
char *ch ="abcd";
ch指向的是一个字符串常量,常量不可修改
追问:双引号内的字符,称为字符串常量。
如果初始化字符数组,也是用的字符串常量,为何可以修改呢?
回答:ch是指针变量,它只负责指向某个地址,恰好它指向的是一个常量,所以不能修改所指向的常量的值;字符数组占用一定的内存空间,字符数组的初始化和赋值,其实是将字符串常量写到他自己的内存空间中,而等号右边的无名字符串常量并不会被改变,改变字符数组的值也不会改变那个无名字符串常量的值。 好绕口。。。。。。。。。总之一个原则,只有变量才可以被修改,常量不可以被修改。
追问:我能否这样理解,
程序中出现的没有赋给某个变量的双引号内的字符串,是属于静态存储类。把指针初始化到指向这个静态存储的字符串,只是引用了这个字符串。
而初始化字符数组为这个字符串,是说把这个字符串复制到了一个分配好的变量存储空间,之后再修改的,就是数组里的字符。
回答:可以这么理解
提问者评价
谢谢!
*********************************************************************
上述描述中,有一句话:“而初始化字符数组为这个字符串,是说把这个字符串复制到了一个分配好的变量存储空间,之后再修改的,就是数组里的字符。”
对于指针,我们无法验证那个区域的是常量还是变量,但是对于数组,我们可对其初始化后再修改其中某个值来对比是常量还是变量。
代码设计:
#include<stdio.h>
int main()
{
chara[10]="abcde";
a[1]='z';
return 0;
}
设置断点,debug,反汇编,单步跟踪……过程如下:
4: chara[10]="abcde";
0040E148 mov eax,[string"abcde" (00422fc8)]
0040E14D mov dword ptr[ebp-0Ch],eax
0040E150 mov cx,word ptr [string"abcde"+4 (00422fcc)]
0040E157 mov word ptr [ebp-8],cx
0040E15B xor edx,edx
0040E15D mov dword ptr [ebp-6],edx
从上面可以看出”abcde”是存储在地址00422fc8h中的,查看一下:
00422FC8 61 6263 64 65 00 00 00 abcde...
果然如此,但是我们还不知道这是常量还是数组的变量空间,所以继续:
5: a[1]='z';
0040E160 mov byte ptr [ebp-0Bh],7Ah
此时 EBP= 0018FF48,但是题意中是[ebp-0Bh],所以我们查看ebp-0Bh=0018FF48-0bh=0018FF3d中的内容。
0018FF3C 61 6263 64 65 00 00 00 abcde...
当执行完a[1]='z';指令后,
018FF3C 61 7A63 64 65 00 00 00 azcde...
我们可以看到,值已经改变了,
再回去看00422fc8内的内容:
0422FC8 61 62 63 64 65 00 00 00 abcde...
没有变!
从上面的实例中可以看出,0422FC8中的是字符串常量,而0018FF3C中的是变量,也即a数组的空间区域。
引出问题:
对指针指向的内存区域赋值:
#include<stdio.h>
int main()
{
char *a="abcdefghij";
printf("1\n");
a[1]='a';
printf("2\n");
gets(a);
return 0;
}
结果:出错。而且根据printf设置的标记,确定是"a[1]='a';"这条指令出错。
//b指向字符串常量,c指向a数组区域
#include<stdio.h>
int main()
{
char a[10]="abcdef";
printf("%d\n",a);
char *b,*c;
c=(char *)(1638204);// 18ff3b
c[1]='z';
printf("%c 1\n",c[1]);
b=(char *)(4333596);// 0042201c
b[1]='z';
printf("2\n");
return 0;
}