Printf, кажется, портит вывод простой программы на C - PullRequest
1 голос
/ 06 декабря 2009

У меня есть код для добавления дроби.

#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 ]

11 голосов
/ 06 декабря 2009

Ваша функция Add возвращает указатель на временную переменную, созданную в этой функции. Как только эта функция вернулась, программа может использовать эту память любым способом, каким пожелает; Вы не должны больше получать к нему доступ. В первый раз вам повезло - программа оставила эту область памяти в покое, и ваш результат был сохранен. Добавление во второй printf вызвало дополнительные изменения в памяти стека, и это переписало ваши исходные значения и выявило ошибку.

Вы должны передать указатель на frac_t функции Add, чтобы получить результат. E.g.:

void Add(frac_t *result, frac_t *b1, frac_t *b2) {
    // modify result here
}
3 голосов
/ 06 декабря 2009

В

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.

1 голос
/ 06 декабря 2009

Вы возвращаете адрес объекта, который является локальным для функции Add. Это означает, что после выхода из функции адрес больше не действителен, объект был уничтожен.

Если вы пытаетесь получить доступ к объекту, иногда он может работать (как в первом примере), но большую часть времени это не так, и вы не можете полагаться на то, что может делать программа.

Вам необходимо изменить функцию, чтобы она возвращала структуру по значению, а не указатель на локальную структуру, или чтобы взять указатель на структуру, в которую следует записать результат, или динамически распределять память для результата. и вернуть указатель на эту память. В последнем случае вызывающая сторона должна нести ответственность за освобождение этой памяти.

...