C语言read函数的那些坑
今天在复习UNIX文件系统,用到那个read函数,但是无意中却掉到一个坑里了,用了一个多小时才找到问题根源,这里记录一下。
问题是这样的:我需要使用read和write函数把键盘输入的信息复制到输出。所以我写了如下程序:
#include<stdio.h>
#define MAXSIZE 10
int main(void)
{
char c;
char buf[MAXSIZE];
int n;
while((n = read(,buf,MAXSIZE)) > )// 海燕高尔基在苍茫的大海上狂风卷积
write(,buf,n);//从buf中输出n个字节的信息到标准输出中return ;
}
输入”HelloWorld“检测,好像没问题。但是当我输入”海燕高尔基在苍茫的大海上狂风卷积“却发现不太对了,这是个什么操作??
HelloWorld
HelloWorld
海燕高尔基在苍茫的大海上狂风卷积
海燕高尔基海上狂风卷
为什么后面那个它中间有几个字掉队了?经过多次测试我发现,如果输入的是英文字符就没问题,而中文字符字节数只要超过了那个MAXSIZE就会出问题。我一度认为,是因为读取一次read后,内存中数据对齐导致的,所以我换了几种组合,中文加英文,但是还是有问题。于是没办法,只能去读函数的原型和定义的相关描述了。函数的原型是长下面这样的:
ssize_t read(int fd, void *buf, size_t count);
该函数每次调用成功返回读取的字节数,出错返回-1并设置errno,如果在调read之前已到达文件末尾,则这次read返回0。参数count是请求读取的字节数,读上来的数据保存在缓冲区buf中,同时文件的当前读写位置向后移。注意这个读写位置和使用C标准I/O库时的读写位置有可能不同,这个读写位置是记在内核中的,而使用C标准I/O库时的读写位置是用户空间I/O缓冲区中的位置。
为了检测我读取到的到底是多少个字节,我把程序修改如下:
#include<stdio.h>
#define MAXSIZE 10
int main(void)
{
char c;
char buf[MAXSIZE];
int n;
while((n = read(,buf,MAXSIZE)) >= )// 海燕高尔基在苍茫的大海上狂风卷积
{
printf("%d\n",n);
write(,buf,n);//从buf中输出n个字节的信息到标准输出中
putchar('\n');
}
return ;
}
我很疑惑的发现:每次读到的的确是MAXSIZE个字节的数据,也把这对应的数据输出了,但是在一次循环后,中间还是跳过了MAXSIZE个字节的数据没输出。
海燕高尔基在苍茫的大海上狂风卷积 海燕高尔基 海上狂风卷
到底是什么导致了这一现象呢?我怀疑是字符与字节的问题,但是说不上到底是那个函数在处理这个出问题了。所以我另外写了一个函数测试。
#include<stdio.h>
int main(void)
{
char buf[];
char c ;
int i;
for(i = ;i < ;++i)
{
read(,buf,);
buf[] = '\0';
printf("%s\n",buf); read(,buf,);
buf[] = '\0';
printf("%s\n",buf);
}
}
我三次分别输入 ”好的\n" "好的h" “好hj”,其输出如下:
好的
好 好的h
好
h 好hj
好
j
我发现,其实在读取的时候,数据是没有任何问题的:一个中文占了两个字节,所以第一组测试数据的两个字节读了前两个字节 "好" 字并输出了,但是它下一个竟然不是读第三个字节和第四个字节的 "的" 字,而是把回车读进去并输出了!(每次输出都本来会输出一个空格,这里共输出了四个空格)
而第二组测试数据也是首先读两个字节,输出 "好" ,而第二次读取的两个字节分别是 'h' 和 '\n' 。
第三组数据前两个字节读的是 "好" ,而后两个字节读的分别是 'j' 和 '\n' 。
其实到这里,问题已经不难看出了,当我们使用read函数去读取数据时,它会按照你提供的count去读取count个字节的数据,同时文件指针后移,但是文件指针移动并非是以字节为单位来移动的!!!而是以字符为单位来移的。(这里说的字符并非只是char类型的,还包括了宽字符。我把它们都叫字符)。所以这也就导致了我最开始的那个错误。
海燕高尔基在苍茫的大海上狂风卷积 海燕高尔基 海上狂风卷
它读取了10个字节的数据,也就是读到了5个中文字;然后它把文件指针往后移动10个字符,所以在第一次调用read函数之后,文件指针已经指向了第十一个字符,也就是 "海" 字。所以下一次读取就是从这个位置开始了。
C语言read函数的那些坑的更多相关文章
- C语言pow函数编写
C语言pow函数编写 #include<stdio.h> double chaoba(double f,double q); //声明自定义函数 void main(void) { dou ...
- C语言-自定义函数
C语言自定义函数 --1-- 自定义函数定义 1.1 无参无返回值函数 1.2 无参有返回值函数 1.3 有参无返回值函数 1.4 有参有返回值函数 --2-- 函数的参数 2.1 形式参数介绍和使用 ...
- C语言printf()函数:格式化输出函数
C语言printf()函数:格式化输出函数 头文件:#include <stdio.h> printf()函数是最常用的格式化输出函数,其原型为: int printf( char ...
- C语言的函数
"函数"在英文的翻译是"function",无论在自然科学还是计算机科学都是这个词,而"function"的本意是"功能" ...
- c语言main函数返回值、参数详解(返回值是必须的,0表示正常退出)
C语言Main函数返回值 main函数的返回值,用于说明程序的退出状态.如果返回0,则代表程序正常退出:返回其它数字的含义则由系统决定.通常,返回非零代表程序异常退出. 很多人甚至市面上的一些书籍,都 ...
- Go语言示例-函数返回多个值
Go语言中函数可以返回多个值,这和其它编程语言有很大的不同.对于有其它语言编程经验的人来说,最大的障碍不是学习这个特性,而是很难想到去使用这个特性. 简单如交换两个数值的例子: package mai ...
- 【学习笔记】【C语言】函数
一. 什么是函数 任何一个C语言程序都是由一个或者多个程序段(小程序)构成的,每个程序段都有自己的功能,我们一般称这些程序段为“函数”.所以,你可以说C语言程序是由函数构成的. 比如你用C语言编写了一 ...
- 【转载】 c语言inline函数的使用
c语言inline函数的使用 转载自:http://blog.chinaunix.net/uid-21843265-id-3056446.html 大学在教科书上学习过inline函数,定义为inli ...
- 【C语言】函数和自定义函数
函数,我之前也提到过一点点内容.其实函数是很好理解的,但是写起来又十分麻烦. 一. 函数引入 我们知道,C源程序是由函数组成的.请看下面的简单函数例子 #include <stdio.h ...
随机推荐
- asp.net的HTTP请求处理过程
1.asp.net的HTTP请求处理过程 说明: (1).客户端浏览器向服务器发出一个http请求,此请求会被inetinfo.exe进程截获,然后转交给aspnet_isapi.dll进程,接着它又 ...
- 【转】15个必须知道的chrome开发者技巧
一.快速切换文件 如果你使用过sublime text,那么你可能不习惯没有Go to anything这个功能的覆盖.你会很高兴听到chrome开发者功能也有这个功能,当DevTools被打开的时候 ...
- xsd文件记录
<MESSAGE Version="1.0"> <CV_HEADER MsgType=" /> <QUERY_PROFILE> < ...
- 【重构.改善既有代码的设计】14、总结&读后感
14.总结 首先,这是一本太老的书,很多观点已经被固化或者过时了.但核心观点没有问题,虽然大多数观点已经被认为是理所当然的事情了. 重构的定义 重构分几种: 1.狭义的代码重构 就是本书讲的, ...
- grep 满足多个关键字 任意关键字 排除多个关键字
① grep -E "word1|word2|word3" file.txt 满足任意条件(word1.word2和word3之一)将匹配. ② grep word1 f ...
- IOS 缓存思路
为了提高程序的响应速度,可以考虑使用缓存(内存缓存\硬盘缓存) 第一次请求数据时内存缓存中没有数据硬盘缓存中没有数据 当服务器返回数据时,需要做以下步骤 使用服务器的数据(比如解析.显示) 将服务器的 ...
- Linux环境编程之IPC进程间通信(五):Posix消息队列1
对于管道和FIFO来说.必须应该先有读取者存在.否则先有写入者是没有意义的. 而消息队列则不同,它是一个消息链表,有足够写权限的线程可往别的队列中放置消息,有足够读权限的线程可从队列中取走消息.每一个 ...
- 2018-2019-2 网络对抗技术 20165322 Exp5 MSF基础应用
2018-2019-2 网络对抗技术 20165322 Exp5 MSF基础应用 目录 实验内容与步骤 一个主动攻击实践 MS08-067(失败) ms17_010_psexec(成功且唯一) 一个针 ...
- SQL进价2:三值逻辑和null
1.SQL中的bool类型的值有三种 普通编程语言里的布尔型只有 true 和 false 两个值,这种逻辑体系被称为二值逻辑.而 SQL 语言里,除此之外还有第三个值 unknown,因此这种逻辑体 ...
- Todolist项目总结 JavaScript+jQuery
Html部分 消息提醒,开始隐藏 内容区 2.1 标题 2.2 表单(输入框.提交按钮) 2.3 清单列表 2.4 任务详情遮罩 2.5 任务详情 3 video引入提示音乐 Css部 ...