- 将指针指向一串字符串(char *a = "abcdef";),可以以 “printf("a[2] = %c
", a[2])“ 这种方式输出字符串中第三个字符。但不能这样 “a[2] = 'G' “ 妄图将字符串中的第三个字符‘c'改为‘G‘。至于为什么,我现在是不知道了。先看代码。
1 #include <stdio.h> 2 3 int main(void) 4 { 5 char *a = "abcdef"; 6 printf("a[2] = %c ", a[2]);//可以正确输出a[2] = c 7 a[2] = 'G';//到了这里程序不正常结束。 8 9 printf("In main = %s ",a); 10 return 0; 11 }
做一点小小的改动,就可以在做到更改字符串中的某个位置的字符了。看代码:
#include <stdio.h> int main(void) { char a[10] = "abcdef"; ------> 修改这儿. printf("a[2] = %c ", a[2]);//正确输出a[2] = c a[2] = 'G'; printf("In main = %s ",a);//正确输出In main = abGdef return 0; }
这两个代码的小小差距映射出的东西很有趣。给他们加点东西继续看看。
- 这里看看在函数调用。
1 #include <stdio.h> 2 3 void change_piont(char*); 4 5 int main(void) 6 { 7 char *a = "abcdef"; 8 printf("a[2] = %c ", a[2]); 9 10 change_piont(a); 11 printf("In main = %s ",a); 12 return 0; 13 } 14 15 void change_piont(char *a) 16 { 17 printf("a[2] = %c ",a[2]);//这里可以输出a[2] = c,说明这个函数里可以访问指针a。 18 a[2] = 'g';//这里就出现错误。 19 20 } 21 /************************************** 22 * 输出结果: 23 * a[2] = c 24 * a[2] = c 25 * Segmentation fault (核心已转储) 26 * ************************************/
和第一点一样,当尝试改变字符串中某个位置的字符,就出现错误。像第一点一样,我们改动一下。
1 #include <stdio.h> 2 3 void change_piont(char*); 4 5 int main(void) 6 { 7 char a[10] = "abcdef"; ---------------> 改的仅仅是这行. 8 printf("a[2] = %c ", a[2]); 9 10 change_piont(a); 11 printf("In main = %s ",a); 12 return 0; 13 } 14 15 void change_piont(char *a) 16 { 17 printf("a[2] = %c ",a[2]); 18 a[2] = 'g'; 19 20 }
意料之中,和第一点一样,将指针改为数组后,就可以正常替换了。
到这里,我们可以先来个小总结了。
不知道你对上面的输出有没有注意到:对于初始化为指向一个句子的指针,可以用数组记号(即a[i])输出这个句子中任意一个字符。我们知道,输出数组中的值就是用数组记号来完成的。也就是说,对于定义char a[10] = "abcdef" 和 char *a = "abcdef" 都可以用数组记号a[2]输出字符串abcdef的第三个字符:c 。那么,是不是char a[10] 与 char *a 定义的abcdef 含义都一样呢?非也,首先,从上面的代码例子中可以看出,可以修改数组定义的字符串的某个序列的字符,比如在第二个代码中a[2] = 'G' 修改了字符串的第三个字符。而指针指向的字符串,不能修改其中的的字符。只能引用。还有,当你用sizeof(a)来分别输出数组a 和 指针 a ,就会发现更大的不同。当然,对于指针,sizeof(a)输出的是存储a指针的内存大小(一般是8,决定于你的系统)。如果你想输出a指针指向的地址的字节大小,就要这样sizeof(*a),对于这篇文章的例子,就是输出1 ,char 型就是占用一个字节啊。
真正的问题还在,为什么用指针定义的字符串不能用指针记号a[i] 修改其中字符的值?
指针指向的字符串是一个整体的常量。你见过有人能修改常量的么?其实还有更深层含义的东西,我隐约存在着疑问:用a[i] 可以输出这个字符串常量中的某个字符,这说明了可以知道这个字符所在的地址,那通过这个地址为什么不能修改这个地址上的值?我们平时的变量值不都是通过地址来改变的吗?
个人猜测:a[i] 也是一个常量,常量也有地址,但通过地址就不能修改常量。 - 给分配了内存的指针赋值,再看看可不可以改变。
#include <stdlib.h> #include <stdio.h> int main(void) { int number = 10; char *a = (char*)calloc(number, sizeof(char)); printf("a_size = %d ", sizeof(a)); for(int i = 0 ; i < number ; ++i){ char b = 'a'; a[i] = b+i;//用b++会失败,每次b的值都会在上面一句重新初始化。 } printf("a = %s ", a); printf("a_size1 = %d ", sizeof(a)); a[2] = 'B'; printf("a1 = %s ", a); free(a); a = NULL; //change_piont(a); // printf("In main = %s ",a); return 0; } /************************************** * a_size = 8 * a = abcdefghij * a_size1 = 8 * a1 = abBdefghij * ************************************/
给上面代码怎增加两行:
1 scanf("%s",a); 2 printf("a2 = %s ", a);
可以利用scanf函数对a指向的值任意修改(当然,不能超过number)。
问题似乎明确了起来了,再看看:1 #include <stdio.h> 2 3 int main(void) 4 { 5 char a = 'a'; 6 char *pA = &a; 7 pA[0] = 'A'; 8 printf("a = %c ",a); 9 printf("*pA = %c ",*pA); 10 11 return 0; 12 } 13 /************* 14 * a = A 15 * *pA = A 16 * **********/
终于明白了。当这样来初始化:char *a = "abcdef",实质上就是给指针a指向了一个字符串常量!!!!!而且这个字符串的每一个字符都是常量,不能修改这些常量,也不能这样scanf("%s",a)!!!!在函数调用中,如果给指针a指向了一个变量,就可以修改,但要注意,修改的是这个变量的值,而不是指针本身,就是你不能将指针指向新的地址。如果你想将指针指向新的地址,就需要将存储指针的地址传递为变元。要努力区分:存储指针的地址和指针村存储的地址。否则指针难以学好。