文件结束符EOF与空字符‘\0‘

C程序设计语言》中首次提到EOF是在下面这段代码:

 #include <stdio.h>
 /* copy input to output; 1st version */
 main()
 {
     int c;
     c = getchar();
     while (c != EOF) {
         putchar(c);
         c = getchar();
     }    
 }

这段代码作用从stdin获取一个字符输出到stdout。

一般看到这里会有疑惑:这里变量c为何要定义为int型而不是char型?为何while里的判断条件是“c != EOF”而不是“c != '\0'”?

书中原话是这么说的:

        这里需要解决如何区分文件中有效数据与输入结束符的问题。C语言采取的解决方法是:在没有输入时,getchar函数将返回一个特殊值,这个特殊值与任何实际字符都不同。这个值称为EOF(end of file,文件结束)。我们在声明变量c的时候,必须让它大到足以存放getchar函数返回的任何值。这里之所以不把c声明称char类型,是因为它必须足够大,除了能存储任何可能的字符外还要能存储文件结束符EOF。因此,我们将c声明成int类型。

        EOF定义在头文件<stdio.h>中,是个整型数,其具体是什么并不重要,只要它与任何char类型的值都不相同即可。这里使用符号常亮,可以确保程序不需要依赖于其对应的任何特定的值。

       以上解释得很清楚了,如果将c定义成char,则不能获取到char的取值范围之外的值,使用 “char c; c = getchar();”可能会发生意料之外的数据转换(类似int a = -1; unsigned int b = a;)。

        EOF不与任何实际字符相同,所有的字符都能在ascii表里128个字符里找到,acsii码表对应的十进制数从0-128,而十进制数0对应的字符就是空字符'\0'(null),EOF不存在这128个字符里,即不属于字符,而上述代码需要判断的是获取到的不是字符时结束while,空字符'\0'虽然无法从键盘输入,但也属于字符,所以此处用“c != EOF”而不是“c != '\0'”。如果需要判断是否空字符或者判断字符串是否结束则用“c != '\0'”。

EOF的值

       那EOF等于多少呢,通过代码测试printf("EOF = %d\n", EOF);可以得知EOF的值为-1

空字符'\0'

       其值为0,用以标记字符串的结束,占一个字节(空字符也是字符)。

定义一个字符串:

char str[6] = {"abcdef"};
printf("str = %s strlen(str) = %d c=%d\n", str, strlen(str), *(str + strlen(str)));
		
*(str+6) = 'g';
printf("str = %s strlen(str) = %d c=%d\n", str, strlen(str), *(str + strlen(str)));

str[4] = '\0';
printf("str = %s strlen(str) = %d c=%d\n", str, strlen(str), *(str + strlen(str)));

输出结果:

str = abcdef strlen(str) = 6 c=0
str = abcdefg strlen(str) = 7 c=0
str = abcd strlen(str) = 4 c=0

strlen以‘\0’作为字符串结束标志,即使‘\0’后面仍有字符,也不会再统计。即空字符不是字符串的一部分,所以字符串的长度并不包含空字符。

printf使用%s格式输出,同strlen一样也是一直到结束符'\0'就终止,如果字符数组里包含的字符不含'\0',则会继续往下查找,当然这就是数组越界了,容易引起未知错误,实际项目中不可这样使用。

关于<string.h>下的库函数strcpy、strcmp、strstr、strcat关于'\0'处理的简单介绍:

以char *strcpy(char *dst, char const *src)为例,若源字符串src的长度比字符数组dst的长度要长,这样src的所有字符仍然会被复制到dst,同样这里也属于数组越界。可用如下代码测试:

	char src[10] = {"ABCDEFGHIK"};
	char dst[5] = {0};

	strcpy(dst, src);
	printf("src = %s\n dst = %s\n", src, dst);

输出:

src = ABCDEFGHIK
 dst = ABCDEFGHIK

所以复制的内容需要小于dst的长度,在最后手动赋值'\0';

 

在dst的长度大于等于src的情况下,strcpy会将src的第一个字符一直到遇到结束符为止的所有字符copy到dst,用如下代码测试:

		int i = 0;
		char src[10] = {"ABCDEFGHIK"};
		char dst[10] = {0};

		src[6] = '\0';
		src[9] = '\0';
		strcpy(dst, src);
		printf("src = %s\n dst = %s\n", src, dst);
		for(i = 0; i<10; i++)
			printf("src[%d]=%d\t", i, src[i]);
		printf("\n");

		for(i = 0; i<10; i++)
			printf("dst[%d]=%d\t", i, dst[i]);
		printf("\n");

输出结果:

src = ABCDEF
 dst = ABCDEF
src[0]=65    src[1]=66    src[2]=67    src[3]=68    src[4]=69    src[5]=70    src[6]=0    src[7]=72    src[8]=73    src[9]=0    
dst[0]=65    dst[1]=66    dst[2]=67    dst[3]=68    dst[4]=69    dst[5]=70    dst[6]=0    dst[7]=0    dst[8]=0    dst[9]=0

可以看到src[6]即为结束符,虽然后面仍然有有效字符,但是不会复制。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值