【C语言】字符串和字符串数组的输入和陷阱

浅谈:C语言写程序时,因为没有字符串数据类型,所以字符串和字符串数组的输入也是一个难题和陷阱,这里讨论一下几种字符串输入情况。


字符串输入函数:
1.格式输入函数:int scanf("%s",字符数组名或指针);
2.字符串输入函数:char* gets(字符数组名或指针);
(1)相同点:字符串接受结束后自动加’\0’。
(2)不同点(容易出错):
①scanf :当遇到回车,空格和tab键就认为输入结束,会自动在字符串后面添加’\0’;但是回车、空格和tab键仍会留在输入的缓冲区中(如果连续多次scanf输入的话要注意考虑上一次scanf后的缓冲区有无”垃圾“),只至遇到回车就停止输入。(适用于输入没有空格、tab的字符串)

char s[20],str[20];
scanf("%s",s);          //若输入“Hel lo,World!”    空格认为第一个scanf输入结束,后面输入的字符留在缓冲区送给下一次scanf
scanf("%s",str);        
printf("s=%s str=%s",s,str);    //输出s=Hel str=lo,World!

若想去掉上一次scanf后缓冲区留下的“垃圾”,可以使用gets()

char s[20],str[20],temp[20];
scanf("%s",s);          //输入“Hel lo,World!”  
gets(temp);             //temp= lo,World!
scanf("%s",str);        //输入“Hel lo,World!”  
printf("s=%s str=%s",s,str);    //输出s=Hel str=Hel

②gets:可接受回车键之前输入的所有字符。(适用于输入任何字符串)

char s[20],str[20]; 
gets(s);             //Hello World!
gets(str);             //Hello World!
printf("s=%s str=%s",s,str);    //输出s=Hello World!str=Hello World!

易错点:

char s[20],str[20]; 
scanf("%s",s);            //Hello World!
gets(str);             //此时str得到的是scanf输入后留在缓冲区的回车,即马上结束输入,str="\0"
printf("s=%s str=%s",s,str);    //输出s=Hello World!str=

纠错方法:可以用getchar、gets等函数去除缓冲区的“垃圾”

char s[20],str[20]; 
scanf("%s",s);            //Hello World!
getchar();             //去掉缓冲区回车符
gets(str);             //abc
printf("s=%s str=%s",s,str);    //输出s=Hello World!str=abc

一、输入字符串
用scanf时注意陷阱
1.字符数组存储字符串

char s[10]={
    
    0};     //在栈区分配10个char大小的内存
scanf("%s",s);	//gets(s)
static char s[10]={
    
    0};     //在静态区分配10个char大小的内存
scanf("%s",s);	//gets(s)

2.字符指针表示字符串;一定要为指针分配空间和地址或者让指针指向某个地址才能操作

 char s[10]={
    
    0};     //在栈区分配10个char大小的内存
 char*p=s;
scanf("%s",p);	//gets(p)  实际操作的数组s的内存
char*s=(char*)malloc(sizeof(char)*10); //在堆区动态分配10个char大小的内存,并把地址赋给指针s。(动态分配在前面的文章有讲噢)
scanf("%s",s);	//gets(s)  操作的指针s指向的堆空间

二、输入字符串数组(多次输入字符串)
用scanf时注意陷阱
1.二维数组表示字符串数组

char s[5][10]={
    
    0};      //定义5个字符串,每个字符串占10个字节
for(int i=0;i<5;i++)
{
    
    
	scanf("%s",s[i]);  //gets(s[i])或者scanf("%s",*(s+i))、gets(*(s+i))
}

2.字符指针数组表示字符串数组

char *s[5]={
    
    0};      //定义5个字符指针,表示5个字符串,但是5个字符指针都为0,还没有指向具体的地址
for(int i=0;i<5;i++)
{
    
    
	//scanf("%s",s[i]);   //直接输入会出错,此时不知道指针指向的具体内存地址和内存大小
	s[i]=(char*)malloc(sizeof(char)*10);   //在堆区动态分配10个char大小(每个字符串的大小)的内存,并把地址赋给指针s[i]
	scanf("%s",s[i]);  //gets(s[i])或者scanf("%s",*(s+i))、gets(*(s+i))
}

3.二维字符指针表示字符串数组

char **s=NULL;      //定义二维字符指针,但是不知道字符串的数目和每个字符串的大小
s=(char **)malloc(sizeof(char*)*5);  //为s分配5个char*大小的堆内存表示5个字符串
for(int i=0;i<5;i++)
{
    
    
	s[i]=(char*)malloc(sizeof(char)*10);   //在堆区动态分配10个char大小的内存,并把地址赋给指针s[i]
	//或者     *(s+i)=(char*)malloc(sizeof(char)*10);
	scanf("%s",s[i]);  //gets(s[i])或者scanf("%s",*(s+i))、gets(*(s+i))
}

注意点:
1.定义二维数组时可以不声明行数,但是要声明列数,另外数组一定要初始化,不然编译器分辨不出数组所占的空间而报错;声明了行数和列数可以不初始化先;
2.操作数组注意下标只能是整型常量或者整形表达式,且下标从0开始,注意数组溢出(编译不会报错,结果可能出错)
3.操作指针一定要先初始化地址空间才能操作,虽然编译不报错,但是程序会崩掉

猜你喜欢

转载自blog.csdn.net/yechongbinbin/article/details/114632343