在这种情况下要求`malloc()`

时间:2018-01-15 20:53:37

标签: c

现在,我正在研究Yale course

其中一个片段是:

char *
strdup(const char *s)
{
    char *s2;

    s2 = malloc(strlen(s)+1);

    if(s2 != 0) {
        strcpy(s2, s);
    }

    return s2;
}

如果我理解正确,我们需要malloc(),因为我们将字符串s复制到另一个字符串s2中,因此我们需要为s2分配足够的空间。但是,当我尝试以下代码时:

#include <stdio.h>

int main(void) {
    // your code goes here
    char *str = "Test";

    printf("%s", str);

    return 0;
}

here,它为我提供了正确和预期的输出。

所以,我有两个问题:

  1. 第一个代码段中是否需要malloc(),因为我们需要s2作为数组?

  2. 我是否在第二个片段中调用UB,(因为我没有声明*str指向数组的地方)?我们需要一个数组,因为在C中,字符串存储为字符数组。

3 个答案:

答案 0 :(得分:2)

是的,需要复制字符串。 (你无关紧要的原因)你正在分配内存来保存重复的字符串。在第二种情况下,您只是通过将指针传递给printf来打印文字,您不会复制任何内容。

这里没有UB - 这是合法代码。 char* str正在将char*初始化为指向文字数组的衰减指针。衰减的指针指向数组的第一个元素。

确实,字符串在C中存储为char数组 - 但它如何影响我们在第二个片段中看到的行为?我们正在传递一个char*,它指向空终止的char数组,正好是%s的{​​{1}}说明符所期望的。

文字也有静态存储时间。您不需要创建用于存储它们的内存。当您编写printf时,这是隐式完成的。

答案 1 :(得分:1)

此代码:

char *str = "Test";

表示:

  • 创建一个包含T,e,s,t和空字符的五个字符的数组。该阵列的存储是“静态的”;它是在程序的整个生命周期内分配的。

  • 创建指向名为char的{​​{1}}的指针,并将其初始值设置为上面创建的数组中第一个字符的地址。

在这种情况下,str的存储空间会自动分配给您,作为编译,加载和执行程序的一部分。

相反,在"Test"代码中,函数传递指向字符串的指针。 (字符串是一个字符数组,其字符串用于标记字符串的结尾。)在这种情况下,函数事先不知道字符串的长度。因此,在调用函数之前,它不知道需要多少内存,它使用strdup来测量字符串的长度。

如果您事先不知道需要多少内存,通常需要使用strlen或其中一个相关的内存分配例程来分配存储空间。 (另一种方法是使用可变长度数组。并非所有C实现都支持可变长度数组,并且它们只应用于仅在一个函数中需要的小型或中等大小的数组。)

答案 2 :(得分:0)

  

我没有声明* str指向数组

你错了。字符串文字存储为具有静态存储持续时间的字符数组。

所以在这个宣言中

char *str = "Test";
发生了两件事。

第一个是编译器创建一个类型为char[5]的字符数组,其中存储了字符串文字。然后,数组的第一个字符的地址用于初始化具有自动存储持续时间的指针str

您甚至可以通过以下方式重写声明

char *str = &"Test"[0];
  

第一个片段中是否需要malloc()因为我们需要s2才能成为   阵列

函数strdup创建原始字符串的副本。所以你必须存储创建副本的某个地方。要做到这一点,你必须分配足够的内存来存储副本,并从函数返回一个指针,该指针将指向带有字符串副本的已分配内存。