【问题标题】:Why do we have to malloc in this string function c? [duplicate]为什么我们必须在这个字符串函数 c 中进行 malloc? [复制]
【发布时间】:2018-01-23 21:22:07
【问题描述】:
char * concat(const char *s1, const char *s2) {
    char result[70];
    strcpy(result, s1);
    strcat(result, s2);
    return result;
}
int main() {
    char *s1 = "Hello";
    char *s2 = " World!";
    char *s3 = concat(s1, s2);
    printf("%s\n", s3);

    return 0;
}

这个程序只调用concat 函数,它返回一个char *,它是s1 and s2 的concat。但是,在编译时,我收到错误address of stack memory associated with local variable 'result' returned

所以我知道result 是 concat 函数中的一个局部变量,但并不是我们必须 malloc 它的真正原因。为什么不直接以 Hello World 的值返回结果?

如果你考虑这样的程序:

int ret() {

    int a = 4;
    return a;
}
int main() {
    int b = ret();
    printf("%d\n", b); // 4

    return 0;
}

没有错误。我不必malloc int。 a 是本地的,但我仍然返回它,它仍然有效。

我想知道 concat 和 ret 的主要区别是什么,以及为什么 concat 必须动态分配内存。谢谢。

【问题讨论】:

  • 有人愿意解释一下否决票以便我改进这个问题吗?
  • 这个“Hello world”应该存储在哪里?
  • char * 表示“指向字符的指针”,而不是“70 个字符的块”
  • @MartinJames 好吧,OP 声称“我知道结果是 concat 函数中的局部变量”。这使得它比 dup 更“不清楚”。
  • 我将它作为 dup 关闭,因为我有锤子 - 它更快。

标签: c string memory malloc dynamic-memory-allocation


【解决方案1】:

来自 C 标准(6.2.4 对象的存储持续时间)

1 对象具有决定其生命周期的存储期限。 有四种存储持续时间:静态、线程、自动和 分配。 7.22.3 中描述了分配的存储空间。

2 对象的生命周期是程序执行期间的一部分 保证为它保留哪些存储空间。对象存在, 有一个常量地址,33) 并保留其最后存储的值 34) 如果一个对象在其生命周期之外被引用 它的生命周期,行为是未定义的。指针的值 当它指向(或刚刚过去)的对象时变得不确定 达到其生命周期的终点。

6 对于这样一个没有变长数组类型的对象, 它的生命周期从进入它所在的块开始 关联,直到该块的执行以任何方式结束...

在这个函数定义中

char * concat(const char *s1, const char *s2) {
    char result[70];
    strcpy(result, s1);
    strcat(result, s2);
    return result;
}

变量result具有自动存储持续时间。它的生命周期在退出函数后结束。所以正如标准中所写的那样

如果一个对象在其生命周期之外被引用,则行为是 未定义。

如果动态分配数组,那么它的生命周期不会在退出函数后结束,指向它的指针将是有效的。您可以在分配内存的函数之外访问分配的内存。

至于这个函数定义

int ret() {

    int a = 4;
    return a;
}

然后函数返回对象本身。如果您通过这样的指针间接返回对象

int * ret() {

    int a = 4;
    return &a;
}

那么您遇到的问题与第一个程序相同,即如果您尝试使用返回的指针访问变量 a,该程序将具有未定义的行为。

考虑到函数可以返回 int 类型的对象,但不能返回数组。

【讨论】:

    【解决方案2】:
    char * concat(const char *s1, const char *s2) {
        char result[70];
        strcpy(result, s1);
        strcat(result, s2);
        return result;
    }
    

    在你的函数中,结果数组在函数调用后被释放,所以 char *s3 = concat(s1, s2); 指针 s3 指向的地址无效。

    【讨论】:

      【解决方案3】:

      有一些方法可以让这个函数在没有动态内存分配的情况下工作。例如,如果兼容多线程并在函数内部声明一个静态变量,则可以放弃所有希望。插图:

      char* concat() {
          static char result[70];
          // ... rest of the code
      }
      

      【讨论】:

        【解决方案4】:

        返回像int 这样的基元和返回字符串在C 中是根本不同的。字符串不是基元对象,实际上是字符数组。就像您不能在本地函数中声明一个数组,然后返回该数组一样,您不能简单地返回字符串。编译器不会抛出错误,而是警告,因为通常情况下,存储result的内容的栈帧在函数返回时并没有被清除,所以在退出函数后的一小段时间内,你可能仍然能够返回指针,但不要指望它。

        这里的根本区别在于malloc 将在堆上分配空间,除非另有明确说明,否则不会被覆盖,而在函数中简单地声明一个数组并不能保证该数组占用的空间仍然可以访问/ 函数退出后可读(因此是局部变量)。

        【讨论】:

        • 是UB的经典例子。
        • UB 是未定义的行为?
        • 你好,我的朋友。未定义的行为
        • 你的'因为通常......'是非常错误的。这不是编译器没有给出错误。
        猜你喜欢
        • 1970-01-01
        • 2015-05-29
        • 2011-12-30
        • 2014-07-02
        • 2023-03-07
        • 2020-09-03
        • 2011-03-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多