今天遇到一个有趣的问题,关于scanf("%s,%s,%d,%d",a,b,&c,&d); 给字符数组赋值的问题。

#include<stdio.h>
int main()
{
char a[1]={0};
char b[1]={0};
int c=0;
int d=0;
scanf("%s,%s,%d,%d",a,b,&c,&d);
printf("%s\n",a);
return 0;
}
首先我a定义为长度为1的字符数组,是这个数组的指针无疑,
如果用1s%,无任何问题,这个没有异议。
但是我输入3,4,5,6
输出也是3,4,5,6
也就是说a被赋值为3,4,5,6了。
问题:我已经定义了数组的长度为1,a是数组的首地址,那么char*1应该是数组在内存中的大小。给a赋值3,4,5,6在我的感觉下应该是只获取第一位即3给数组赋值才对吧?
还是说指针会动态分配?貌似只有smart 指针才会动态分配吧?
而且我debug的时候显示a确实只有一个元素,也就是第一个元素3
还有,你说错了一点不是scanf不接受空格,scanf("%c%c%c",&a,&b,&c); 当你使用%c的时候是可以读取到空格的,scanf会把任何输入都接收。scanf("%c %c %c",&a,&b,&c); 这样儿才不会识别空格。所以不是scanf不接受空格,而是看输入的类型。不过你说的错误返回的问题是对的。scanf("%s,%s,%d,%d",a,b,&c,&d); scanf是根据输入约定来分析输入的"%s,%s,%d,%d"表示用逗号分开scanf("%s空格%s空格%d空格%d",a,b,&c,&d); 表示用空格分开,下面这句是可以正确分析的,但是上面的用逗号却不行。

为什么是3,4,5,6
这个问题,应该归结于字符串的输出问题

为什么你的这种极其不严格的输入输出代码,没有报错,我并不清楚。建议不要这么用,我给你先解释一下

根据你的想法,你要接收字符串,你确实将3,4,5,6存入了以a地址开头的数组中,但是a仅有一个空间,但并不影响数据的存入,因为字符串存了就是存了,但但输出却不是找到数组的结尾就结束输出,而是找到一个'\0'字符,就是空字符。
那么很显然声明一个长度为1的字符数组,但保存时你并没有给定字符串的结束。追问

首先这并不是我写的代码,因为今天在回答问题的时候发现的直接复制过来的。
我想探讨的是这个问题的实质,而不是代码规范性的问题。
什么叫“字符串存了就是存了”?

追答

你接收的是%s,明显是接收一个字符串,而不是一个字符,不管你的字符数组多长,计算机会把按回车以前的字符串存入a地址开头的一段内存空间。数组与指针在C语言里面是通用的,对数组的操作实际是按指针的方式。字符串的结束符是'\0',而并不是通过数组声明了多少空间。

另外scanf是不接受空白符的,包括空格和回车

追问

看我问题补充。

追答

个人认为是这样的,在C++里面有这样的规定
当接收一段字符串时,假如遇到了空百符,那么scanf就会得到一个错误的返回值表示不能接收了。这个返回值一直存在,除非清除掉。即是后面再写更多的scanf,也不会执行了。
照目前来看,C语言也是如此,机制是一样的
但这样额规定有的方法是不会有的,比如gets(),允许接收空白符

追问

还有,你说错了一点不是scanf不接受空格
scanf("%c%c%c",&a,&b,&c); 当你使用%c的时候是可以读取到空格的,scanf会把任何输入都接收。
scanf("%c %c %c",&a,&b,&c); 这样儿才不会识别空格。
所以不是scanf不接受空格,而是看输入的类型。
问题我已经搞清楚了,虽然没有给出明确的结论,但是还是很感谢。

追答

如果我说空格有两种作用,一种是输入格式符,一种是结束符呢
或者空格是字符没错,但在字符串的输入中是不接受空格的

你尽可以用空格作为格式符,但却不能用来做字符串的格式符。空格可以作为数字,字符的格式符输入,是可以的,但在字符串的输入上,却是以空格来作为结束符的,会返回一个错误值。你尽可以试试在之前的基础上多加几个scanf,它是不会被执行的。

我只希望你能正确理解一些东西,而不是按照自己的错误理解。另外,因为这样,scanf在接收字符串上,很多人都不愿意用。以后你会碰到这样的问题的

温馨提示:答案为网友推荐,仅供参考
第1个回答  2013-04-24
我认为是这样的,
a占用的空间首先肯定是固定的
读入3,4,5,6,可能会被当作一个整字符串读入给a,由于其长度超过了a的长度,所以它把a指向地址的后面那一段不属于a的内存空间也占用了。
输出的时候直到输出‘\0’才会终结,也就是说输出了后面那一段不属于它内存空间里的内容了
以上是我的见解,不妨再看看他人的理解追问

我的理解是这样儿的,
你看是不是这样儿呢
1.scanf这个方法要求传入的参数是地址,那么假如使用s%而不是1s%或ns%,他就会以传入的地址来存放这个接收到的数据,而不管他是多大的长度?
2.scanf("%s,%s,%d,%d",a,b,&c,&d); 每个%s之间都有逗号分隔,也就是说输入的时候用逗号分隔每个元素
那么我使用s%输入3,4,5,6的时候scan不会解析“,”了?而是完全按照ns%前面的n这个系数来决定的?

追答

抱歉,在工作很忙,一会儿还要加班,没有及时回复,不好意思。
我作出了如下改动进行尝试
printf("%s\n",a);
printf("%s\n",b);
printf("%d\n",c);
printf("%d\n",d);
strcpy(a,"xxxxx");
printf("%s\n",a);
printf("%s\n",b);

输入a,b,c,d
输出如下
a,b,c,d
a,b,c,d
,b,c,d
0
0
xxxxx
xxxx
可见:
1.a,b申请的内存空间是连续的。因而a的改动会影响到b
2.读入时b,c,d并没有接受到值。
关于追问

1.scanf这个方法要求传入的参数是地址,那么假如使用s%而不是1s%或ns%,他就会以传入的地址来存放这个接收到的数据,而不管他是多大的长度?
我认为它对字符串的识别很是不怎么样,只会以回车或者换行符进行识别。只要char指针的地址不为空,就会不管后面的直接写如该指针后面的那段内存中(所以c语言不安全)

2.scanf("%s,%s,%d,%d",a,b,&c,&d); 每个%s之间都有逗号分隔,也就是说输入的时候用逗号分隔每个元素
那么我使用s%输入3,4,5,6的时候scan不会解析“,”了?而是完全按照ns%前面的n这个系数来决定的?
对于‘,’解析也是,如果都是数字的话应该是没问题的,但是对于字符串而言,这个好像很难做出来。原因还是对于字符串的识别是以回车或者换行符结束
感觉也可能读入后出现了什么错误,不是很了解细节

int a=0;
int b=0;
int c=0;
int d=0;
scanf("%d,%d,%d,%d",&a,&sb,&c,&d);

printf("%d\n",a);
printf("%d\n",b);
printf("%d\n",c);
printf("%d\n",d);
这样结果是正确的,所以不是‘,’问题,我感觉还是字符串方面处理的问题,等我再试试
新尝试:
char a[1]={0};

char b[1]={0};

int c=0;

int d=0;

scanf("%s ,%s ,%d ,%d",a,b,&c,&d);

printf("%s\n",a);
printf("%s\n",b);
printf("%d\n",c);
printf("%d\n",d);
输入:
a ,b ,1 ,2
输出:
ab
b
1
2
终于正常输出了
综上:出现问题的地方是c语言对于字符串结束的识别问题
a=ab是因为没有找到结束符‘\0'所以把后面b的内容也输出了

求采纳 T T 好辛苦

本回答被提问者采纳
第2个回答  2018-03-12
这个赋值语法上是没有问题的,逻辑上却有问题,逗号也算是字符串一部分,%S遇到空格或回车或换行结束输入,显然3,4,5,6最后出现了个回车+换行,所以全都进a里面了,至于越界,编译器不管,反正是操作地址,这个要靠程序员自己检查。
相似回答