手绘知识点——字符串指针

指针系列第五篇了,来到字符串指针,和上篇的数组指针极其类似,很多操作都可以照搬,我们来聊聊这位朋友的故事。

大家都知道在C语言中有三种基本数据类型:整型、实型和字符型;这里边并没有字符串类型,所以我们通常要用字符类型来表示字符串,即将字符串放到一个字符数组中,那既然都是数组(上篇我们用的是整型数组),所以很多操作是可以共用的。

字符数组中的元素为一个个字符,在内存中也是按顺序依次排序的,每个字符占一个字节大小,即一个内存基本单元的大小;除了用字符数组来表示字符串,在C语言中还可以使用字符串指针,顾名思义,字符串指针即指向字符串的指针,就像数组指针那样,我们可以使用字符串指针输出字符串中的某一个字符,直接上代码吧:

#include 
#include 
int main() {
	char str[7];
	char *s=str;
	str[0] = '1'; str[1] = '2'; str[2] = '3';
	str[3] = 'x'; str[4] = 'y'; str[5] = 'z'; 
	str[6] = '\0';
	for (int i = 0; i < strlen(str); i++) {
		printf("%c ",*(s+i));
	}
	printf("\n");
	printf("%s\n",str);
	puts(str);
	return 0;
}

我们定义了字符数组str,大小为7个字节(因为char类型在32位及以上系统中占一个字节),然后定义了字符串指针s,指向str,之后就是使用下标依次初始化,注意最后一个元素要显示地赋值“\0”,这是字符串结束标志,即printf函数输出字符串时从str(即字符串首地址)开始依次输出,直到“\0”为止,如果没有这个结束符将会发生一系列意想不到的问题,这个我们后边会展示;接下来使用字符串指针s输出str中的每一个字符,最后的puts函数是专门输出字符串的,不需要像printf函数那样指明输出格式,看结果吧:

没啥问题,在内存中str的具体表示如下图所示:

手绘知识点——字符串指针_第1张图片

当然我们还可以直接在定义str的时候初始化,即:

char str[7]="123xyz";

也可以直接赋值给字符串指针,即:

char *s="123xyz";

这样就不用显性地标出“\0”了,它会自动在末尾加上,但如果使用下标初始化则需要显性地在末尾加上“\0”

在上面的例子中如果我们去掉最后的str[6]='\0'会怎样呢,看一下结果:

手绘知识点——字符串指针_第2张图片

喔喔~乱码了...

因为没有结束符 , printf输出时从str开始往后搜寻 , 直到发现结束符'\0'为止 , 但至于何时能碰上这个结束符可就看运气了.....

这里大家可能注意到了,我们的for循环中用到的控制开关是strlen(str),之前在数组指针中提到过这个函数,与之做对比的是sizeof操作符(这里再次注意一下 , 前者是函数,后者是操作符),那我们看看在去掉str[6]='\0'的前提下这二者的输出是多少:

而在加上str[6]='\0'后二者的输出为:

显而易见,strlen计算的是字符数组中实际的元素个数(不包括字符串结束符),而sizeof计算的是字符数组定义时的大小

其实总的内容大概就这些,其余的就是很细的知识点了,建议大家先看看字符串和数组的基础知识,在这个基础上再去扩展,这样效果会更好,最后再聊几点吧:

1.字符串结束符真的很重要,如果需要使用下标挨个赋值请一定要在最后加上‘\0';

2.如果没有要求用下标初始化赋值,则建议直接赋值,如char  str=“123xyz”,这样就避免了遗忘字符串结束符;

3.字符串的两种表现形式是有区别的,字符数组表示的字符串全局数据区或栈区,字符串指针表示的字符串则存储在常量区,继而造成前者可以读写,后者只能读取,没有写入权限,即如果你打算在后者表示的字符串中修改某个字符则会报错:

手绘知识点——字符串指针_第3张图片

ps:第一次在vs2015中运行会报错,但再次运行则没有错了,但也是什么都不会输出,这应该是编译器的一种try----case机制

4.字符数组声明时最后初始化一下,比如char str[7]={0},这样现有的七个空间都会被初始化为0,但这里大家注意一下,并不是说这种赋值方式表示给所有元素都初始化为0,而是给首元素初始化为0,之后的元素系统会默认为0,这里的0表示的是ASCII中的0,即字符串结束符‘\0’ , 这也是最保险的初始化方式,避免后边忘了加上字符串结束符;

但这里大家也可以初始化为其他的值,如char str[7]={'1'},此时你输出一下str会发现结果为1,表明首元素为1,后边的六个元素都为'\0' , 所以不会输出,也就是说不管你初始化为'0','1','2'或者其他的字符,后边的元素自动初始化为‘\0’~~注意我说的是字符0123,如果你初始化为char str[7]={1},则结果为一个方块,实际表示的是SOH,大家一定要注意数字1和字符1的区别,二者最终都要转换为ASCII码,要想显示1有两种方式,第一种就是直接指明为‘1’,第二种就是数字49,即char str[7]={49},这二者都会输出1,至于为何,前边说了,字符在内存中都是用ASCII码表示的,详情见下图:

手绘知识点——字符串指针_第4张图片

最基本的二进制运算大家应该很熟悉,字符1对应的ASCII码为0110001,转换为十进制为49

如果不初始化会怎么样呢,那就很可能会产生随机值了,比如:

#include 
int main() {
	char str[7];
	puts(str);
	return 0;
}

结果为:

所以说正确的初始化也是很重要的。。

5.补充一下前边说的字符串的两种表示形式的不同,其中字符数组只能在声明时初始化,即char str[7]="123xyz" , 不能先声明再初始化,即char str[7];str="123xyz" , 这样会报错,而字符串指针则可以先声明后初始化,这是没问题的,并且可以改变指针的指向,如char str[7]="789abc";str="123xyz";这样也是没问题的,这个要区别一下前别提到的不能修改字符串的值,感兴趣的朋友可以自己试一下,看看地址有没有改变;

6.关于字符数组的初始化还有一种形式就是char str[]={'a','b','c'},这个等同于下标赋值,系统不会在最后自动加上字符串结束符,这个大家要注意一下,尽量不要使用这种初始化方式;

7.最后一点就是想到了一个关于ASCII码的问题,先看以下代码:

#include 
int main() {
	int a = 100;
	printf("%d\n", a);
	printf("%s\n", "a");
	printf("%d\n", 'a');
	return 0;
}

结果为:

这里的整型变量a以不同的方式输出则代表着不同的值,第一个代表变量a本身的值;第二个代表字符串a;第三个代表字符a所对应的ASCII码,这里大家注意一下双引号表示字符串,单引号表示字符就行了,以后不要用错,别和python中混了,后者不分单引号和双引号;

ps:现在已经是2019.10.9号凌晨0:04分了,我也没想到这点东西会整到现在,各种添加,本来打算写一点点,一不留神字数又超了。。(博客发布时间应该是10.8号的晚上八点,因为一开始出了差错导致页面闪退,文章保存到了草稿,所以就以保存到草稿的时间作为发布时间了,当然也不是从八点钟写到现在,中间有事暂停了很久~~~这也算是个bug吧,之前几篇都遇到了这个问题,而且使用edge浏览器会出现各种字符数字输入问题,使用火狐又一直闪退,且行且珍惜吧,各位晚安)

如果本篇内容对你有一点点帮助,请点个赞或者收藏关注一下,让我们一起努力

——————————————————   分割线   —————————————————————

2019.10.14更新

最近几篇手绘知识点--指针系列文章阅读量差异较大,比如第二篇耗费大量精力最终木有过百,心凉啊。。。

刚创建了一个公众号,一开始的文章是和csdn博客同步的,后续会着重来做这一块,比如发布第一手信息,抽个奖啥的,希望各位小伙伴支持一下,加个关注,如果能帮忙宣传一下就更完美了,爱你们,还是那句话,让我们一起努力,共同进步~

公众号为“非著名IT表演艺术家”,比较中二的名字,就是灵光一闪,然后这个名字就冒出来了……

大家也可以扫码关注,拜托了:
手绘知识点——字符串指针_第5张图片

你可能感兴趣的:(手绘知识点,字符串指针,字符串结束符)