字符串输入输出函数
Posted jeffrey-yang
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了字符串输入输出函数相关的知识,希望对你有一定的参考价值。
字符串输入
字符串输入首先要考虑的是存储位置和存储空间大小。
例子:char *name; scanf("%s", name); 指针未初始化,可能指向内存中的任意地方,字符串读入的时候有可能覆盖内存中的关键数据,造成程序或机器崩溃。
char name[81]; 这种方式显式声明空间并进行初始化。
gets()函数
scanf("%s", str)函数读入单个word。而gets()可以读取一整行的字符串。它通过换行符读取整行,丢弃换行符,存储剩余的字符,添加空字符(‘ ‘)以创建C字符串。一般和puts()搭配使用。
示例:
#include<stdio.h>
#define STLEM 81
int main(void)
{
char words[STLEM];
puts("Enter a string, please.");
gets(words);
printf("Your string twice:
");
printf("%s
", words);
puts(words);
puts("Done.");
return 0;
}
??:gets函数的问题(int puts(const char *);):虽然在定义字符串的时候声明了大小为81,但gets函数无法阻止输入超过大小的字符串长度,编译运行时将报错"warning: this program uses gets(), which is unsafe."
gets函数只接收一个参数,char类型的指针。没有其他参数限定用户输入的字符串长度。gets()只知道数组的开始位置,却不知道数组的长度。
如果输入字符串太长,则会出现缓冲区溢出,这意味着多余的字符溢出了指定的目标。 额外的字符可能只是进入未使用的内存并且没有立即出现问题,或者它们可能会覆盖程序中的其他数据,但这些肯定不是唯一的可能性。
C99已经不建议使用该函数,并建议将gets()从标准库中移除,C11已经将gets()从标准中移除。但C的标准只是要求编译器厂商必须符合所要求的标准,而不是限制编译器厂商不能做什么。所以,主流的编译器依然支持gets()函数已确保向后兼容。
gets()的替代品fgets()
为了解决gets()函数容易引起的缓冲区溢出问题,出现了fgets()函数。char fgets(char __restrict, int, FILE *);
fgets()与gets的主要不同点为:
- fgets()有第二个参数,是一个int类型,限定输入的字符串最大长度。
- fgets()读取换行符(‘ ‘),并保存在字符串中,而不是像gets(),丢弃换行符。
- fgets()有第三个参数,默认为文件输入。也可以读取键盘输入,参数为stdin。
示例:
#include<stdio.h>
#define STLEN 14
int main(void)
{
char words[STLEN];
puts("Enter a string, please.");
fgets(words, STLEN, stdin);
printf("Your string twice (puts(), then fputs()):
");
puts(words);
fputs(words, stdout);
puts("Enter another string, please.");
fgets(words, STLEN, stdin);
printf("Your string twice (puts(), then fputs()):
");
puts(words);
fputs(words, stdout);
puts("Done.");
return 0;
}
输出:
Enter a string, please.
apple pie
Your string twice (puts(), then fputs()):
apple pie
apple pie
Enter another string, please.
strawberry shortcake
Your string twice (puts(), then fputs()):
strawberry sh
strawberry shDone.
解读:
- 首先输入"apple pie",字符串长度小于14,使用fgets()时会保留换行符。使用puts()输出时,会额外添加一个换行符(因为gets()丢弃了换行符),则puts()会输入" "。fputs()会按words实际保存的进行输出。因此,两个"apple pie"之间的空行就是puts()函数额外添加的。
- 其次输入"strawberry shortcake",字符串长度超过14,则仅保留13个有效当前输入(额外一个留给‘ ‘)。故使用puts()时输出"strawberry sh "(‘ ‘为额外添加)。而使用fputs()输出时,不会添加‘ ‘,故直接输出"strawberry sh",紧接着是"Done."。
fgets()函数的返回值为指向char类型的指针。指针指向输入的字符串地址。但是,如果函数遇到文件结尾,则返回一个称为空指针的特殊指针。这是一个确保不指向有效数据的指针,因此它可用于指示特殊情况。在代码中,该指针可以表示为数字0,或者在C中更通常的表示方法为宏NULL。
fgets()的输入问题
由于fgets()会保存换行符,这就带来了一些问题。有时,你不想保存该换行符,而仅仅将用户输入的换行符作为buffered I/O的一个指令,通知临时存储区的数据可以被fgets()函数使用。
如何丢弃换行符?
while (words[i] != ‘
‘)
i++;
words[i] = ‘ ‘;
words为通过fgets()得到的输入字符串,将换行符替换为‘ ‘。
如果想将超过数组定义大小的剩余字符串也丢弃掉,以免作为下次的输入,如何做到呢?
while (getchar() != ‘
‘)
continue;
Null字符和NULL指针
NULL字符或‘ ‘,用来标记字符串的结束。代码为0的字符,ASCII 为0的字符。
空指针或NULL具有与有效数据地址不对应的值。 它通常由函数使用,否则返回有效地址以指示某些特殊情况,例如遇到文件结束或未能按预期执行。
另外,空字符是int类型,而NULL指针是指针类型。
gets_s()函数
C11引入了一个新函数gets_s(),类似fgets(),但和fgets也有不同之处。
- gets_s()只读取标准输入,因此不需要第三个参数如stdin。
- 如果get_s()读取到换行符,则丢弃换行符,而不是和fgets()一样,保留它。
- 如果gets_s()读取最大字符数并且无法读取换行符,则需要几个步骤。 它将目标数组的第一个字符设置为空字符。 它会读取并丢弃后续输入,直到遇到换行符或文件结尾。 它返回空指针。 它调用依赖于实现的“处理程序”函数(或者选择的函数),这可能导致程序退出或中止。
轮子
char * s_gets(char *st, int n)
{
char *ret_val;
int i = 0;
ret_val = fgets(st, n, stdin);
if (ret_val)
{
while (st[i] != ‘
‘ && st[i] != ‘ ‘)
i++;
if (st[i] == ‘
‘)
st[i] = ‘ ‘;
else
{
while (getchar() != ‘
‘)
continue;
}
}
return ret_val;
}
s_gets()函数为自定义函数,可以丢弃fgets()函数保留的换行符,同时丢弃超过最大字符数的剩余输入。
scanf()函数
一般我们使用scanf()函数和%s格式读取字符串。scanf()更像是读取一个单词,而不是一个字符串。
示例:
Input Statement | Original Input Queue* | Name Contents | Remaining Quenue |
---|---|---|---|
scanf("%s‘, name); | Fleebert#Hup | Fleebert | #Hup |
scanf("%5s", name); | Fleebert#Hup | Fleeb | ert#Hup |
scanf("%5s", name); | Ann#Ular | Ann | #Ular |
‘#’代表space character(/t, /b等)。
可以到,scanf会在遇到空白字符或最大字符时读取结束,其他字符将再下次输入时读取。scanf的返回值为成功读取到的字符串个数。
字符串输出
以上是关于字符串输入输出函数的主要内容,如果未能解决你的问题,请参考以下文章