字符串?字符数组?指针?傻傻分不清楚

首先我们来看一下下面这个程序,不妨先猜猜它会输出什么哟。

#include<stdio.h>
#include<string.h>
int main(void)
{
    int a[5] = {1,2,3,4,5};
    int i = 1;
    char str1[] = "HelloWorld\n";//数组除了在被运算符sizeof操作的时候不是直接看作地址外,其余都是可以直接等同于这个数组首元素的地址的。即一个指向首元素的指针
    char *str2 = "HelloWorld\n";
    char *str6 = {"HelloWorld\n"};
    char str3[] = {"HelloWorld\n"};//事实上等同于第一种 
    char str4[] = {'H','e','l','l','o','W','o','r','l','d','\n','\0'};
    char str5[] = {'H','e','l','l','o','W','o','r','l','d','\n'};//末尾没有加 \0 结束符  最后可能会输出该数组外内存里的东西
    printf("%d  %d   %d\n",a[i],i[a],3[a]);//当执行a[i]时   事实上等同于*(a+i);   而a + i  ==  i + a;  所以,我们用i[a]也可以达到目的  同样的  3[a]也是
    //str1[2] = 'M';    // 位置1
    printf(str1);    
    //str1[2] = 'M';    // 位置2   
    //str2 = "This a Test";    // 位置3
    printf(str2);
    printf(str3);
    printf(str4);
    printf(str5);
    printf("strlrnResult:  %d %d %d %d %d\n",strlen(str1),strlen(str2),strlen(str3),strlen(str4),strlen(str5));
    printf("sizeofResult:  %d %d %d %d %d\n",sizeof(str1)/sizeof(str1[0]),sizeof(str2)/sizeof(str2[0]),sizeof(str3)/sizeof(str3[0]),sizeof(str4)/sizeof(str4[0]),sizeof(str5)/sizeof(str5[0]));
}

前面各个字符串的输出结果相信大家应该都很清楚,第五个的结果在不同机器上运行的到的结果可能会不同,事实上也存在一定的偶然性,这里我们不讨论它们,我们主要一起讨论一下定义以及最后两行输出的结果分析。

我们在C语言里,想要定义一个所谓的字符串,事实上是通过定义一个字符数组来实现的:像系统申请一块内存,然后可以再定义的时候一次性给它们都放入元素,也可以事后另外再一个个给它们赋值,要注意,如果不在定义的时候一次性赋值,后面就不要尝试偷懒直接把用双引号包住的东西直接给它了哟。

通常我们想使用字符串时定义使用比较多的方式主要是这两种:1、通过定义一个字符数组,并在初始的时候直接把一个字符串常量的值给它或者是通过一个个字符的形式赋值,如果是后者,一定不要忘记’\0‘符号。在定义一维字符数组的时候,如果直接给它赋初值了,那么数组的长度可以不显示给出 2、定义一个字符指针,并让它指向字符串常量。(注意,是常量哟,如果非刻意如此,不建议这么做)或者是让它指向另一个数组。(这也是指针的灵活性所在)

当我们使用字符指针来操作时,大家可千万别让它直接指向了一个常量!为什么?因为如果你非刻意需要一个常量的话,那你这么做的确是有点多余了。

这个指针指向的这个常量你不知道它在哪,你也不知道怎么修改值。当你需要做出改变的时候,你会发现无从下手,最后你只能无奈的放弃让这个指针指向它从而重新弄一块内存重新的到一片可控的空间。不妨试试把位置1、位置2和位置3分别取消注释看看结果,并想想为什么。

你可能要说,我本来就需要这么一个常量,我就喜欢这么做。那为什么不考虑考虑宏定义,就一定要吊死在字符指针这一棵树上呢?或许那是个更好的选择。

关于定义我们就讨论这么多啦,接下来看看最后的两个输出结果吧。

strlrnResult:  11 11 11 11 23
sizeofResult:  12 4 12 12 11

用函数strlen与运算符sizeof分别求得的结果为什么会不一样呢?我们简单分析一下就知道了:

str1和str3两种方式输出的结果不一样 是因为我们在定义字符数组的时候,如果非第四、五种定义方式,会自动为你补上一个NUL结束符作为字符的结束符。函数strlen是以’\0’(即NUL,注:并不存在这样的保留字)为结束条件的,所以strlen未计算结束符’\0‘。而运算符sizeof(str)是计算这个数组总共花费的内存大小/数组每个元素大小,也就是它包括了结束符在里面。 故后者得到的结果比前者大1.
  str2两种方式输出的结果不一样 是因为str2是采用了字符指针的方式定义的,指针的长度在同一台电脑上所占的长度是一致的。(在32位电脑中应该是4)。因为不管是什么指针,它事实上就是一个地址,使用4个字节可以存下。故sizeof(str2)得到的是这个指针本身所占的内存的大小。而strlen是将这个指针作为字符数组来对待的,因此计算的是字符数组真正的长度。
  str5两种方式输出的结果不一样,是因为前者未在自己本来地盘(也就是自己申请的那块内存)的末尾加上’\0’,因此使用strlen会一直往后找,判断后面的是不是’\0’,直到找到或者产生错误。(注:极可能发生严重的错误,尽管我自己电脑并没有,它找到了str4的结束符停止了并把str5与str4、str4的整体都包含进来了)。 而sizeof计算时,当时系统是为其分配了11个sizeof(str5[0])长度 所以结果自然就为11咯。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值