2010-03-05 92 views
2

對於一些背景,我正在用C語言編寫一個讀表應用程序,用於運行DOS專有版本的小型16位掌上電腦。C指針問題 - 我在這裏做錯了什麼?

我有一個顯示儀表信息並提示用戶輸入讀數的屏幕。當用戶按下該單元上的輸入鍵,下面的代碼將執行:

/* ... 
* beginning of switch block to check for keystrokes 
* ... 
*/ 
case KEY_ENTER: { 
    /* show what has been entered */ 
    if(needNew == 0) { 
     /* calculate usage for new reading */ 
     double usg = 0; 
     int ret = CalculateNewUsage(vlr, buf, &usg); 
     VerifyReadScreen(vlr, ret, buf, &usg); 
     needRedraw = TRUE; 
    } 
    break; 
} 
/* .... end switch statement */ 

vlr是一個指針,它指向包含所有帳戶/米的信息的結構,buf是用來存儲數值擊鍵char[21]類型的在這個塊之上處理的讀數。當我在調用CalculateNewUsage之前和之後檢查它們時,我的變量都包含有效數據。

但是,當我在輸入VerifyReadScreen後再次檢查變量數據時,newread指向內存中隨機的某處,並返回看起來像版權聲明的東西。有趣的是,無論帳號是什麼或讀入的是什麼 - 屏幕上都會顯示VerifyReadScreennewread的相同無效數據。我以與CalculateNewUsage相同的方式將地址傳遞到VerifyReadScreen,但不知何故,我已經結束了一些不同的事情。

這裏是VerifyReadScreen

BYTE VerifyReadScreen(const VLRREC * vlr, 
         const int status, 
         const char * newread, 
         const double * usage) { 

    /* snip a whole bunch of irrelevant formatting code */ 

    printf("%s", (*newread)); /* prints funky copyright text */ 

    /* snip more irrelevant formatting code */ 
    return TRUE; 
} 

謝謝Jefromi爲指出,在那裏我居然在VerifyReadScreen打印newread代碼真的應該閱讀:

printf("%s", newread); /* yay! */ 

,因爲我並不需要取消newread,因爲printf爲我做這個。我基本上是將一個指針傳給了一個指向內存中某個任意位置的指針。

+0

如何聲明'buf'和'usg'? – 2010-03-05 17:59:45

+0

當你說「'buf'是一個字符串」時,你的意思是它已經是'char *'了嗎?並且你正在投射它的地址來輸入'const char *'? – Cascabel 2010-03-05 18:00:25

+0

@Alokzilla - buf的類型是char [21]',在檢查鍵擊的代碼的功能塊中聲明。 usg在'case KEY_ENTER'塊中聲明。 – 2010-03-05 18:06:00

回答

7

我想我有足夠的信心張貼此作爲一個答案:

BYTE VerifyReadScreen(const VLRREC * vlr, const int status, const char * newread, const double * usage) { 
... 
    LCD_set_cursor_pos(19 - strlen(newread), 3); 
    printf("%s", (*newread)); /* prints funky copyright text */ 
... 
} 

你已經有了一個字符串(char*newread,但在printf的,你解引用它,它給你字符串的第一個字符。然後,您將它用作printf的%s的參數,因此它會嘗試轉到由該字符給出的內存地址並在其中顯示它找到的內容。

P.S.你有些不幸 - 通常,做這樣的事情很可能會給你一個段錯誤,所以你可以追蹤到那條線,並意識到那裏有一個指針錯誤。

+0

你是對的 - 拿出解除引用修復它!非常感謝! :D – 2010-03-05 18:36:23

+0

我應該補充一點,我一遍又一遍地看着那段代碼,它看起來並不合適。這些掌上電腦大部分時間都很有趣,而不是在你做錯某些事情時給出明確的錯誤信息。 – 2010-03-05 18:53:05

2

如果這就是你所面臨的問題,我不知道,但在VerifyReadScreen使用buffer,這是21個字符長,將最有可能溢出:

if(strlen((*vlr).ServAdd) >= 20) { 
    sprintf(buffer, "%20s", (*vlr).ServAdd); 
} 

%20s格式說明不阻止sprintf寫入超過20個字符。如果字符串短於20個字符(或者你想在if條件中想要<= 20?),它只是用空格填充字符串?

else { 
    memset(buffer, 0x20, (int)(strlen((*vlr).ServAdd)/2) + 1); 
    strcat(buffer, (*vlr).ServAdd); 
} 

這裏一些填充取決於字符串的長度做了,但我看不出它如何確保結果不超過20個字符。

+0

'snprintf'是你的朋友! – Cascabel 2010-03-05 18:24:50

+0

此代碼非常粗糙,但這很好理解。謝謝! – 2010-03-05 18:37:02