c语言构建输出函数,C语言细节 - 输入输出库函数 -待完成

文章目录

1 `int getc (FILE* __F) && int getchar (void)`

标准库中的函数实现

功能

输入结束标志

返回值

2 `char *gets(char *str) `

功能

输入结束标志

返回值

说明

缺陷

3 `char *fgets(char *str, int n, FILE *stream) `

功能

输入结束标志

返回值

参数 int n

参数 char *str

参数 FILE *stream

4 `int scanf(const char *format, ...)`

函数实现

功能

可变参数列表

返回值

刨析 vsscanf(g_pcInBuf,fmt,args)

总结

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个文件)

#defineINBUFSIZE 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"

匹配/过滤特定字符

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值