C 的 "%s"对应以'\0'结尾的字符串

1.字符数组和字符串数组

字符数组是指数组中每一个元素为字符型(char),数组的最后一个元素也是字符型且不为字符'\0'。字符串数组中每一个元素也为字符型(char),但数组的最后一个元素为字符'\0'。字符'\0'是字符串结束的标志字符。

 

//字符数组:系统自动为ch1分配三个字节(且先不管ch1为全局或局部数组变量)
char ch1[]  = {'a', 'b', 'c'};

//字符串数组:规定了下标大小,部分被赋值时未被赋值的元素系统默认分配'\0'(int型数组赋值0给未被赋值的元素)
char ch2[5] = {'a', 'b', 'c'};

//字符串数组:"string"形式是字符串的表示形式,系统会自动的分配'\0'给数组,作为字符串的结束标志
char ch3[] = "abc";
char ch4[4] = "abc";

用sizeof函数计算每一个数组的字节大小可得:sizeof(ch1) = 3,sizeof(ch2) = 5,sizeof(ch3) = sizeof(ch4) = 4。字符在内存中占据一个字节,sizeof用来计算一个数据类型所占据空间的大小(一字节为单位)。字符数组与字符串数组的一个区别是字符串数组末尾会有系统自动为其分配的'\0'字符,而字符数组不以'\0'字符结束。

 

2. 字符(串)数组输出

在学习C语言过程中,我们经常会用"printf"以参数"%s"输出一个字符串(多用指针来输出)。在未分清字符数组与字符串数组的区别且不知道"%s"输出方式时,遇到了某些问题还是蛮有趣的。

 

(1) 程序

#include <stdio.h>

char ch1[]      = {'a', 'b', 'c'};
char ch2[]      = "abc";

int main(void)
{
        printf("String ch1 is: %s\n", ch1);
        printf("String ch2 is: %s\n", ch2);

        return 0;
}

这是一个很简单、很朴素的C程序。编译程序使之生成可执行文件:

 

 gcc -Wall char_array.c -o char_array

 

 

 

 

运行程序

./char_array

 

 

 

 

在最初我们也许并不会料到程序的输出结果是这样子的:

String ch1 is: abcabc
String ch2 is: abc

ch1输出来的值怎么会是两个”abc“呢?

 

 

这是因为:

  • ch1为字符数组,字符元素不以'\0'结束
  • 函数printf参数”%s“输出字符串会找寻存有字符'\0'那个字节,然后结束输出
  • ch1的最后一个元素的地址与ch2的地址连续
 

(2) 验证

#include <stdio.h>

char ch1[]      = {'a', 'b', 'c'};
char ch2[]      = "abc";

int main(void)
{
        //Address of ch1[0]
        printf("ch1[%d] address: %p\n", 0, ch1);

        //Address of ch1[2]
        printf("ch1[%d] address: %p\n", 2, &ch1[2]);

        //Address of ch2[0]
        printf("ch2[%d] address: %p\n", 0, &ch2[0]);

        //Print ch1, ch2
        printf("String ch1 is: %s\n", ch1);
        printf("String ch2 is: %s\n", ch2);

        return 0;
}

 
经以上编译方式后运行可执行文件得到结果如下:
ch1[0] address: 0x804967c
ch1[2] address: 0x804967e
ch2[0] address: 0x804967f
String ch1 is: abcabc
String ch2 is: abc
 
分析程序运行的结果:字符数组中每一个元素占据一个字节的内存,ch1[0]所存的地址为:0x804967c,则ch[1]的地址为0x804967d,故ch1[2]的地址为0x804967e,可喜的是紧接着定义的这个数组的首地址跟ch1最后一个元素的地址成连续关系,ch2(即ch2[0])的地址为:0x804967f
则ch1及ch2在内存中的存储形式为:
图1.字符数组ch1,字符串数组ch2在内存中的存储
分析,图1:
先撇开数据存储时都是二进制形式。根据程序输出结果可知数组存储和数组元素存储(一个数组内的元素连续存储)满足图1关系。
首先由字符数组的特点:不以字符'\0'为结束标志。
         由字符串数组特点:以字符'\0'为结束标志。
 
其次,用printf函数以参数"%s"输出字符串时过程为:
  • 从首地址开始逐字节寻址,把存储单元(一个字节)内的数据转换为相应数据应具有的的形式(如把二进制数转换为字符‘a’)
  • 直到某一个字节内存的元素为字符'\0'时,输出此字符并且寻址结束。
由以上列举的”首先、其次“来看printf("String ch1 is: %s\n", ch1);语句,原来此语句在找到了ch1中所有的元素之后并没有找到字符'\0',所以继续往下寻址打印字符,直到寻到ch2[3]地址:0x804982时遇到字符'\0'放才结束寻址。所以打印结果为地址0x804967c到地址0x8049682中存储的所有内容,内容刚好为输出的字符串"abcabc"。
 
所以,通过这个笔记可以看出C语言中printf函数中的"%s"直到遇到内存中的‘\0’标志时才会结束输出。

 

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值