一个c语言字符指针问题!
ch="abcdefg";
为什么不能这样修改?:*(ch+1)='a';
char **x,str[20][100]={""};
这个x可以直接指向str吗?:x=str ;
但是这样会出错:*(*(x+2)+3)='1';
为什么???求详细解释!!! 展开
看了目前的回答,觉得还不完整。
1、为什么不能修改:
其实不一定,不让修改是一种保护。
Linux kernel前一阵子报告的严重问题的就是可以修改这个东西了。
如果能够修改,这个ch="abcdefg"的语义就不正确了。
因为,假设如果有下面的程序:
ch="abcdefg";
printf("%s\n",ch);
如果按照正常理解,应当总是打印"abcdefg",但是如果你刚才的那个能够执行,那可就不是了。
看看下面的程序:
bug:
ch="abcdefg";
printf("%s\n",ch);
*(ch+1)='a';
goto bug;
那岂不是第一次打印"abcdefg",后面都是打印"aacdefg",如果这样也可以,C语言的程序就没办法看了。
理论上,这种错误很明显,所以一般的编译器会检查出来,说编译器检查不到的说法是错误的。但是因为C语言是弱类型语言,检查出来也不汇报告,换做C++就不行了,会告诉你,ch="abcdefg",这句话有问题。因为"abcdefg"是一个const char [8],但是ch是一个 char *这种转换很危险。
---------------------------------------------------------
2、复制不行,类型不匹配,很多书上在这个问题上写的都不对。
数组类型不是指针类型,差别很多。
举个例子:
这个会报错
char *ch="abcdefg";
*(ch+1)='a';
这个呢
char ch[10]="abcdefg";
*(ch+1)='a';
先说说一维数组的类型:
char ch[10];
ch的指针的类型是
char (*p)[10];
p=&ch;
所以能够和str赋值的x的类型是:
char (*x)[100];
x=str;
或者说指针没有长度,而数组有,怎么赋值呢?
但是为什么这样又可以修改呢?:
char *ch;
ch=(char *)malloc(20);
strcpy(ch,"abcdefg");
*(ch+1)='a';
puts(ch);
这样的话输出就是aacdefg了?何解?
这个你还要慢慢学。
一般来说,堆上和栈上的东西是可以修改的。
malloc会在堆上创建东西,千万不要忘记free!!!!!!!!!!!!!!!!!!!!!!!!!!
你现在这样做,很可能未来会因为这个丢了工作。
-------------------------------
类似的,堆上的操作包括:
char *ch=strdup("abcdefg"); ( 对于VC,有些版本要写成char *ch=_strdup("abcdefg"); )
free(ch);
未来如果学习C++,还包括new/delete等等。
--------------------------------
还有栈上的:
char ch[10]="abcedfg";
(也可以写成:char ch[10];strcpy(ch, “abcdefg");)
---------------------------------
无论堆上或者栈上,如果要显示字符串,都要经过复制的步骤,在你的程序里面就是strcpy。
复制的操作,是把一个const char *,转化成char *的步骤,你可以看看strcpy那个函数。
char * strcpy(char *dest, const char* src);
其中,src是不能修改的(const char *),而dest你复制完成后,变成了char *。这个步骤去掉了const 的约束。
此外,strdup是分配内存+复制,ch[10]="abcdefg"是栈上分配内存+复制,char ch[10];是栈上分配内存。
栈上的变量有时也叫做自动变量,分配和释放是自动的,堆上的典型的包括:malloc、calloc、strdup……,必须要配合free使用。不释放内存是写程序的最大忌讳之一。
错误的原因很简单,因为编译器默认是把"abcdefg"放在代码段,代码段是不可写的,所以会出错,如果你想修改的话,建议这样声明 char s[]="abcdefg"; char *ch = s;
第二问:
可以这样
char **x;
char *p;
char str[20][100] = {"abcdefghijklmn"};
p = &str[0][0];
x = &p;
但是你操作不能这样操作*(*(x+2)+3) = '1'; 这样会修改其他变量的数据
应该改成*((*x+2*100)+3) = '1'; //相当于str[2][3]
但是为什么这样又可以修改呢?:
char *ch;
ch=(char *)malloc(20);
strcpy(ch,"abcdefg");
*(ch+1)='a';
puts(ch);
这样的话输出就是aacdefg了?何解?
ch指向a,(ch+1)指向b, *(ch+1)='a';表示把'b'替换成'a'
但是为什么这样又可以修改呢?:
char *ch;
ch=(char *)malloc(20);
strcpy(ch,"abcdefg");
*(ch+1)='a';
puts(ch);
这样的话输出就是aacdefg了?何解?
这次是动态分配的内存,在堆上分配,这种内存可以自由修改,我说的是只有常量不让修改
第一问:
因为“abcdefg”这个字符串存放在C语言定义内存的静态存储区,这个区的特点是程序运行时不能修改其内容,而当指针指向这个存储区时,也当然不可以修改啦。可修改内容的区有内存栈区和内存堆区,而静态生成的数组就定义在栈区,如果你的指针指向该区,当然就可以修改啦,所以你的程序写成这样:char *ch;char a[]="abcdefg";ch =a; 则可以这样修改:*(ch+1)=‘a’;这是因为栈区可以修改的啦。
第二问:
因为你的x是指向指针的指针,这个意思是这个x是一个指针,这个指针指向的变量的存储区必须是指针类型的,而你的str[20][100]申请的二维数组时按线性排列的存储区(如下图所示),且存储的内容是char型而不是指针型,虽然str是一个指针,但是这个指针指向的是数组的第一个元素,和一维数组的指针没有太大区别,只是区别在指针加一时是按照数组列的长度来移动指针,所以该指针不是一个指向指针的指针,而是一个指向元素的指针,当让不能赋值给指向指针的指针ch啦,一般大家都是通过一个中间的指针数组来过渡的,这样写:char **x;char *a[20];char str[20][100]={}; x=a;for(i=0to20)a[i]=str[i];这是因为a数组元素存的是指针,所以数组名是一个指向指针数组的指针,当然就可以赋值给x了。但是你要注意的是指针的移动只是按照一个元素一个元素的移动,他不会随你指向的是数组元素而变成二维数组那样的移动一个行,所以在使用多级指针而不是多维数组名时要这样写:*(*(x+2*100)+3)='1';
写的手都麻了,还画了图,楼楼加分啊!
*(*(x+2*100)+3)='1';这个还是不太理解,这个和这个:*(x+2*100+3)有什么不一样啊?也就是说
char *p;
char a[3][10]={"abcd","1234"};
p=a;
*(p+2*10+2)='5';
这样是用一级指针来修改字符‘2’,用2级指针怎么操作?不明白
你自己有没有亲自测试过?
你就确定网上说的都是真的?char *ch = “abcdefg"; *(ch+1)='a';真的不可以修改???
建议还是自己亲自动手测试一下!
附上测试代码:
#include<stdio.h>
void fun(char a[10])
{
printf("sizeof(a) = %d\n", sizeof(a));
}
int main(void)
{
char a[5] = {"abcd"};
//fun(a);
printf("a = %d\n", a);
char *p = "abcd";
*p = 'x';
printf("*p = %c\n", *p);
*(++p) = 'y';
printf("*p = %c\n", *p);
p[2] = 'z';
printf("p[2] = %c\n", p[2]);
//p[3] = '\0';
printf("*p = %s", p);
return 0;
}
对于第二个问题,你可以试一下x=str是不行的;这个问题我们不需深究;但你要记住,一 维数组
int *x=p是可以的,但是对于二维数组int **x=str是不可以的;那么我们可以这么理解记忆一维数组首地址是1,二维数组首地址是1.5;一级指针是1,二级指针式2;即一维数组首地址能给一级指针赋值;但二维数组不能给二级指针赋值。
x=str; 会出错;
*(*(x+2)+3)='1';同样会出错 你可以再编译器上试试。
但是为什么这样又可以修改呢?:
char *ch;
ch=(char *)malloc(20);
strcpy(ch,"abcdefg");
*(ch+1)='a';
puts(ch);
这样的话输出就是aacdefg了?何解?
(1)char *ch; 定义了一个char型的指针;
(2)h=(char *)malloc(20); 动态分配了一个字节的内存,并把该内存的首地址赋给了ch;
(3)trcpy(ch,"abcdefg");将指针ch指向字符串首地址,注意这个用法,我们给字符数组赋值时ch位置是字符数组的首地址,即一个指针;
(4)(ch+1)='a';将ch所指内存的下一个内存赋值‘a’,当前ch指向"abcdefg"中的'a'所在内存,
那么ch+1则指向‘b’所在内存,*(ch+1)='a';操作将b所在内存值赋成‘a’,即将‘b’替换成'a';
(5)最后输出该字符串,即aacdefg