c语言笔记 - 标准库函数 - 持续更新
文章目录
1 int getc (FILE* __F) && int getchar (void)
标准库中的函数实现
可以看见 getc 与 getchar 的唯一区别就是 getchar 默认 __F 参数为 stdin
int getc (FILE* __F) { return (--__F->_cnt >= 0) ? (int) (unsigned char) *__F->_ptr++ : _filbuf (__F); } int getchar (void) { return (--stdin->_cnt >= 0) ? (int) (unsigned char) *stdin->_ptr++ : _filbuf (stdin); }
功能
从标准输入流(getc还包括从指定文件)中读取一个字符
输入结束标志
换行即结束
返回值
- 若输入成功:返回用户输入的第一个字符的ASCII码;
例如:什么都不输入直接按 “Enter” 键,因 “Enter” 键包含 ‘\r’ 和 ‘\n’ 两个字符,又遇到 ‘\n’ 结束,故返回 ‘\r’ 即 10 - 其他:则返回EOF;例如输入组合按键 ctrl+z
2 char *gets(char *str)
功能
从标准输入流中读取一串字符,并把它存储在str所指向的字符串中
输入结束标志
换行即结束
返回值
若输入成功,则返回str;其他情况,返回NULL
说明
遇换行符结束后,最终输入的值是:在输入有效字符的基础上丢弃换行符,末尾添加 nul (’\0’字符)
缺陷
gets可以从标准输入无限读取,不会判断上限,以回车结束读取,而gets()函数只知道buffer的首地址,并不知道有多少个元素。若输入字符串过长,则会导致溢出,访问其他地址空间,若这些空间未被使用,则暂时不会出现问题,若这些空间已被使用,则会覆盖原有内容,导致不可估量的后果。因此,不建议使用此函数,为了避免上述缺陷,建议使用 fgets() 代替 gets()
3 char *fgets(char *str, int n, FILE *stream)
char *fgets( char *str, int n, FILE *stream ) { register int c; register char *cs; cs = str; while( --n>0 && (c = getc(stream))!= EOF ) { if( (*cs++ = c) =='\n' ) break; } *cs ='\0'; return (c == EOF && cs == str) ? NULL : str; }
功能
获取一行长度为 n 的字符串(包含 ‘0’ 符)
输入结束标志
换行即结束
返回值
若输入成功,则返回str;其他情况,返回NULL
参数 int n
1.输入字符串的长度 < n-1 :保留换行符,在最后添加 ‘0’
例:fgets(str,4,stdin); 输入:12 则实际为:12\n + ‘0’
这种情况下得到的字符串中包含了换行符 ‘\n’,故在输出时会进行自动换行
2.输入字符串的长度 >= n-1:保留 n-1 个字符,在最后添加 ‘0’;下一次调用会继续读该行的剩余部分
例:fgets(str,4,stdin); 输入:123 则实际为:123 + ‘0’
参数 char *str
参数 str 可以是一个字符数组或字符指针,若是字符指针,一定要进行初始化,分配内存空间
char str1[100];可以进行传递
char *str2;不能进行传递,并没有为它分配内存空间
char *str3 = (char*)malloc(100*sizeof(char));可以进行传递,已分配动态内存空间
参数 FILE *stream
1.从标准设备读数据:该参数为 stdin
2.从文件流读取数据:fopen()、fwrite()、fread()函数使用说明与示例
4 int scanf(const char *format, ...)
函数实现
(想了解具体文件请访问:关于输入输出的3个文件)
#define INBUFSIZE 1024 static char g_pcInBuf[INBUFSIZE]; int scanf(const char * fmt, ...) { int i = 0; unsigned char c; va_list args; //获取输入的内容 while(1) { c = getc(stdin); //此处可以看到输入流中遇见 '\r', '\n' 即结束 if((c == 0x0d) || (c == 0x0a)) { g_pcInBuf[i] = '\0'; break; } else { g_pcInBuf[i++] = c; } } va_start(args,fmt); i = vsscanf(g_pcInBuf,fmt,args); //将g_pcInBuf缓冲区反格式化为参数列表 va_end(args); return i; }
功能
格式输入函数,从标准输入 stdin 读取指定格式化输入;
可变参数列表
请看:可变参数列表
返回值
成功:成功匹配和赋值的个数;其他:EOF
刨析 vsscanf(g_pcInBuf,fmt,args)
scanf格式字符串中的统一格式 :%[*][width][qualifier]type],如%3d,包含对width, type的格式说明
下面函数省略 * 和 qualifier,以及对具体匹配部分的具体转换,函数实现如下:(包含解析)
// buf:输入缓冲 // fmt:缓冲区格式 // args:可变参数列表首地址 int vsscanf(const char * buf, const char * fmt, va_list args) { /*...*/ //!nul while (*fmt && *str) { //跳过格式中的任何空白,格式中的空白匹配输入中任何数量的空白(即空格,回车...) if (isspace(*fmt)) { while (isspace(*fmt)) //检测空白字符 ++fmt; while (isspace(*str)) ++str; } //任何非转换的内容都必须完全匹配 if (*fmt != '%' && *fmt) { if (*fmt++ != *str++) break; continue; } //到达转换符%位置 if (!*fmt) break; ++fmt; /*...*/ //获取字段宽度 field_width = -1; if (isdigit(*fmt)) //检查字符是一个十进制数字字符(0-9) field_width = skip_atoi(&fmt); //将数字字符转换为相应数字,如将'1'->1 /*...*/ switch(*fmt++) { //%nc case 'c': { char *s = (char *) va_arg(args,char*); //n:1 :输入一个字符 if (field_width == -1) field_width = 1; //n:2-9 :输入多个字符,组成固定长度字符串(包含空格) do { *s++ = *str++; } while (--field_width > 0 && *str); num++; } continue; //%s case 's': { char *s = (char *) va_arg(args, char *); if(field_width == -1) field_width = INT_MAX; //字符串长度为最大值,否则按限定长度读取 //忽略字符串前的所有白字符 while (isspace(*str)) str++; //存储知道下一个空白符之前 while (*str && !isspace(*str) && field_width--) { *s++ = *str++; } //加入nul *s = '\0'; num++; } continue; //%n 返回到目前为止读取的字符数(长度按字节算) case 'n': { int *i = (int *)va_arg(args,int*); *i = str - buf; } continue; //%o case 'o': base = 8; break; //%x case 'x': case 'X': base = 16; break; //%d case 'i': //old base = 0; case 'd': //new is_sign = 1; case 'u': //%u break; //%% case '%': /* looking for '%' in str */ if (*str++ != '%') return num; continue; default: return num; } //跳过缓冲区中的空白符 while (isspace(*str)) str++; /*...*/ } return num; }
总结
-
格式字符串中的所有空白均无效
-
任何非转换的内容都必须完全匹配,格式中的空白匹配输入中任何数量的空白
-
对于width的举例
scanf("%4d", &a); printf("%d", a);
将输入得到一串0-9的字符直接合并转换为数字输入为"12345" / 输出为1234
scanf("%4c", str); printf("%s", str);
%nc可进行带空白符的固定长度的字符串输出str必须为一段已开拓的空间的首地址:数组/分配的动态内存的首地址
输入为"12 345" / 输出为"12 3"scanf("%4s", str); printf("%s", str);
%ns与%nc类似,但遇到空白符即终止输入为"12 345" / 输出为"12"
5 void qsort (void * base, size_t num, size_t size, int ( * comparator ) ( const void *, const void * ) )
功能
对数组元素进行排序
参数 void * base
数组的首地址
参数 size_t num
数组的元素个数
参数 size_t size
元素的字节大小
参数 int ( *comparator ) ( const void *, const void * )
指向比较函数的函数指针,决定了排序的顺序;示例如下:dir决定排序方式
#define dir -1 //method1 int comparator (void const *a, void const *b) { int *pa = (int *)a; int *pb = (int *)b; return (*pa > *pb) ? dir : ((*pa < *pb) ? -dir : 0); } //method2 int compare (const void * a, const void * b) { return ( *(int*)a - *(int*)b ) * dir; }
- 点赞
- 收藏
- 分享
- 文章举报
- C语言笔记系列文章 索引目录表(持续更新中......)
- #新手入门C语言笔记#更具慕课网课程《C语言入门》整理,持续更新中..
- C语言学习笔记(持续更新)
- 【笔记】数据挖掘导论(持续更新)
- TensorFlow入门及实战笔记——tips(持续更新)
- 重拾CCNA,学习笔记持续更新ing......(5)
- 学习笔记:大话设计模式之简单工厂模式---持续更新
- css 部分常见问题的部分解决方法(笔记)(持续更新)
- Sybase数据库学习笔记【持续更新中】
- 《c++标准库》 第2版 学习笔记 准备知识 持续更新中
- ACE学习笔记--持续更新中
- U-Boot-2009-03移植笔记(目录:持续更新)
- javascript学习笔记---注意知识点(持续更新)
- Java语言程序设计(基础篇)- 笔记(持续更新中)
- 从交换a,b的值开始--巧妙的C语言问题(持续更新)
- (转载)cocos2d-x学习笔记(持续更新)
- spring学习笔记(持续更新)
- JQuery应用笔记【持续更新】
- 我的JAVA学习笔记(记下一些容易忘记的知识点)持续更新
- Gradle使用笔记(持续更新)