c语言中输入包含空格的字符串:scanf(“%[^\n]“,str) vs gets(str)

本文详细讲解了在C语言中如何读取包含空格的字符串,对比了使用gets()和scanf()的不同方法,特别是在多组数据输入时的注意事项和解决策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • 背景:想要在c语言中输入包含空格的一行字符串。很明显scanf("%s",str)无法实现,因为这个输入方式,遇到空格或者回车符就会停止输入。(备注:全文中出现的str都表示一个字符串数组,或者char *

一. 输入单组数据

  • 方法一:使用gets(str)来实现
#include<stdio.h>

int main(){
	
	char str[20];
	gets(str);
	printf("----分界线----\n");
	printf("%s\n",str);
	return 0;
}

运行结果如下:
在这里插入图片描述

注意: 虽然gets()函数可以实现如上功能,但是该函数被称作一个危险的函数,因为该函数不会判断输入数据的长度是否会超过数组的长度,所以可能会造成数组越界、栈溢出等问题,所以使用的时候必须格外小心。

  • 方法二:使用scanf("%[^\n]",str)来实现
    这里稍作解释一下:%[]可以用来限制输入的内容,比如%[0-9]就表示只读入‘0’-‘9’之间的数字,%[a-z]表示只读入‘a’到‘z’之间的字母。我们这里的%[^\n]中的^就表示“非”的意思,\n就是我们平时所说的回车符,所以%[^\n]这个符号就是表示只读取 不是\n的字符
#include<stdio.h>

int main(){
	
	char str[20];
	scanf("%[^\n]",str);
	printf("----分界线----\n");
	printf("%s\n",str);
	return 0;
}

在这里插入图片描述

到这里,你以为就结束了?不是不是,还要讲讲这两种输入方式的区别,还有有多组输入数据时的坑。
-----------------------------------------------分界线1-------------------------------------------

二. 输入多组数据时

  • 方式一:
    	#include<stdio.h>
    
    	int main(){
    		
    		char str[20];
    		while(gets(str)!=NULL){
    			printf("----分界线----\n");
    			printf("%s\n",str);
    		}
    		return 0;
    	}
    
    测试结果如下:ok没问题
    在这里插入图片描述
  • 方式二:
    #include<stdio.h>
    
    int main(){
    
    char str[20];
    while(~scanf("%[^\n]",str)){
    	printf("----分界线----\n");
    	printf("%s\n",str);
    }
    return 0;
    }
    
    测试结果如下,居然是死循环了。。。。。
    在这里插入图片描述
    为什么呢? 两种方式几乎是做相同的修改,但是运行的结果却是截然不同!
    为什么第二种会出现死循环,原因在于%[^\n]这个符号就是表示只读取 不是\n的字符,一遇到\n就停止了。并未对\n做任何处理,所以当第一次循环完成后,要进行第二次输入时,从缓冲区读取到的第一个字符是上一次遗留下来的\nscanf(%[^\n],str)一遇到\n又马上停止了,什么都没读入。所以str数组中的内容没有被更新,依旧是上一次读取是留下的内容。那该如何解决呢?
    • 方法:使用getchar()去掉多余的回车符
      getchar()方法的作用就是读取任何一个字符,包括\n,然后返回。如果没有变量来接收这个返回值,那相当于把读取的这个字符丢弃了。
    #include<stdio.h>
    
    int main(){
    	
    	char str[20];
    	while(~scanf("%[^\n]",str)){
    		getchar();   //使用getchar()去掉多余的回车符
    		printf("----分界线----\n");
    		printf("%s\n",str);
    	}
    	return 0;
    }
    
    测试结果如下:
    在这里插入图片描述

三. 输入多组数据中的坑

输入多组数据时,在非首次输入时,直接按下回车会出现什么情况?

  • 方式一:gets(str)这个方式
    在这里插入图片描述
  • 方式二:scanf("%[^\n]",str)配合getchar()这种方式
    在这里插入图片描述
  • 结果对比分析:
    方式一的结果正常,如果直接输入一个回车,那也就输入一个回车,体现出来的就是一行空行。而方式二中,如果直接输入一个回车,输出的内容居然是上一次输入(非回车)的内容。为什么会这样子呢?我们猜测,gets(str)的方式,如果读入的是一行输入中只有一个回车符,那么它会在str的第一个位置中放入一个\0,所以输出的时候就啥都没有了;而scanf("%[^\n]",str)这个方式,如果读入的是一行输入中只有一个回车符,并不会对str做任何的改动。
  • 想法验证:
    • 关于gets(str)
#include<stdio.h>
#include<string.h>

int main(){
	
	char str[20];
	int preLen=0,curLen=0,i;
	while(gets(str)!=NULL){
		preLen=curLen;
		curLen=strlen(str);
		printf("preLen=%d\n",preLen);
		printf("curLen=%d\n",curLen);
		for(i=0;i<preLen;i++){
			printf("str[%d]=%c\n",i,str[i]);
		}
		printf("curStr=%s\n",str);
		printf("---------------------------\n");
	}
	return 0;
}

结果如下:
在这里插入图片描述
从以上结果可以看出,当第二次输入仅为一个回车符时,gets(str)会把str的第一位字符设置为\0

  • 关于scanf("%[^\n]",str)
#include<stdio.h>
#include<string.h>

int main(){
	
	char str[20];
	int preLen=0,curLen=0,i;
	while(~scanf("%[^\n]",str)){
		getchar();   //使用getchar()去掉多余的回车符
		preLen=curLen;
		curLen=strlen(str);
		printf("preLen=%d\n",preLen);
		printf("curLen=%d\n",curLen);
		for(i=0;i<preLen;i++){
			printf("str[%d]=%c\n",i,str[i]);
		}
		printf("curStr=%s\n",str);
		printf("---------------------------\n");
	}
	return 0;
}

结果如下:
在这里插入图片描述
从以上结果可以看出,当第二次输入仅为一个回车符时,curLen依旧为6,str依旧保留着上一次输入的内容且未做任何改变。

  • 填坑
    所以严格一些来说,使用scanf("%[^\n]",str)配合getchar()这种方式进行多组输入时,必需确保在每一次输入前,字符串数组已被重新初始化。
    所以使用scanf("%[^\n]",str)配合getchar()这种方式进行多组输入时的改进版本如下:
#include<stdio.h>
#include<string.h>

int main(){
	
	char str[20];
	while(~scanf("%[^\n]",str)){
		getchar();   
		printf("----分界线----\n");
		printf("%s\n",str);
		memset(str,0,sizeof(str));  //在每一组数据的最后,把数组重新初始化 !!!!
	}
	return 0;
}
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值