9

C语言基础非常重要,为什么字符串输出不正常呢?

 3 years ago
source link: https://blog.popkx.com/c-language-is-very-important-why-is-the-output-of-strings-abnormal/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

C语言基础非常重要,为什么字符串输出不正常呢?

发表于 2019-03-09 21:03:00   |   已被 访问: 509 次   |   分类于:   C语言   |   暂无评论

最近公司部门里来了两个刚毕业的新同事小明和小华,小伙子头脑很灵活,交待给任务时,一般都能有不错的想法。但是基本功略差,写出的C语言代码很难看。中午吃饭时,正巧跟他们碰到一起,我就提到嵌入式程序开发要注重基础,没想到被他俩鄙视了,哈哈。他们认为研究基础的都是码农,程序员要注重的是思维和架构设计。

8079eb4dc6a2e3858c303dfebcf7fc7f.png

来看看这个问题

可是,作为前线程序员,就算有好想法好设计,也得有相匹配的代码能力把它们实现出来吧。正好,今天群里有小伙伴(@别挤我)提了个问题,请看下面的C语言代码:

#include <stdio.h>

void del_space(char* str)
{
    int i, j = 0;
    for(i=0; str[i]!='\0'; i++){
        if(' '!=str[i])
            str[j++] = str[i];
    }
}
int main()
{
    char str[] = "hello Embed Time!";
    del_space(str);
    printf("%s\n", str);

    return 0;
}
5733acbb0a8053aa59d806a530fa6614.png

这个C语言程序会输出什么呢?

这段C语言代码比较简单,应该能明白小伙伴的意图是定义一个 del_space() 函数,用于删除字符串中的空格。在 main() 函数中传递给 del_space() 函数的是“hello Embed Time!”,小伙伴的预期输出应该是 "helloEmbedTime!",那么到底对不对呢?

实践是检验真理的唯一标准,我们编译并执行这段C语言代码,如下:

# gcc t.c 
# ./a.out 
helloEmbedTime!e!

发现输出居然比预期多出 "e!",怎么回事?小伙伴也比较疑惑,于是在群里提出了这个问题。

这其实是一道基础题

这道题比较典型,并没有涉及到花里胡哨的技巧,明显是一道基础题。于是我把这个问题发给了小明和小华,没有别的意思,纯粹是觉得题目比较有意思。

48e1b32ecdf6a714812b4a49a5c82d44.png

小华到现在也没有回我。小明一开始说这个题目没有意思,纯粹是应试教育的产物,但又实在手痒,就研究了一会,跟我说:“这段C语言程序之所以没有按照预期输出,是因为 del_space() 函数的输入和输出使用了同一个变量 str。”说完,又发给我他修改后的 del_space() 函数的C语言代码,如下:
#include <string.h>

void del_space(char* str)
{
     int i, j = 0;
     char a[30];

     memset(a, 0, 30);
     for(i=0; str[i]!='\0'; i++){
         if(' '!=str[i])
             a[j++] = str[i];
     }
     strcpy(str, a);
}
ff29e2d7570f79303bf2375fa3ba7de7.png

使用小明修改后的 del_space() 函数的确能够得到预期输出,但是他并没有正确回答小伙伴的C语言程序为什么没有按照预期输出。

小伙伴的C语言程序,没有按照预期输出的真正原因

其实,只要有 C语言中字符串默认“截止条件”的概念,小伙伴遇到的问题就清晰了。请看下面这几个C语言中常用的量:

int a = 8;
char b = '8';
char c[] = "8";

从人类语言来看,变量 a, b, c 都表示 8 这个符号,但是在 C语言中它们是有差异的:a 表示整数 8,b 表示字符 8,c则表示字符串 8。相信即使是 C语言初学者也明白 8 和 '8' 的区别,那字符串 “8”和字符 '8' 的区别在哪里呢?

从字面意思看,字符应该是若干个字符组成的,那么如果字符串只有 1 个字符,它就和字符一样了,也就是说 "8" 和 '8' 一样了?当然不是。在 C语言中,字符串的末尾一般都默认有字符 '\0'。也就是说,字符串“8”其实是由 '8''\0' 组成的。

781b25194d3348a0e4a0af40be4293e3.png

'\0' 一般是作为字符串的结束标志的,C语言中常用的一些字符串操作函数一般都是以字符'\0'作为“结束条件”的,例如计算字符串长度的 strlen() 函数,它从字符串首部每读入一个字符,就把计数器加一,一直读到字符'\0'结束,才把计数器内部的值返回。例如下面这段 C语言程序:
#include <stdio.h>
#include <string.h>
 int main()
{
     char a[6] = "123456";
     printf("%lu\n", strlen(a));
     a[3] = '\0';
     printf("%lu\n", strlen(a));

     return 0;
}
9d0034cdab84b44382a1712ec3c3212f.png

按照我们的分析,程序应该会输出 6 和 3,编译执行之,发现的确如此:
# gcc t.c 
# ./a.out 
6
3

现在再来看小伙伴遇到的问题,就一切清楚了,他的C语言程序未能按照预期输出的原因在于: del_space() 函数中的目标 str 没有指定结束字符 '\0',将之加上就一切正常了。请看:

void del_space(char* str)
{
     int i, j = 0;
     for(i=0; str[i]!='\0'; i++){
         if(' '!=str[i])
             str[j++] = str[i];
     }
     str[j] = '\0';
}
f7c4d417742716a3d0ba7bfe4fc58729.png

对比之下,会发现小明的程序略显啰嗦了,多用了 meset() 和 strcpy() 以及 a[30] 的时间开销和空间开销,而且,小明的程序只能处理 30 个字符长度以下的字符串。

从这个案例能够看出,至少在嵌入式C语言程序开发中,基础真的很重要。基础不扎实的话,遇到问题就很难写出消耗资源少,运行效率高的程序。你看,小伙伴遇到的问题,明明只需要多写一个字节的赋值语句就能解决,小明没能发现这一点,他新写的函数运行时会使用更大的内存,消耗更多的时间,而且函数的通用性也不够好。

阅读更多:   C语言


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK