【问题标题】:C function doesn't return a stringC函数不返回字符串
【发布时间】:2014-12-13 19:49:29
【问题描述】:

为什么这段代码没有返回预期的连接字符串,而是一个 2?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

const char * meh() {
    char meh1[32] = "This ";
    char meh2[32] = "should work :)";
    return strcat(meh1, meh2);
}

int main() {
    printf(meh());
    return 0;
}

【问题讨论】:

  • 你在开玩笑吗:printf(meh());?你在哪里读到的?
  • 不要将局部变量(strcat() 返回meh1)返回给调用代码。不要像那样使用printf():使用printf("%s\n", meh());。返回(指向)局部变量的变量是灾难的根源;你会得到未定义的行为,这意味着程序几乎可以做任何事情,无论发生什么都可以,因为编译器不需要对未定义的行为做任何明智的事情。
  • @Jonathan 我很确定他发布了预期结果和实际结果。
  • 继续 Jonathan Leffler 所说的,如果 meh() 返回由用户提供的输入形成的字符串,则 printf(meh()); 表单可能会导致 Uncontrolled format string vulnerability,更多信息在这里:en.wikipedia.org/wiki/Uncontrolled_format_string#Details
  • 鉴于问题的性质,我知道我之前的评论并没有太大帮助。但突出你面前的危险不会​​有任何害处。

标签: c function strcat


【解决方案1】:

因为一旦你离开函数 meh,meh1 就会超出范围,它在堆栈上占用的区域用于 printf 内部的其他事情。

【讨论】:

  • 这并不能解决 OP 的问题!他只知道现在是什么!
  • OP 的问题是“为什么?”不是“我该如何解决?” - 他或她可能即将在局部变量如何工作的概念上取得突破,只需要朝着正确的方向推进。
  • 好的,同意你的看法!但我认为看到 OP 的工作示例仍然会有所帮助!
【解决方案2】:

由于strcat() 写入了它的第一个参数,您实际上返回了一个指向meh1(的第一个元素)的指针。 meh1meh2 是具有自动存储持续时间的变量。一旦周围的函数返回,这些变量就会被销毁。访问它们会产生未定义的行为(通常是崩溃)。

你可以这样做:

const char *meh(void)
{
    char meh1[32] = "This ";
    char meh2[32] = "should work :)";

    char *result;
    size_t meh1_len, meh2_len;

    /* figure out how long meh1 and meh2 are */
    meh1_len = strlen(meh1), meh2_len = strlen(meh2);

    /* make a new string with enough space */
    result = malloc(meh1_len + meh2_len + 1);
    if (result == NULL)
        perror("Cannot malloc");

    /* Copy the strings */
    memcpy(result, meh1, meh1_len);
    memcpy(result + meh1_len, meh2, meh2_len + 1);

    return (result);
}

当您不再需要 meh() 的结果时,不要忘记调用 free()

【讨论】:

  • 好像是小错字,应该是meh1_len = strlen(meh1), meh2_len = strlen(meh2);。 +1 无论如何指出 UB :-)
  • @GrzegorzSzpetkowski 修正了错字。
  • 我阅读了其他 cmets,但我无法 100% 理解,但这个 sn-p 有效。我开始学习 C,我还有很多东西要学,感谢这段代码。
  • @FilipeTeixeira 永远记住:C 对你没有任何帮助。你必须自己做所有的事情!
【解决方案3】:

strcat 通过附加字符串meh2 修改字符串meh1,然后返回指向第一个字符串的指针。字符串meh1是在函数中声明的,所以指针在函数外是无效的。这就是为什么你没有得到你期望的结果。相反,您可以这样做:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void meh(char * meh1) {
    char meh2[32] = "should work :)";
    strcat(meh1, meh2);
    return;
}

int main() {
    char meh1[32] = "This ";
    meh(meh1);
    puts(meh1);
    return 0;
}

这将给出预期的结果。它之所以有效,是因为字符串meh1main 中声明,然后传递给要修改的函数。这意味着在函数调用meh 之后,修改后的字符串在main 中仍然可用。

【讨论】:

  • 这适用于这种情况,因为变量足够大(特别是meh1 足够大以容纳连接产生的字符串)。但是,函数meh() 无法验证它是否正常。它不知道目标字符串有多大。因此,检查目标字符串中字符串的初始长度或要添加的字符串的长度是没有意义的,但是会告诉弹性代码有多少空间(例如void meh(char *buffer, size_t buflen),然后它会检查结果字符串适合缓冲区。
【解决方案4】:

来自strcat()的手册页,

char *strcat(char *dest, const char *src);   

strcat() 和函数返回一个指向结果字符串 dest 的指针。

根据你的用法,destchar meh1[32] 的基地址,它是meh() 的本地地址。一旦控件从meh() 返回,meh1 就会超出范围。所以,printf() 的结果是未确定的 [未定义的行为]。

要使其工作,请为meh1 使用指针和动态内存分配。

例如,

char *meh1 = NULL;
meh1 = malloc(32);
strcpy(meh1, "this");

以及其他现有的meh()

可以根据您的要求返回动态分配的指针。在main()的末尾,需要free()返回的指针,避免内存泄漏。

另外,你需要使用printf()like

 printf("%s\n", meh());

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-11-06
    • 2013-10-30
    • 1970-01-01
    • 2011-05-29
    相关资源
    最近更新 更多