导读
在刷Oj题时,遇到包含空格的字符串输入,如何读取呢?如果使用scanf以%s格式去读取输入的字符串,遇到空格就读取结束了,显然这样是读取不了的。当然,scanf也是可以读取含空格字符串的,但操作起来相对较难,对C语言初学者并不友好。下面开始介绍两个可以对含空格字符串读取的库函数------gets和gets_s函数
gets函数
函数声明
char * gets ( char * str );
函数介绍
头文件
#include<stdio.h>
从stdin获取字符串
从标准输入(stdin)中读取字符(包括空格,Tab),并将其作为C字符串存储到str中,直到到达换行符或文件结尾。
如果找到换行符,则不会将其复制到str中。
在复制到str的字符之后,将自动追加终止的空字符。
请注意,gets与fgets完全不同:gets不仅使用stdin作为源,而且在结果字符串中不包含结尾的换行符,并且不允许指定str的最大大小(这可能导致缓冲区溢出)。
参数
str
指向内存块(字符数组)的char*型指针,其中读取的字符串作为C字符串复制。
返回值
成功时,函数返回str(返回输入字符串的起始位置)。
读取结束(读取到'\n')或读取失败时,函数返回空指针(NULL)。
以下两行了解即可
如果在尝试读取字符时遇到文件结尾,则设置EOF指示符(FEOF)。如果在读取任何字符之前发生这种情况,则返回的指针为空指针(NULL)(str的内容保持不变)。
如果发生读取错误,将设置错误指示符(ferror),并返回空指针(NULL)(但str指向的内容可能已更改)。
兼容性
C标准的最新修订版(2011年)已明确将该功能从其规范中删除。
该函数在C++中被禁止(如2011个标准,它遵循C9+TC3)。
用法实例(在DEV-C++编译器环境底下,Visual Studio 2019并不支持gets函数)
eg1:多组输入含空格字符串,输出其字符串长度和字符串
#include<stdio.h> #include<string.h> int main() { char str[100] = { 0 }; int len=0; while(gets(str) != NULL) //gets函数的多组输入写法,读取结束或失败时返回NULL,注意和scanf函数的多组输入结束或失败返回值EOF区分开 { len = strlen(str); printf("输入的字符串%s长度是%d\n", str, len); } return 0; }
eg2:使用动态内存分配函数返回的指针接收输入的含空格的字符串
#include<stdio.h> #include<string.h> #include<stdlib.h> int main() { char* str = (char*)calloc(100, sizeof(char)); //char* str = (char*)malloc(100 * sizeof(char)); int len=0; if(str != NULL) { while(gets(str) != NULL) //gets函数的多组输入写法,读取结束或失败时返回NULL,注意和scanf函数的多组输入结束或失败返回值EOF区分开 { len = strlen(str); printf("输入的字符串%s长度是%d\n", str, len); } free(str); str=NULL; } return 0; }
eg3:由于目标指针str不允许指定str的最大大小(这里指内存空间大小)(这可能导致缓冲区溢出)
#include<stdio.h> #include<string.h> #include<stdlib.h> int main() { char str[3] = { 0 };//创建可以存放三个字符的数组 int len=0; //输入字符串abcdef(超过str数组长度) 这种情况下的输出依然可以得到期望的值。 //但是,这也体现了gets函数在某些情况下可能会导致缓冲区溢出,这是一个不安全的函数 while(gets(str) != NULL) //gets函数的多组输入写法,读取结束或失败时返回NULL,注意和scanf函数的多组输入结束或失败返回值EOF区分开 { len = strlen(str); printf("输入的字符串%s长度是%d\n", str, len); } return 0; }
gets_s函数
函数声明
char * gets_s( char * buffer, size_t sizeInCharacters );
函数介绍
头文件
#include<stdio.h>
参数
buffer
输入字符串的存储位置,char*型指针。
sizeInCharacters
缓冲区的大小。返回值
如果成功,则返回
buffer
。NULL
指针指示错误或文件尾条件。 使用 ferror 或 feof 来确定发生了哪一个。注解
gets_s
函数从标准输入流stdin
中读取一个行并将该行存储在buffer
中。 该行由所有字符组成,其中包含第一个换行符 ( "\n
" ) 。gets_s
然后,在返回行之前,将换行符替换为空字符 ( "\0
" ) 。 相反,fgets_s
函数将保留换行符。如果读取的第一个字符是文件尾字符,则空字符将存储在
buffer
的开头,并返回NULL
。
_getws_s
是gets_s
的宽字符版本;其参数和返回值都是宽字符字符串。如果
buffer
为NULL
或sizeInCharacters
小于或等于零,或者如果缓冲区太小,无法包含输入行和 null 终止符(小写的null即空字符 ( "\0
" )),这些函数将调用无效参数处理程序,如buffer
中所述。 如果允许执行继续,则这些函数返回NULL
并将 errno 设置为ERANGE
。以下两行了解即可
在 C++ 中,使用这些函数由模板重载简化;重载可以自动推导出缓冲区长度 (不再需要指定大小自变量),并且它们可以自动用以更新、更安全的对应物替换旧的、不安全的函数。 有关详细信息,请参阅安全模板重载。
默认情况下,此函数的全局状态的作用域限定为应用程序。 若要更改此项,请参阅 CRT 中的全局状态。
用法实例(由于gets_s是Visual Studio 编译器提供的安全gets函数,因此仅在该编译器环境底下可以使用)
eg1:多组输入,多组输出,求含空格字符串长度,以char类型型数组存放
#include<stdio.h> #include<string.h> #define SZ 10 //根据实际输入情况定义最长字符串长度+1即可,增加1是为了给'\0'留位置,这里最长可输入9长度的字符串 int main() { int len = 0; char str[SZ] = { 0 }; while (gets_s(str, SZ) != NULL)//这里只能输入不超过SZ-1长度的字符串,否则程序崩溃,这也体现出gets_s函数的安全性极高 { len = strlen(str); printf("输入的字符串%s长度为%d", str, len); } return 0; }
eg2:多组输入,多组输出,输入处理含空格的字符串,以动态内存分配函数形式
#include<stdio.h> #include<stdlib.h> #include<string.h> #define SZ 10 //根据实际输入情况定义最长字符串长度+1即可,增加1是为了给'\0'留位置,这里最长可输入9长度的字符串 int main() { int len = 0; char* str = (char*)malloc(SZ * sizeof(char)); // char* str = (char*)calloc(SZ, sizeof(char)); while (gets_s(str, SZ) != NULL)//这里只能输入不超过SZ-1长度的字符串,否则程序崩溃,这也体现出gets_s函数的安全性极高 { len = strlen(str); printf("输入的字符串%s长度为%d", str, len); } free(str); str=NULL; return 0; }
学习小结
这两个函数给我们提供了一种新的读取字符串的方式,与scanf函数读取字符串的区别就在于它们可以读取含空格,Tab的字符串。解决关于字符串OJ问题的关键一步,读取输入的字符串就得到有效的解决了。
在DEV-C++编译器环境底下,直接调用gets函数即可;在Visual Studio 2019等VS编译器底下,gets函数被gets_s函数取代,调用gets_s函数即可。
这两个函数,注意传递的参数,在提交到OJ系统上时,应该使用gets函数,因为OJ系统上的编译环境其实是DEV。
给大家西大OJ上的一道处理含空格字符串的题目,OJ练习:OnlineJudge
西大OJ时常会出现崩溃情况,我还是把题目放底下给大家吧。
题外话
今天是2021年12月18日,是的,今天是英语四六级考试。我已经寄了,只能明年继续冲了,在这里记录一下今天,这是一个悲伤的故事。
上午11:20考完试,我就回宿舍做上面那道OJ题。17日的晚上,我做到这道题目时,挨卡了,以前处理字符串的题目是不包含空格的,因此我也是查了很多的资料,但是发现,CSDN上关于处理含字符串函数的介绍并不理想,因此,在我AC这个题目后,我进行了这次学习总结。
查了很多种处理含空格字符串处理方法,最终我选择介绍gets和gets_s函数,这对于C语言初学者来说,是比较好理解和操作的,上面的介绍中也对函数的使用给了具体的例子。
这篇博客,干货多多,建议一键三连,同时希望它可以帮助到C语言初学者。