2010-03-14 60 views
5

我有功能:返回的char *函數

char *zap(char *ar) { 

    char pie[100] = "INSERT INTO test (nazwa, liczba) VALUES ('nowy wpis', '"; 
    char dru[] = "')"; 
    strcat(pie, ar); 
    strcat(pie, dru); 
    return pie; 
} 

和主要有:

printf("%s", zap(argv[1]) ); 

編譯時我得到警告:

test.c: In function ‘zap’: 
test.c:17: warning: function returns address of local variable 

我應該如何恢復char *屬性?

+1

看來你正在與數據庫交互。你必須使用純粹的C?另外,大多數DB都有API來安全地構建SQL語句。你可以使用這些嗎? – kennytm

+0

謝謝,是的 - 我使用MySQL C API,但我必須創建一個字符串用作查詢,因爲我不能在查詢本身中使用變量。 – Devel

回答

18

您最好的選擇可能是完全不返回它 - 相反,傳遞要填充到函數作爲參數的緩衝區。

void zap(char * pie, const char *ar) { 
    strcpy(pie, "INSERT INTO test (nazwa, liczba) VALUES ('nowy wpis', '"); 
    char dru[] = "')"; 
    strcat(pie, ar); 
    strcat(pie, dru); 
} 

然後調用它像這樣:

char pie[100]; 
zap(pie, "foo"); 

要防彈此功能,您還需要在長度緩衝區傳遞,然後覈對這個每次你即將加入時間一個新的查詢元素。

+5

緩衝區溢出說你好 – knittl

+2

如果在這段代碼中存在緩衝區溢出,那麼原來也會有一個緩衝區溢出。我試圖說明一個概念,而不是寫出完美的代碼。 – 2010-03-14 13:26:45

+1

夠公平的。你仍然可以使用strncpy編寫更好的代碼。順便說一句,你在第2行缺少一個paren;) – knittl

4

分配爲pie的內存malloc

+0

正如你所說的malloc,你能幫我寫一個合適的malloc到這個函數嗎? – Devel

2
char pie[100]; 

void zap(char* pie, char *ar) { 

    char pies[100] = "INSERT INTO test (nazwa, liczba) VALUES ('nowy wpis', '"; 
    char dru[] = "')"; 
    strcpy(pie, pies); 
    strcat(pie, ar); 
    strcat(pie, dru); 
} 

zap(pie, argv[1]); 
printf("%s", pie ); 
2

我強烈建議改變這個函數,讓用戶通過一個緩衝區和一個長度,並改用緩衝區。或者,您可以分配一個新的返回值實例,即malloc,但請確保向用戶留言以再次釋放它。

1

聲明你的字符數組靜態

static char pie[100] = "INSERT INTO test (nazwa, liczba) VALUES ('nowy wpis', '"; 
+1

多線程衝突問候,並且緩衝區溢出的可能性仍然存在。 – 2010-03-14 13:27:49

+0

... ... ...:D ... ... ... – knittl

12

張貼的解決方案,所有的工作,但只是爲了回答你的問題,爲什麼你會得到一個警告:當你在函數聲明餡餅緩衝

,您沒有分配堆內存,該變量正在堆棧中創建。該內存內容僅在該功能的範圍內得到保證。一旦你離開函數(返回之後),內存可以被重用,任何時候你都可以找到你指向的內存地址。因此,你會被警告你正在返回一個指向內存的指針,而這個指針並不能保證一直存在。

如果你想在一個c函數中分配持久化內存,你可以在該函數之外引用,你需要使用malloc(或其他類型的堆內存分配函數)。這將爲堆上的該變量分配內存,並且它將保持不變,直到使用free函數釋放內存爲止。如果你不清楚堆棧與堆內存,你可能想要谷歌,它會讓你的C經驗更順暢。

+0

這是[堆棧vs堆]的一個很好的答案(https://stackoverflow.com/questions/79923/what-and-where-are-the-stack-並且 - 堆) –

4
 
#include <assert.h> 
#include <stdio.h> 

/** 
* Returns the buffer, just for convenience. 
*/ 
char *generateSQL(char *buf, size_t bufsize, const char *ar) { 
    int n; 

    n = snprintf(buf, bufsize, "INSERT INTO test (nazwa, liczba) VALUES ('nowy wpis', '%s')", ar); 
    /* FIXME: Properly escape the argument, just in case it contains an apostrophe. */ 
    assert(0 <= n && (unsigned) n < bufsize); 
    return buf; 
} 

int main(int argc, char **argv) 
{ 
    char buffer[4096]; 

    assert(1 < argc); 
    printf("%s\n", generateSQL(buffer, sizeof(buffer), argv[1])); 
    return 0; 
} 
+0

沒關係,但是你通常不想使用assert()進行運行時錯誤檢查... – jpalecek

+0

我知道...但它很簡單...: -/ –

+0

偉大的代碼,謝謝!你能在我的腦海裏讀到嗎? ;) – Devel

0

稍微不同的方法:

void zap(char **stmt, char *argument, size_t *stmtBufLen) 
{ 
    char *fmt="INSERT INTO test(nazwa, liczba) VALUES ('nowy wpis', '%s')"; 
    /** 
    * Is our current buffer size (stmtBufLen) big enough to hold the result string? 
    */ 
    size_t newStmtLen = strlen(fmt) + strlen(argument) - 2; 
    if (*stmtBufLen < newStmtLen) 
    { 
    /** 
    * No. Extend the buffer to accomodate the new statement length. 
    */ 
    char *tmp = realloc(*stmt, newStmtLen + 1); 
    if (tmp) 
    { 
     *stmt = tmp; 
     *stmtLen = newStmtLen+1; 
    } 
    else 
    { 
     /** 
     * For now, just write an error message to stderr; the statement 
     * buffer and statement length are left unchanged. 
     */ 
     fprintf(stderr, "realloc failed; stmt was not modified\n"); 
     return; 
    } 
    } 
    /** 
    * Write statement with argument to buffer. 
    */ 
    sprintf(*stmt, fmt, argument); 
} 

int main(void) 
{ 
    char *stmtBuffer = NULL; 
    size_t stmtBufferLen = 0; 
    ... 
    zap(&stmtBuffer, "foo", &stmtBufferLen); 
    ... 
    zap(&stmtBuffer, "blurga", &stmtBufferLen); 
    ... 
    zap(&stmtBuffer, "AReallyLongArgumentName", &stmtBufferLen); 
    ... 
    zap(&stmtBuffer, "AnEvenLongerRidiculouslyLongArgumentName", &stmtBufferLen); 
    ... 
    free(stmtBuffer); 
    return 0; 
} 

此版本使用動態存儲器分配根據需要來調整緩衝器,具有NULL緩衝器指針開始(realloc的(NULL,大小)==的malloc(大小) )。這樣你就不必擔心從一個「足夠大」的緩衝區開始。唯一的缺點是你需要記住當你完成緩衝區時釋放緩衝區(我通常不喜歡這樣分配調用者和被調用者之間的內存管理職責;如果我考慮了超過10分鐘,拿出更好的東西)。

0

我做這樣的操作是使本地緩存的靜態線程特定變量的方式:

const int max_pie_cnt = 100; 
const char *zap(char *ar) { 

    static __declspec(thread) char pie[max_pie_cnt]; // use TLS to store buffer 
    strcpy(pie, "INSERT INTO test (nazwa, liczba) VALUES ('nowy wpis', '"); 
    char dru[] = "')"; 
    strcat(pie, ar); 
    strcat(pie, dru); 
    return pie; 
} 

我對專家的意見很好奇。

順便說一句,讓我們暫時忘記緩衝區溢出問題。