-3

在玩了几个星期 C 之后,我现在讨厌它。

我现在正在尝试使用 execl 将参数传递给另一个程序,并且参数的格式会做一些奇怪的事情:

int select[2], result[2];
char str_w,str_r;

snprintf(&str_w, 2, "%d", select[1]);
snprintf(&str_r, 2, "%d", result[0]);
printf("%d %d %s %s\n", select[1], result[0], &str_w, &str_r);

execl("./recive.x","./recive.x",&str_w,&str_r,(char *)NULL);

这里重要的是 snprintf:我正在尝试将向量中的数字转换为字符串。该数字将小于 10。当我执行此操作时,显示的 printf 的结果是:

5 6  6

这意味着 select[1] 中有一个数字 (5),result[0] 中有一个数字 (6),并且 result[0] 被正确转换为字符串,但 select[1] 没有。

这到底是什么行为!!

先感谢您!

4

3 回答 3

2

对 sprintf 的调用必须为打印数据提供一个缓冲区,足以容纳整个输出。您正在传递一个指向单个字符的指针,因此输出显然不适合。

char str_w[2];
snprintf(str_w, 2, "%d", select[0]);

将一位数转换为字符串的更好方法如下:

char res[2];
res[0]=num+'0';
res[1]=0;

注意第一个零周围的单引号:想法是将零字符的代码添加到一位数。

于 2013-02-17T14:24:22.440 回答
2

在玩了几个星期 C 之后,我现在讨厌它。

这种反应并不少见。我的 CS 入门课程中有三分之一的人改变了专业,理由是 C 语言有困难(这是一种可怕的教学语言)。我花了几年的时间才充分理解它,但一旦我做到了,我就开始欣赏它。

char str_w,str_r;

snprintf(&str_w, 2, "%d", select[1]);
snprintf(&str_r, 2, "%d", result[0]);

这是您的主要问题;str_w并且str_r仅大到足以容纳单个char值,而不是字符串(至少需要2 个字符)。相反,您需要将str_wand声明str_r为 的数组char足够大以容纳int您所期望的最大字符串表示形式,加上符号空间(如果值为负数),再加上 0 终止符。例如,如果您没有限制selector的值result

#define MAX_DIGITS 20 // max decimal digits for 64-bit integer
#define SIZE MAX_DIGITS+2 // 2 extra for sign and 0 terminator

char str_w[SIZE], str_r[SIZE]; 

sprintf(str_w, "%d", select[1]);
sprintf(str_r, "%d", result[0]);

通过使您的目标数组足够大以容纳任何可能的输入,您不必担心溢出。是的,您会遭受一些内部碎片,并且取决于您的应用程序,这可能是也可能不是问题。但我只是喜欢保持简单。

如果您知道您的selectresult数组永远不会保存 0..10 范围之外的值,那么您可以将 SIZE 设置为 3(最多 2 位数字加上 0 终止符)。

这意味着 select[1] 中有一个数字 (5),result[0] 中有一个数字 (6),并且 result[0] 被正确转换为字符串,但 select[1] 没有。

这到底是什么行为!!

由于您将地址传递给不足以容纳结果的缓冲区,因此行为是undefined,这意味着编译器没有义务警告您您正在做一些危险的事情。

这是最有可能发生的事情(由于行为未定义,任何事件序列都是可能的,但我认为这是对结果的合理解释)。首先,假设您的变量在内存中的布局如下:

Item        Address        Value
----        -------        -----
str_r       0xffec1230     ??
str_w       0xffec1231     ??
            0xffec1232     ??

str_wstr_r分配给连续的字节,它们的初始值是不确定的。在第一个snprintfto之后str_w,你的记忆现在看起来像这样:

Item        Address        Value
----        -------        -----
str_r       0xffec1230     ??
str_w       0xffec1231     '5'
            0xffec1232     0

snprintf将尾随的 0 终止符写入缓冲区;在这种情况下,它将终止符写入后面的字节str_w。在第二次sprintf调用之后,内存现在看起来像这样:

Item        Address        Value
----        -------        -----
str_r       0xffec1230     '6'
str_w       0xffec1231     0
            0xffec1232     0

第二次snprintf调用将 0 终止符写入后面的字节str_r,恰好是str_w; 你最终破坏了之前写入它的值。这就是为什么您看到str_r字符串但看不到字符串的原因str_w

于 2013-02-17T15:16:18.553 回答
0

char您一起定义唯一的一个字节变量。它必须是一个 s 数组char

于 2013-02-17T14:21:00.077 回答