2010-03-14 62 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; 
} 

我对专家的意见很好奇。

顺便说一句,让我们暂时忘记缓冲区溢出问题。