• C语言打印输出字符串的怪事?


    #include <stdio.h>
    int main()
    {           
        char *a[]={
            "Hello World"
        };    
        char b[]={ 
            'C','D' 
        };        
        printf("%c",b);
        printf("\n");
        printf("%s",b);
    }

    C语言中的数组名,是不可修改的变量,只能在初始化的时候赋值,我们不能做类似b++,b=b+1这样的操作,否则会提示:“表达式必须是可修改的左值”。如果我们代码上写   7++;  也会提示一样的错误,但是数组名可以引用下标输出,如b[1],代表数组中的第二个值。

    上面代码传递数组b,打印输出一个字符B,很奇怪,代码中也没有看到B啊?我们通过监视窗口获取这个b所代表的地址是0x28ff42,地址最后的42的ASCII刚好就是字符B,这边地址直接被当成字符输出,当地址发生变化,这个输出值也会改变。

    最后输出一个字符串CD,为什么这边不输出地址的ASCII码了,因为%s表示输出的是字符串,所以传进来的肯定是一个地址,编译器编译的时候会通过该地址去内存中取对应的数据输出。

    下面我们改下代码,把第一个指针数组的指针符号*去掉,如下代码,看看会发生什么?

    #include <stdio.h>
    int main()
    {           
        char a[]={
            "Hello World"
        };
    
        char b[]={ 
            'C','D' 
        };        
        printf("%c",b);
        printf("\n");
        printf("%s",b);
    }

    第一行的点号因为b代表的地址已经发生了变化,所以这里也改变了

    第二行把只一个字符数组a中的全部字符都输出来了,这是为什么?

    因为C语言规定,定义了一个字符串常量,都是以字符数组的形式存储在内存中,而且会以\0表示字符串的结束。所以就算定义字符串没有带\0,实际内存存储的时候也存进去。当输出打印的时候如果遇到\0代表字符串结束了,\0不会输出。

    我们通过内存窗口看下,首先找到 b的起始地址0x28ff2e,开始打印字符,打印C,再打印D,往后发现没有00,那就继续打印,这个时候其实已经把a数组中的字符也打印来了,最后一个64刚好是a数组中d的ASCII编码,注意这边都是16进制。再往后有一个00,这时候代表字符串结束。

    如果我们希望打印b的时候,不要把a也打印出来呢,最简单的办法就是b再添加一个数组元素 ‘\0’。

    a数组中Hello World是一个字符串常量,会在程序加载的时候分配到内存堆中,当运行到该代码段的时候字符串重新复制一份到栈中,这个我们可以从编译好的汇编代码中看出来。

    栈中分配了12个字节的空间,用来存放从ds:0x403000 复制过来的Hello World\0,数组名a是栈中第一个字符的地址,我看下ds:0x403000内存

    回过头来我们看最前面那段代码,也就是定义了一个指针数组的a,  为什么最后打印的时候只输出了CD,而没有打印Hello World

    因为栈中并没有拷贝一份Hello World\0,栈中中存放了1字节的堆地址:0x403000,而这个内容的末尾刚好是0结尾,所以打印的时候遇到0代表字符串的结束,没有再打印,如果不是0结尾则继续打印。

  • 相关阅读:
    C#中的Singleton模式
    C#中的TemplateMethod模式
    从汉堡加料说起——浅谈C#中的Decorator模式
    轻松实现记录与撤销——C#中的Command模式
    分布式系统一致性问题与Raft算法(上)
    Scala函数式编程(五) 函数式的错误处理
    Spark RPC框架源码分析(三)Spark心跳机制分析
    AnalyticDB实现和特点浅析
    java并发编程 --并发问题的根源及主要解决方法
    数据的存储结构浅析LSM-Tree和B-tree
  • 原文地址:https://www.cnblogs.com/fuyun2000/p/16657803.html
Copyright © 2020-2023  润新知