代码之家  ›  专栏  ›  技术社区  ›  citronas

printf似乎把一个简单的C程序的输出搞得一团糟。

  •  1
  • citronas  · 技术社区  · 15 年前

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

    #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 回复  |  直到 15 年前
        1
  •  11
  •   int3    15 年前

    你的职能 Add 正在返回指向在该函数中创建的临时变量的指针。一旦该函数返回,程序就可以以它希望的任何方式使用该内存;您不应该再访问它了。你第一次幸运了——程序恰好离开了内存区域,结果被保存了下来。添加到第二个 printf 导致了对堆栈内存的额外修改,这会覆盖原始值并暴露出错误。

    您应该将指针传递给 frac_t 对函数 添加 而是得到你的结果。例如。:

    void Add(frac_t *result, frac_t *b1, frac_t *b2) {
        // modify result here
    }
    
        2
  •  3
  •   anon    15 年前

    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显示自身。

        3
  •  1
  •   CB Bailey    15 年前

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

    如果您试图访问对象,有时它可能会工作(如在第一个示例中),但大多数情况下它不会工作,并且您不能依赖程序可能会做什么。

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