目录
1、字符串长度和初始化列表个数都小于字符数组长度,其他保持不变
2、再讨论另一种情形:在使用上述两种方法初始化时,定义时可以省略数组长度,系统会自动确定长度。
3、注意:在字符数组长度确定的情况下,如果用于初始化的初始化列表或者字符串常量长度大于字符数组长度,则会出现语法错误。
问题描述:
在定义字符数组用于存放字符串时遇到了一个小问题,即字符串长度和定义数组时需要指定的大小之间的关系。
比如有这样一个字符串:"I Love You!",一共是11个字符,但是我们定义字符数组Str[N]时,这个N应该是多少呢?
为什么这里会存在问题,看代码:
用字符串常量初始化字符数组
int main(int argc, char* argv[]) {
//用长度相同的字符串对字符数组初始化
char Str[11] = "I Love You!";
int StrLen;
StrLen = strlen(Str);
for (int i = 0; i < 11; i++) {
printf("第%d个字符是:%c\n", i + 1, Str[i]);
}
printf("\n");
printf("输出字符串为:%s\n", Str);
printf("该字符串长度为:%d\n\n", StrLen);
system("pause");
return 0;
}
可见,对于长度为11的一个字符串:"I Love You!",定义一个同样长度的字符数组Str[11]来存放它,并且直接用该字符串对数组进行初始化,其第i个元素、用strlen()求得的字符串长度以及用格式声明"%s"输出的字符串结果如图:
可见,当字符串长度和定义的字符数组长度相同时,每一个元素都准确无误地存放到了字符数组里面,但是当用strlen()求得的字符串长度以及用格式声明"%s"输出的字符串时,便出现了问题,而且有两个重要现象:
1、每一次运行这个实例,输出字符串后面跟的乱码都不一样。
2、每一串运行这个实例,求得的长度都是23。
解释:由于C语言中字符串的结尾标志都认为是空字符:'\0',但是因为字符串和数组长度相同,数组中所有位置都被有效字符占据,没有位置放置空字符,而求长度和输出字符串的过程中,原理都是检测空字符,所以必然就会出问题。在字符数组所在的内存空间之后的地址,其数据未知,所以就输出了乱码,由于没次运行实例,开辟的内存空间都不相同,所以乱码也就不同。
但是!这个用strlen()求得的字符串长度都是23这个问题,就有些让人摸不着头脑了,望指正!
通过上述现象可得出结论:
直接用与数组长度相同的字符串对字符数组初始化时,字符串中所有元素都能存进字符数组,但由于缺少空字符,在求长度和进行格式化输出时会出问题。
用初始化列表初始化字符数组
如果用初始化列表对确定长度的字符串Str[11]进行初始化,结果又会如何呢?
//用长度相同的初始化列表对字符数组初始化
char Str[11] = { 'I',' ','L','o','v','e',' ','Y','o','u','!' };
其他保持不变,结果如图:
可以看出,出现了和上述一样的问题,毋庸置疑,原因也和上述分析中的一致。
对比:为作比较,讨论以下几种情况
1、字符串长度和初始化列表个数都小于字符数组长度,其他保持不变
//1、初始化列表不变,字符数组长度提高到12,保证比初始化列表大
char Str[15] = { 'I',' ','L','o','v','e',' ','Y','o','u','!' };
//2、初始化列表不变,字符数组长度提高到12,保证比字符串长度大
char Str[15] = "I Love You!";
两种情况下的结果如下:
1、初始化列表进行初始化
2、字符串常量进行初始化
可见,二者都得到了预期的结果,这是由于在用字符串和初始化列表对确定长度的字符数组进行初始化时,如果初始化列表或者字符串的长度小于字符数组大小,那么系统会将其余的元素填充为空字符,这样求长度以及格式化输出便不会出现问题。
2、再讨论另一种情形:在使用上述两种方法初始化时,定义时可以省略数组长度,系统会自动确定长度。
即用如下方法定义和初始化:
//定义时省略数组长度,由系统自动给出
char Str[] = { 'I',' ','L','o','v','e',' ','Y','o','u','!' };
char Str[] = "I Love You!";
对于这两种情况,结果如图:
1、初始化列表进行初始化
可见,在以初始化列表进行初始化时,列表有几个元素,就存进去几个,不会在结尾加空字符,它仅仅就是个纯粹的字符数组。
2、字符串常量进行初始化
可见,对于缺省数组长度的情况下,如果用字符串常量进行初始化,系统也会自动地按字符串进行存储,即会在最后加一个空字符作为结束标志;也可以理解为:长度为N的字符串常量在内存中的存储类型为char[N+1],多的那个1便是字符串结束标志,即空字符,是系统自动加上去的。
3、注意:在字符数组长度确定的情况下,如果用于初始化的初始化列表或者字符串常量长度大于字符数组长度,则会出现语法错误。
最后再讨论用scanf()进行格式化输入字符串的各种情形
代码如下:
int main(int argc, char* argv[]) {
char Str[12];
int StrLen;
scanf("%s", Str);
StrLen = strlen(Str);
for (int i = 0; i < 15; i++) {
printf("第%d个字符是:%c\n", i + 1, Str[i]);
}
printf("\n");
printf("输出字符串为:%s\n", Str);
printf("该字符串长度为:%d\n\n", StrLen);
system("pause");
return 0;
}
1、对于键盘输入字符串长度小于字符数组长度的情况:
可见,如果字符数组没有初始化,通过格式声明"%s"进行格式化输入时,如果输入字符串长度小于字符数组长度,那么字符串中的字符会依次存入数组中,并在最后加上空字符,其余的元素不确定。
2、对于输入字符串的长度等于字符数组长度的情况:
增加如下验证语句:
printf("字符数组最后一个元素的下一个字节的内容为:%s\n\n", *(Str + 9)=='\0'?"空字符":"其他");
结果如下:
可见,通过scanf()用'%s'进行格式化输入时,输入字符串长度与字符数组长度相同的情况下,可以正常地进行格式化输出以及求长度,这一点与用长度相同的字符串常量或者初始化列表进行初始化的结果不同。
由验证的结果似乎可以推测:系统在字符数组最后一个元素的下一个字节自动存了个空字符,以作为结束标志(下一个结论推翻了这个猜测)。
3、对于键盘输入的字符串个数大于字符数组长度的情况
定义字符数组Str[5],从键盘键入长度为8的字符串"HHXXTTXS",结果如图:
可见,这结果就很有意思,虽然这个字符数组长度只有5,但后面的格式化输出却输出了所有的8个字符,而且,字符串长度也是8,而且并不是按上一个推测的结论那样,字符数组最后一个元素的下一个字节内存了空字符。
写到了这里,算是总结出了,也才想起来那个问题,即:在定义字符数组来存放字符串时,根本不用管大小问题,定义它,仅仅起到了开辟一段内存空间的作用,再进一步说,仅仅是起到了确定一个首元素地址的作用,定义时的那个长度,其实没有意义,长度为1都没问题,如果大了,反而会浪费空间。
上面干的所有事情算是验证了上一段结论,我也是试完最后一种情况,看见结果才想起这个东西,可谓是因吹斯听了。
如果最后这里没看懂,可以多复习一下C语言指针部分。