Printf似乎搞乱了一个简单的C程序的输出

时间:2009-12-06 15:18:44

标签: c pointers structure printf

我有一些代码可以添加分数。

#include <stdio.h>
#include <stdlib.h>

struct frac
{
    int enumerator;
    int denominator;
};
typedef struct frac frac_t;


frac_t *Add(frac_t *b1, frac_t *b2)
{
  frac_t rfrac;
  frac_t *p;
  p = &rfrac;
 (*p).enumerator= ((*b1).enumerator* (*b2).denominator) + ((*b2).enumerator* (*b1).denominator);
 (*p).denominator= ((*b1).denominator* (*b2).denominator);
  return p;
}

int main(void)
{
  frac_t b1 = {2,4};
  frac_t b2 = {1,7};
  frac_t *add = Add(&b1, &b2);
  printf("%i %i\n", add->enumerator, add->denominator);
  system("pause");
  return 0;
}

这完全没问题。结果是:3 5,因为它应该是。

如果我添加“printf”,它会完全弄乱我的结果:

int main(void)
{
 frac_t b1 = {2,4};
 frac_t b2 = {1,7};
 frac_t *add = Add(&b1, &b2);
 printf("addition:\n"); 
 printf("%i %i\n", add->enumerator, add->denominator);
 system("pause");
 return 0;
}

结果是:

此外:

2008958704 -1

出了什么问题?

3 个答案:

答案 0 :(得分:11)

您的函数Add正在返回指向该函数内创建的临时变量的指针。一旦该函数返回,程序就可以以任何方式使用该内存;你不应该再访问它了。你第一次幸运 - 程序碰巧只留下了那段记忆,你的结果得以保留。添加第二个printf会导致对堆栈内存的额外修改,这会覆盖原始值并暴露出错误。

您应该将指向frac_t的指针传递给函数Add,而不是获得结果。 E.g:

void Add(frac_t *result, frac_t *b1, frac_t *b2) {
    // modify result here
}

答案 1 :(得分:3)

frac_t *Add(frac_t *b1, frac_t *b2)
{
  frac_t rfrac;
  frac_t *p;
  p = &rfrac;
 (*p).enumerator= ((*b1).enumerator* (*b2).denominator) + ((*b2).enumerator* (*b1).denominator);
 (*p).denominator= ((*b1).denominator* (*b2).denominator);
  return p;
}

你返回一个局部变量rfrac的地址。当您使用它时,这会给您未定义的行为。 printf()调用只是让UB显现出来。

答案 2 :(得分:1)

您将返回函数Add的本地对象的地址。这意味着一旦你离开函数地址不再有效,对象就会被破坏。

如果您尝试访问该对象,有时它可能会起作用(如您的第一个示例中所示),但很多时候它不会,您不能依赖该程序可能会执行的操作。

您需要更改为按函数返回结构,而不是指向本地结构的指针,或者指向应该向其写入结果的结构的指针,或者为结果动态分配内存并返回指向此内存的指针。在最后一种情况下,调用者必须负责释放该内存。