今天在复习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函数的那些坑的更多相关文章

  1. C语言pow函数编写

    C语言pow函数编写 #include<stdio.h> double chaoba(double f,double q); //声明自定义函数 void main(void) { dou ...

  2. C语言-自定义函数

    C语言自定义函数 --1-- 自定义函数定义 1.1 无参无返回值函数 1.2 无参有返回值函数 1.3 有参无返回值函数 1.4 有参有返回值函数 --2-- 函数的参数 2.1 形式参数介绍和使用 ...

  3. C语言printf()函数:格式化输出函数

    C语言printf()函数:格式化输出函数 头文件:#include <stdio.h> printf()函数是最常用的格式化输出函数,其原型为:     int printf( char ...

  4. C语言的函数

    "函数"在英文的翻译是"function",无论在自然科学还是计算机科学都是这个词,而"function"的本意是"功能" ...

  5. c语言main函数返回值、参数详解(返回值是必须的,0表示正常退出)

    C语言Main函数返回值 main函数的返回值,用于说明程序的退出状态.如果返回0,则代表程序正常退出:返回其它数字的含义则由系统决定.通常,返回非零代表程序异常退出. 很多人甚至市面上的一些书籍,都 ...

  6. Go语言示例-函数返回多个值

    Go语言中函数可以返回多个值,这和其它编程语言有很大的不同.对于有其它语言编程经验的人来说,最大的障碍不是学习这个特性,而是很难想到去使用这个特性. 简单如交换两个数值的例子: package mai ...

  7. 【学习笔记】【C语言】函数

    一. 什么是函数 任何一个C语言程序都是由一个或者多个程序段(小程序)构成的,每个程序段都有自己的功能,我们一般称这些程序段为“函数”.所以,你可以说C语言程序是由函数构成的. 比如你用C语言编写了一 ...

  8. 【转载】 c语言inline函数的使用

    c语言inline函数的使用 转载自:http://blog.chinaunix.net/uid-21843265-id-3056446.html 大学在教科书上学习过inline函数,定义为inli ...

  9. 【C语言】函数和自定义函数

    函数,我之前也提到过一点点内容.其实函数是很好理解的,但是写起来又十分麻烦. 一.     函数引入 我们知道,C源程序是由函数组成的.请看下面的简单函数例子 #include <stdio.h ...

随机推荐

  1. 网络编程进阶---->>> hamc模块 socketserver模块验证合法性 两者进行通信连接

    我们在工作中经常遇到,你公司内的某一台电脑要去访问你的服务器或者一个服务端电脑,那么你是让每一台都进行连接吗?  那不可能的  你肯定要进行限定的 验证客户端链接的合法性: hamc模块 hamc也是 ...

  2. [翻译] TLTagsControl

    TLTagsControl https://github.com/ali312/TLTagsControl#tltagscontrol A nice and simple tags input con ...

  3. 文件复制(shutil)

    import shutil #拷贝整个目录树 shutil.copytree('d:\\aaa','e:\\aaa') #目标文件夹(e:\aaa)必须不存在 shutil.rmtree('e:\\a ...

  4. 排序算法(1) 快速排序 C++实现

    快速排序基本特性 时间复杂度:O(n*lgn) 最坏:O(n^2) 空间复杂度:最好情况下:O(lgn),最坏情况:O(n),平均情况:O(lgn) 不稳定. 关于快速排序的空间复杂度,谢谢@命运他爹 ...

  5. Chapter 4 Left Outer Join in MapReduce

    4.1 Introdution Consider a company such as Amazon, which has over 200 millions of users and possibly ...

  6. python strip()

    函数原型 声明:s为字符串,rm为要删除的字符序列 s.strip(rm)        删除s字符串中开头.结尾处,位于 rm删除序列的字符 s.lstrip(rm)       删除s字符串中开头 ...

  7. kubernetes 入门学习

    kubernetes 学习 kubernetes 简介 Kubernetes这个名字源自希腊语,意思是"舵手",也是"管理者","治理者"等 ...

  8. WebUploader 图片上传控件使用范例

    ​官网 http://fex.baidu.com/webuploader/getting-started.html 其实官网写的挺详细的,看官网也可以了. 引入资源 使用Web Uploader文件上 ...

  9. 【[SDOI2008]Sandy的卡片】

    被\(mhr\)的暴力干翻了 这道题做法还是非常好想的 先做一遍差分,在每个串的某尾插入一个特殊字符,再将所有的串拼接在一起 现在的问题就转化为找到一个最长的公共子串使得其出现了\(n\)次,但是在一 ...

  10. 【JavaScript】particle

    这是js实现的粒子动画,有两种模式,分别是zoom和line,它们对应的效果不同,但是原理都相同,具体分析如下: 部分程序如下: var p = this; p.originParams = orig ...