Chinaunix

标题: sprintf困惑 [打印本页]

作者: jiangf    时间: 2008-10-23 14:07
标题: sprintf困惑
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;

int main()
{
&nbsp;&nbsp;&nbsp;&nbsp;char s1[20]="319";
&nbsp;&nbsp;&nbsp;&nbsp;char s2[10];
&nbsp;&nbsp;&nbsp;&nbsp;memset(s2,0,sizeof(s2));
&nbsp;&nbsp;&nbsp;&nbsp;strcpy(s2,"1235");
&nbsp;&nbsp;&nbsp;&nbsp;sprintf(s1,"%s%s",s2,s1);
&nbsp;&nbsp;&nbsp;&nbsp;printf("%s\n",s1);
}

我本来想用这段代码实现字符串的拼接,吧s2加载到s1的前面,可为什么出来的结果却是12351235,如果要实现把s2加载到s1的后面却一切正常
作者: 5毛党党员    时间: 2008-10-23 14:22
sprintf(s1,"%s%s",s2,s1);

第一步,已经把 s2 复制到 s1的地址了
第二步,再把 s1 接到 s1后面 ,这时s1已经是"1234"了
作者: cuteorange    时间: 2008-10-23 14:35
原帖由 5毛党党员 于 2008-10-23 14:22 发表
sprintf(s1,"%s%s",s2,s1);

第一步,已经把 s2 复制到 s1的地址了
第二步,再把 s1 接到 s1后面 ,这时s1已经是"1234"了


C 标准中, 挡逗号操作符(,)出现在函数的参数列表中,则表达式的计算顺序跟实现有关。你的正好是从左至右进行计算,故得到12351235;如果换到别的机器上,实现是逗号操作符从有往左计算,则可以得到预期的结果。通常不要写和实现相关的代码。
作者: Godbach    时间: 2008-10-23 14:48
1. 新声明一个字符串, strcat然后strcpy给s1
2. 将原先的s1中字符串保存在另外一个字符串里,然后实现copy
作者: jiangf    时间: 2008-10-28 22:30
哦,sprintf实际是上分两步走的,对吧
作者: lipingtababa    时间: 2008-10-28 22:39
哈,你忘了你用的是原始的愚蠢的C,你得从机器的角度想问题.

如果是OO的Java或者别的什么语言,你就可以用这样的思维.
作者: newbie1984    时间: 2008-10-28 22:39
原帖由 cuteorange 于 2008-10-23 14:35 发表


C 标准中, 挡逗号操作符(,)出现在函数的参数列表中,则表达式的计算顺序跟实现有关。你的正好是从左至右进行计算,故得到12351235;如果换到别的机器上,实现是逗号操作符从有往左计算,则可以得到预期的结果 ...

给个掌声支持! 通常实现sprintf, 在c都是从左开始计算进行传参的, pasical其他的除外.
作者: aoegiss    时间: 2008-10-28 22:45
原帖由 cuteorange 于 2008-10-23 14:35 发表


C 标准中, 挡逗号操作符(,)出现在函数的参数列表中,则表达式的计算顺序跟实现有关。你的正好是从左至右进行计算,故得到12351235;如果换到别的机器上,实现是逗号操作符从有往左计算,则可以得到预期的结果 ...


正解
作者: yecheng_110    时间: 2008-10-29 08:48
If copying takes place between objects that overlap as a result of a call to
       sprintf() or snprintf(), the results are undefined.
作者: jakepain    时间: 2008-10-29 09:19
一早就学到知识了
真好
谢谢大家
作者: Lee@china    时间: 2008-10-29 10:20
补充一下,strcat 只能连接字符串(一段以’\0’结尾的字符数组或叫做字符缓冲,null-terminated-string),但有时我们有两段字符缓冲区,他们并不是以’\0’结尾。比如许多从第三方库函数中返回的字符数组,从硬件或者网络传输中读进来的字符流,它们未必每一段字符序列后面都有个相应的’\0’来结尾。如果直接连接,不管是sprintf 还是strcat 肯定会导致非法内存操作,而strncat 也至少要求第一个参数是个null-terminated-string,那该怎么办呢?想到打印字符串可以指定长度,比如:
char a1[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G'};
char a2[] = {'H', 'I', 'J', 'K', 'L', 'M', 'N'};
如果:
sprintf(s, "%s%s", a1, a2); //Don't do that!
十有八九要出问题了。是否可以改成:
sprintf(s, "%7s%7s", a1, a2);
也没好到哪儿去,正确的应该是:
sprintf(s, "%.7s%.7s", a1, a2);//产生:"ABCDEFGHIJKLMN"
作者: RNW    时间: 2008-10-29 10:32
恩,学习
作者: shaoxia    时间: 2008-10-29 11:05
补充一下,strcat 只能连接字符串(一段以’\0’结尾的字符数组或叫做字符缓冲,null-terminated-string),但有时我们有两段字符缓冲区,他们并不是以’\0’结尾。比如许多从第三方库函数中返回的字符数组,从硬件或者网络传输中读进来的字符流,它们未必每一段字符序列后面都有个相应的’\0’来结尾。如果直接连接,不管是sprintf 还是strcat 肯定会导致非法内存操作,而strncat 也至少要求第一个参数是个null-terminated-string,那该怎么办呢?想到打印字符串可以指定长度,比如:
char a1[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G'};
char a2[] = {'H', 'I', 'J', 'K', 'L', 'M', 'N'};
如果:
sprintf(s, "%s%s", a1, a2); //Don't do that!
十有八九要出问题了。是否可以改成:
sprintf(s, "%7s%7s", a1, a2);
也没好到哪儿去,正确的应该是:
sprintf(s, "%.7s%.7s", a1, a2);//产生:"ABCDEFGHIJKLMN"
---------------------------------------
char a1[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G'};
char a2[] = {'H', 'I', 'J', 'K', 'L', 'M', 'N'};
如果:
sprintf(s, "%s%s", a1, a2);

如果s缓冲区足够大,则此用法没有问题,因为a1和a2都是8个字节,以NULL结束
作者: yecheng_110    时间: 2008-10-29 12:01
原帖由 shaoxia 于 2008-10-29 11:05 发表
补充一下,strcat 只能连接字符串(一段以’\0’结尾的字符数组或叫做字符缓冲,null-terminated-string),但有时我们有两段字符缓冲区,他们并不是以’\0’结尾。比如许多从第三方库函数中返回的字符数组,从 ...

你原意是以'\0'结束吧
不过这样写是不会以'\0'结束的
作者: xbzjackey    时间: 2008-10-29 16:29
不错,一般要定义成char a[] = “ABCDEFG”;这样就会有'\0';




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2