2009-12-06 45 views
1

我有一些代碼加分的輸出。printf的似乎一團糟一個簡單的C程序

#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

出了什麼問題?

+0

請參閱http://stackoverflow.com/questions/1846334/printf-modifying-a-string/1846365#1846365 – JCasso 2009-12-06 15:27:41

+2

分數中的頂部數字稱爲「分子」,而不是「枚舉數」。 – SoapBox 2009-12-06 15:36:50

回答

11

你的功能Add返回一個指針,該函數中創建一個臨時變量。一旦該函數返回,程序就可以以任何希望的方式使用該內存;你不應該再訪問它。你第一次感到幸運 - 節目恰好離開了這個記憶區域,並且你的結果被保留下來了。添加第二printf造成其他修改堆棧內存,而這改寫原來的價值和暴露的bug。

您應該將指向frac_t的指針傳遞給函數Add,而不是獲得您的結果。例如: -

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

+1的確切原因。 – 2009-12-07 04:39:09

1

你是返回一個對象,它是本地的功能Add的地址。這意味着一旦你離開函數地址不再有效,對象就被銷燬了。

如果您嘗試訪問該對象,有時它可能會工作(如您的第一個示例中所示),但大多數情況下它不會,並且您無法依賴該程序的功能。

您需要更改爲函數,以便通過值返回結構而不是指向局部結構的指針,或者接受指向應該寫入結果的結構的指針,或爲函數動態分配內存結果並返回一個指向這個內存的指針。在最後一種情況下,調用者必須負責釋放該內存。

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顯示自己。