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

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

来看看这个问题

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


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

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

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

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


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

这其实是一道基础题

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

小华到现在也没有回我。小明一开始说这个题目没有意思,纯粹是应试教育的产物,但又实在手痒,就研究了一会,跟我说:“这段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);
}


使用小明修改后的 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' 组成的。

'\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;
}


按照我们的分析,程序应该会输出 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';
}


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

小结

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

阅读更多:   C语言
添加新评论

icon_redface.gificon_idea.gificon_cool.gif2016kuk.gificon_mrgreen.gif2016shuai.gif2016tp.gif2016db.gif2016ch.gificon_razz.gif2016zj.gificon_sad.gificon_cry.gif2016zhh.gificon_question.gif2016jk.gif2016bs.gificon_lol.gif2016qiao.gificon_surprised.gif2016fendou.gif2016ll.gif