前言:指针!菜鸟的终点,高手的起点。漫谈一些进阶之路上的趣事;记录一些语言本身的特性以及思想,没有STL,也没有API!
众所周知C中是没有类似 string 类型的(别给我说<string.h>),代之的是字符数组;通常我们使用以 ‘\0‘ 结尾的字符数组来表示字符串
char ch1[]={‘a‘,‘b‘,‘c‘}; char ch2[]={‘x‘,‘y‘,‘z‘,‘\0‘}; char ch3[]="123"; printf("ch1=%s,\nch2=%s,\nch3=%s,\n",ch1,ch2,ch3); /*输出: ch1=abc虁, ch2=xyz, ch3=123, */
以上代码中第一种方式初始化的是一个字符数组,能看到后面输出了几个乱码,因为 ‘%s‘ 在做参数格式化的时候会以遇到第一个 ‘\0‘ 为结尾,所以会输出多长以及输出内容都是未知的
第二种方式显得有点麻烦,所以如果你是想初始化一个字符串的话...通常情况下使用第三种方式
字符串的遍历是我们经常会用到的东西,具体有多常用呢...emm......
char ch[]="abcdefg"; int len=strlen(ch); for(int i=0;i<strlen(ch);++i) printf("%c,",ch[i]); putch(‘\n‘); for(i=0;i<len;++i) printf("%c,",ch[i]); putch(‘\n‘); for(i=0;ch[i];++i) printf("%c,",ch[i]); putch(‘\n‘); /*输出 a,b,c,d,e,f,g, a,b,c,d,e,f,g, a,b,c,d,e,f,g, */
以上示例代码 for 循环的判断条件不同,这些在编译后是有效率差异的;前两种方式是新手喜欢使用的方式
第一种判断条件是字符串的长度,调用的 strlen() 函数计算,而每次调用 strlen() 也是需要函数压栈等一系列操作的,所以理论上效率不高
第二种方式较第一种方式略有改进,for 的条件计算时不会每次都调用函数,代之的是访问变量的值(数组定长也是这种方式)
以上两种方式进行实际的内层运算时有差异,第一种因为每次都判断长度,所以当循环过程中长度被改变时 strlen() 是能够获取到变化后的长度的,而第二种不能,也就是说当循环中串长度发生改变时循环不会获取到该信息,实际使用是否要考虑这个差异取决于业务逻辑
第三种方式判断方式为当前字符是否为 ‘\0‘,这也是 strlen() 的内部实现方式,与上一种判断方式区别在于省掉一个变量(当串改变时只能获取到当前循环之后的改变)
指针是地址,字符指针就是字符的地址;定义一个字符指针变量,那么这个变量只能用来存字符的地址
char ch=‘a‘; char *pCh=&ch; printf("ch=%c,*pCh=%c",ch,*pCh); /*输出: ch=a,*pCh=a */
示例中的 ‘&‘ 是取地址运算符,‘*‘ 是取值运算符;根据运算符性质有等式 &ch==pCh and ch==*pCh
另一种字符串声明方式上例定义的 ‘ch‘ 是一个指针变量,将其赋值为 ‘abcdefg‘,值为常量(存储在常量区)
使用 ‘ch‘ 可以取到常量的值,但改变 ‘*ch‘ 时将产生运行时错误(*ch==ch[0]),原因在于常量区的值不可被改变
char ch[]="abcdefg"; for(char *pCh=ch;*pCh;++pCh) printf("%c,",*pCh); /*输出: a,b,c,d,e,f,g, */
上例中可以看到 "char *pCh=ch;" 这样的操作,根据赋值规则可知 ‘ch‘ 是一个字符的地址;赋值后的 ‘pCh‘ 与 ‘ch‘ 的区别在于前者是一个指针变量,后者是一个指针常量,这条赋值语句进行了隐式类型转换
变量的值可变而常量的值不可变,所以 ‘pCh‘ 可以自增而 ‘ch‘ 不可自增
为何使用 ‘pCh‘ 而不是 ‘ch‘?‘pCh‘ 是变量,指针运算灵活,‘*pCh‘ 也是变量,对变量本身的操作灵活;所以在使用指针循环数组时可以达到指针和值都灵活的目的
使用 ‘pCh‘ 取值时使用取值运算 ‘*‘ 而不是下标运算 ‘[]‘,虽然两种方式都可以,但取值运算快于下标运算,下标运算进行了逻辑上的二次寻址
简述了字符指针与字符数组名的关系,其它类型也基本是同样原理,毕竟也只是所占存储空间不同而已。
指针可定义为常量和变量,区别在于指针的指向是否可改变(字符指针变量 - 数组名);值也可以定义常量和变量,区别在于内存中的值是否可变(字符数组 - 字符串常量)
原文:https://www.cnblogs.com/sxdc/p/11918395.html