浅谈: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.操作指针一定要先初始化地址空间才能操作,虽然编译不报错,但是程序会崩掉