在函数中返回 char*

Posted

技术标签:

【中文标题】在函数中返回 char*【英文标题】:Returning char* in function 【发布时间】:2011-01-27 09:17:07 【问题描述】:

我有功能:

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*?

【问题讨论】:

您似乎正在与数据库进行交互。你必须使用纯C吗?此外,大多数数据库都有 API 来安全地构造 SQL 语句。你能用这些吗? 谢谢,是的 - 我使用 mysql C API,但我必须创建一个字符串用作查询,因为我不能在查询本身中使用变量。 【参考方案1】:

mallocpie分配内存

【讨论】:

正如你提到的malloc,你能帮我如何为这个函数写一个合适的malloc吗?【参考方案2】:

您最好的选择可能是根本不返回它 - 而是将要填充的缓冲区作为参数传递给函数。

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" );

要对这个函数进行防弹,你还需要传入缓冲区的长度,然后在每次要添加新的查询元素时进行检查。

【讨论】:

缓冲区溢出问好 如果这段代码中存在缓冲区溢出,那么原始代码中也会存在。我试图说明一个概念,而不是编写完美的代码。 很公平。你仍然可以使用 strncpy 编写更好的代码。顺便说一句,你在第 2 行缺少一个括号;)【参考方案3】:
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  );

【讨论】:

【参考方案4】:

我强烈建议更改此函数,让用户同时传递一个缓冲区和一个长度,并改用该缓冲区。或者,您可以分配返回值的新实例,即使用malloc,但请确保给用户留下评论以再次释放它。

【讨论】:

【参考方案5】:

声明你的 char 数组是静态的

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

【讨论】:

多线程冲突问好,缓冲区溢出的可能性还是存在的。【参考方案6】:

发布的解决方案都有效,但只是为了回答您为什么会收到警告的问题:

当您在函数中将 pie 声明为缓冲区时,您并没有分配堆内存,而是在堆栈中创建变量。该内存内容仅在该功能范围内得到保证。一旦你离开函数(在返回之后),内存可以被重用于任何事情,你可以发现你指向的内存地址随时被覆盖。因此,您会被警告您正在返回一个指向内存的指针,该指针不能保证保留。

如果你想在一个 c 函数中分配持久内存,你可以在该函数之外引用,你需要使用 malloc(或其他风格的堆内存分配函数)。这将为堆上的该变量分配内存,并且它将一直存在,直到使用 free 函数释放内存为止。如果您不清楚堆栈与堆内存的区别,您可能需要 google 一下,这将使您的 C 体验更加流畅。

【讨论】:

这是对stack vs heap的一个很好的回答【参考方案7】: #include #include /** * 返回缓冲区,只是为了方便。 */ char *generateSQL(char *buf, size_t bufsize, const char *ar) 诠释n; n = snprintf(buf, bufsize, "INSERT INTO test (nazwa, liczba) VALUES ('nowy wpis', '%s')", ar); /* FIXME: 正确转义参数,以防它包含撇号。 */ 断言(0

【讨论】:

没关系,但你通常不想使用 assert() 进行运行时错误检查... 我知道...但是很简单... :-/【参考方案8】:

略有不同的方法:

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, size) == malloc(size)) 开始。这样您就不必担心从“足够大”的缓冲区开始。唯一的缺点是你需要记住在完成后释放缓冲区(我通常不喜欢像这样在调用者和被调用者之间划分内存管理职责;如果我考虑了超过 10 分钟,我d 想出更好的东西)。

【讨论】:

【参考方案9】:

我进行此类操作的方式是使本地缓冲区成为静态线程特定变量:

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;

我对专家的cmets很好奇。

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

【讨论】:

以上是关于在函数中返回 char*的主要内容,如果未能解决你的问题,请参考以下文章

如何从 char* 函数返回指针

Char* 在函数中使用 malloc 创建,编译器说地址在堆栈上,无法返回

为啥 char** 不能成为 C++ 中以下函数的返回类型?

从函数返回 char* 和 char[] 有啥区别? [复制]

函数中返回char *类型

函数返回 Int 而不是 char