范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

10个C库函数的那些坑

  函数是C语言的基石,函数库是面向过程编程语言的重要组成部分。
  通常,使用库函数只需要理解其接口即可,接口和注释通常会较友好地透露如何使用的细节,而一些库函数手册还会增加一些有代表性的实例,以加强用户对其理解。但一些库函数在使用时出错频率较高,原因是实现时在安全、易使用性、效率等方面需要有所取舍,要避坑及深入理解其原因,自然需要深入理解库函数背后实现的细节。
  1 int scanf(char* format, ptrParaList) (stdio.h)
  Read from standard input under control of the format string; equivalent to fscanf(stdin, char* format, args)
  ① 全部参数为指针(第一个参数是字符指针);
  ② 读取整型或浮点型数据时会忽略掉前面的空白字符(以空白字符(isspace())为分隔);
  2 int fscanf(FILE* f, char* format, ptrParaList) (stdio.h)
  Read from the file under control of the format string.
  当试图读取文件中的一行以空白字符分隔的字符串时,字符串并不以空白字符做分隔,而是将空白字符做为普通字符一起读取。如果以空白字符分隔分隔的字符串长度固定,可以指定固定长度读取,否则需要先fgets(),然后使用strtok()来处理。sscanf()也是如此。例如要读取下面的文本:PKL071 Park-Lens 8 6.50 BLJ372 Ball-Joint 12 11.95 PKL073 Park-Lens 8 6.50 FLT014 Oil-Filter 23 7.95 DKP085 Disc-Pads 16 9.99 GSF556 Gas-Filter 9 4.50 FLT017 Oil-Filter 23 7.95
  以下代码直接报错:typedef struct partRecord {     char partNum[PartNumSize + 1];     char name[MaxName + 1];     int amtInStock;     double unitPrice; } PartRecord; FILE *ftxt, *fbin; PartRecord part; if((ftxt = fopen("parts.txt", "r")) == NULL) {     printf("Cannot open parts file ");     return -1; } while(fscanf(ftxt, "%s %s %d %f", part.partNum, part.name,     &part.amtInStock, &part.unitPrice) == 4)     {         printf("%s %s %d %f ", part.partNum, part.name,part.amtInStock, part.unitPrice);                  if(fwrite(&part, sizeof(PartRecord), 1, fbin) != 1) {             printf("Error in writing file ");             return -1;         }     }
  以下代码没有正确读取:const int MAXCHAR = 128; char str[MAXCHAR]={0}; for(int i=0;i<7;i++) {     fgets(str,MAXCHAR,ftxt);     sscanf(str, "%s %s %d %f", part.partNum, part.name,&part.amtInStock, &part.unitPrice);     printf("%s %s %d %f ", part.partNum, part.name,part.amtInStock, part.unitPrice);          if(fwrite(&part, sizeof(PartRecord), 1, fbin) != 1) {         printf("Error in writing file ");         return -1;     } }
  以下代码OK:const int MAXCHAR = 128; char str[MAXCHAR]={0}; for(int i=0;i<7;i++) {     fgets(str,MAXCHAR,ftxt);     //sscanf(str, "%s %s %d %f", part.partNum, part.name,&part.amtInStock, &part.unitPrice);     strcpy(part.partNum,strtok(str," "));     strcpy(part.name,strtok(NULL," "));     part.amtInStock = atoi(strtok(NULL," "));     part.unitPrice = atof(strtok(NULL," "));     printf("%s %s %d %f ", part.partNum, part.name,part.amtInStock, part.unitPrice);          if(fwrite(&part, sizeof(PartRecord), 1, fbin) != 1) {         printf("Error in writing file ");         return -1;     } }
  3 char fgets(char s, int n, FILE* f) (stdio.h)
  Read at most n-1 characters into the s array; stops at a newline, which is included in the array. The array is automatically terminated with a .    char buf[6];     fgets(buf,6,stdin); // input:abcdef     fputs(buf,stdout);  // output:abcde
  4 char* strcpy(char* d, char* s) (string.h)
  Copy string s to string d
  strcpy并没有边界检查,d所指缓冲区所有足够空间,否则会溢出。
  5 char* strcmp(char* d, char* s) (string.h)
  Compare string d to string s; return 0 if d>s
  注意两字符串比较相等的结果是0而不是其它值。
  6 char* strlen(char* d) (string.h)
  Return the length of string d, not including the terminating NULL.
  strlen函数的实现以"‘为结束标志printf("%d ",strlen("s 16end")); // 3
  7 void* memcpy(void* d, void* s, int n) (string.h)
  Copy n characters from s to d.
  memcpy并没有检查d和s所指区域在复制时是否存在重叠情况,如果存在重叠,会出错。
  memmove()有考虑重叠的情况。
  8 void * memset(void *d, int c, size_t n); (string.h)
  Fill d with n occurrence of c.
  注意其其参数类型,以下操作通常没有问题:
  ① 以单字节数据(字符或零值)填充字符串;
  ② 以布尔值填充布尔数组;
  ③ 以零值填充数组;
  以下操作通常不是预想的结果:
  ① 以非单字节数据填充数组;
  ② 以单字节数组(非零值)填充非字节数据的数组;
  ③ 以整型数据1填充整形数组;
  原因是memset的实现是以字节为单元去填充内存空间的:/*** *char *memset(dst, val, count) - sets "count" bytes at "dst" to "val" * *Purpose: *       Sets the first "count" bytes of the memory starting *       at "dst" to the character value "val". * *Entry: *       void *dst - pointer to memory to fill with val *       int val   - value to put in dst bytes *       size_t count - number of bytes of dst to fill * *Exit: *       returns dst, with filled bytes **********************************************************************/  void * __cdecl memset (                        void *dst,                        int val,                        size_t count                        ) {     void *start = dst;     while (count--) {         *(char *)dst = (char)val;         dst = (char *)dst + 1;     }     return(start); }
  9 char * strtok(char *string, const char *control ) (string.h)
  细节:
  ① 分割字符串时,需要多次调用以依次返回被分割后的子串,子串结尾会附以"";
  ② 非第一次调用strtok()时,其首参以NULL开始,其内部实现以一个静态变量记录了下次开始分割的目标字符串的位置;/*** *strtok.c - tokenize a string with given delimiters *Purpose: *       defines strtok() - breaks string into series of token *       via repeated calls. * ****************************************************************************/  /*** *char *strtok(string, control) - tokenize string with delimiter in control * *Purpose: *       strtok considers the string to consist of a sequence of zero or more *       text tokens separated by spans of one or more control chars. the first *       call, with string specified, returns a pointer to the first char of the *       first token, and will write a null char into string immediately *       following the returned token. subsequent calls with zero for the first *       argument (string) will work thru the string until no tokens remain. the *       control string may be different from call to call. when no tokens remain *       in string a NULL pointer is returned. remember the control chars with a *       bit map, one bit per ascii char. the null char is always a control char. * *Entry: *       char *string - string to tokenize, or NULL to get next token *       char *control - string of characters to use as delimiters * *Exit: *       returns pointer to first token in string, or if string *       was NULL, to next token *       returns NULL when no more tokens remain.  *******************************************************************************/  char * strtok (         char * string,         const char * control         ) {         unsigned char *str;         const unsigned char *ctrl = control;         unsigned char map[32];         int count;          static char *nextoken;         for (count = 0; count < 32; count++)                 map[count] = 0;          /* Set bits in delimiter table */         do {                 map[*ctrl >> 3] |= (1 << (*ctrl & 7));         } while (*ctrl++);          /* Initialize str. If string is NULL, set str to the saved          * pointer (i.e., continue breaking tokens out of the string          * from the last strtok call) */         if (string)                 str = string;         else                 str = nextoken;          /* Find beginning of token (skip over leading delimiters). Note that          * there is no token iff this loop sets str to point to the terminal          * null (*str == "") */         while ( (map[*str >> 3] & (1 << (*str & 7))) && *str )                 str++;          string = str;          /* Find the end of the token. If it is not the end of the string,          * put a null there. */         for ( ; *str ; str++ )                 if ( map[*str >> 3] & (1 << (*str & 7)) ) {                         *str++ = "";                         break;                 }          /* Update nextoken (or the corresponding field in the per-thread data          * structure */         nextoken = str;          /* Determine if a token has been found. */         if ( string == str )                 return NULL;         else                 return string; }
  10 isblank() and isspace() (ctype.h)
  int isblank ( int c );
  Check if character is blank
  Checks whether  c  is a  blank character .
  A blank character is a space character used to separate words within a line of text.
  The standard "C" locale considers blank characters the tab character ("	") and the space character (" ").
  Other locales may consider blank a different selection of characters, but they must all also be  space characters  by isspace.
  int isspace ( int c );
  Check if character is a white-space.
  Checks whether  c  is a  white-space character .
  For the "C" locale, white-space characters are any of:
  " "
  (0x20)
  space (SPC)
  "	"
  (0x09)
  horizontal tab (TAB)
  " "
  (0x0a)
  newline (LF)
  "v"
  (0x0b)
  vertical tab (VT)
  "f"
  (0x0c)
  feed (FF)
  "r"
  (0x0d)
  carriage return (CR)
  Other locales may consider a different selection of characters as white-spaces, but never a character that returns true for isalnum.
  11 其它
  11.1 setbuf() 用来设置缓冲区特性,如果需要改变缓冲的特点和大小等,使用该调用。
  11.2 fflush(stdin)、 fflush(stdout) 用来强制刷新缓冲区数据。如果需要在每次i/o操作前后,不希望缓冲中存在历史数据或者不期望的数据或者为了清除缓存等的时候使用。
  11.3 setbuf(stdin,NULL);
  把输入缓冲区设置为无缓冲,直接从流读取数据。
  11.4 EOF的值是由fgetc()、fgets()动态设置,需要由此类函数调用后返回后的字符与EOF比较判断。
  -End-

怎么把电脑桌面调正?电脑屏幕位置校准的方法最近,一个朋友问如何调整计算机的桌面。其实很多朋友都不了解这个问题。有时,我们发现计算机屏幕有点歪斜并且未处于正常状态,这导致计算机屏幕变形。位移的原因可能是分辨率设置不正确,或者Flink操练(十三)之DS简介(13)读写外部系统0简介数据可以存储在不同的系统中,例如文件系统,对象存储系统(OSS),关系型数据库,KeyValue存储,搜索引擎索引,日志系统,消息队列,等等。每一种系统都是给特定的应用场景设Flink操练(十五)之DS简介(15)FlinkCEP简介(一)什么是复杂事件CEP?一个或多个由简单事件构成的事件流通过一定的规则匹配,然后输出用户想得到的数据,满足规则的复杂事件。特征目标从有序的简单事件流中发现一些高阶特征输入一个或多个由Flink操练(八)之DS简介(8)FlinkDataStreamAPI(三)1设置并行度Flink应用程序在一个像集群这样的分布式环境中并行执行。当一个数据流程序提交到作业管理器执行时,系统将会创建一个数据流图,然后准备执行需要的操作符。每一个操作符将会并Flink操练(二十九)之MapState求平均值1代码逻辑实现packageday03importorg。apache。flink。api。common。state。MapStateimportorg。apache。flink。Flink操练(二十二)之自定义Map1代码逻辑实现packageday02importorg。apache。flink。api。common。functions。FlatMapFunctionimportorg。apFlink操练(二十)之并行度使用讲解1代码实现逻辑packageoneimportorg。apache。flink。api。common。functions。FlatMapFunctionimportorg。apac家用净水器怎么选择比较好?经济越来越好,人们生活水平逐步提高,但水污染却日益加重,我们对于饮用水的安全也更加关注。越来越多家庭开始考虑家用净水设备,选择净水设备,最好在装修的时候就规划进去,能节省很多时间和2021年净水行业,热销净水器十大名牌排名转眼2021年已经过去一大半,天气逐渐炎热,净水器的销售也越来越火爆,夏季补水少不了净水器的帮助,喝水对于身体健康的重要性就不言而喻了。随着社会的发展,工业产业已遍布全国各地,在促听说脱发是因为水太硬,真的么?我们身边有很多人都试过水土不服的现象,究其原因,其实一个是食物,一个是气候的原因。而且水土不服还有一个很重要的原因,就是我们的生命之源水。最近也有消息称,因为南方北方水质不一样,因净水器什么牌子好,分享以下几个品牌净水器是水污染日益加剧背景下的产物,综合全球各国情况来看,净水器市场都处于快速发展中。俗话说民以食为天,食以水为先,水以净为本。可见水的重要性,现如今我们对饮用水的质量要求越来越高
iPhone是辨识度最高的手机,这些设计很独特,你们发现了吗?安卓手机同质化现象越来越严重,虽然系统都有自家的UI,独有的设计,可归根结底还是安卓!想要在外观上有所突破,结果现在到处都是曲面屏设计,摄像头模组也越来越像,包括手机的屁股也几乎一开学季必备,这些数码产品闭眼入!手机平板耳机统统带回家还有一周就要开学啦,新学期有什么必入的数码好物呢?今天就给大家来个数码产品全家福推荐,保准让大家买到性价比高,体验感好的双重惊喜,从手机平板再到电脑耳机统统都有,赶紧来补课吧!手机华为麒麟团队力造的Python,整整600集,建议收藏学习今天小编就给大家送上一个福利,那就是,我给大家整理了一套全套的python的学习教程,今天无偿分享给大家,这一套教程是华为的麒麟团队极力推荐的一套Python600集视频教程和学习造型科幻长安新能源C385正式发布8月24日,长安新能源旗下全新纯电动车型正式发布,目前官方暂未发布新车的正式定名,仅知道其内部代号为C385。新车或定位紧凑级纯电动轿车,基于长安最新的纯电动专用平台打造,其设计或iPhone139月正式发布,不见不散今天经过苹果直营店的时候,看到几个店员都相当悠闲,店里一个客户也没有。旁边的小米之家和华为店倒是有不少人在看手机。而今天,其实也是库克担任苹果CEO这一职位的10周年,在库克担任苹资本无序扩张的恶果菜鸟网络员工年薪百万,快递员却没有社保快递不上门快递员无社保这两个快递行业的顽疾,其实真不怪快递公司,利润大都归了菜鸟驿站,快递公司因此也是比较艰难。阿里菜鸟规划星辰大海(占有更多市场垄断),快递公司却艰难度日,又造成意外的香饽饽!六大城市抢着要,小米汽车凭什么这么牛?在智能汽车赛道上,小米已然是一颗冉冉升起的超新星。小米汽车的一举一动,外界都万分关切。然而,小米至今仍未宣布其总部与汽车工厂位于何处。在漫长的等待时间里,关于小米拿地建厂的传闻不断没有料到,6G美国仍然是陪跑,央视发声表扬北京邮电此前北京邮电在低轨道宽带当中好消息的传出,让央视也发声表扬北京邮电。在6G的发展之下,各国也开始了自己的战略布局,这对于我国接下来的发展来说也会起到重要的关键作用。此次北京邮电好消加速追赶特斯拉!奔驰将向电动汽车投资逾400亿欧元据英国路透社近日报道,奔驰汽车的制造商戴姆勒计划到2030年投资逾400亿欧元(约合人民币3046亿元本网注),准备在全电动汽车市场上与特斯拉抗衡,但也警告称技术转型将导致裁员。戴哪吒汽车加入华为朋友圈360之后的又一个好靠山?经济观察网记者王帅国8月25日,合众新能源汽车有限公司(以下简称哪吒汽车)与华为技术有限公司(以下简称华为)签署全面合作协议。根据协议内容,哪吒汽车与华为将基于物联网云计算大数据的好评如潮!荣耀平板V7Pro晨晖金二次开售移动办公生产力工具首选8月25日1008,荣耀平板V7Pro晨晖金版本二次开售。作为安卓旗舰平板的扛旗之作,荣耀平板V7Pro自发布后,就凭借强大的硬件生态及软件协同能力收获无数媒体好评,同时受到消费者