使用malloc初始化char指针VS不使用malloc而是直接将字符串直接分配给char指针

时间:2019-07-10 05:47:26

标签: c arrays string pointers memory-management

我试图了解当涉及char和string时,这种内存分配方式是如何工作的。

我知道声明的数组的名称就像指向该数组第一个元素的指针一样,但是该数组将存在于内存的 stack 中。

另一方面,当我们想使用内存堆时,我们使用malloc,但是我发现您可以初始化一个char指针并在同一条声明行上为其分配一个字符串,所以我有一些有关此问题的问题:

1)如果我只是初始化一个char指针并为其分配一个字符串,则该信息在哪里?在堆中?在堆栈中? 例如:char *pointer = "Hello world";

2)我尝试使用malloc初始化我的char指针,并在以后使用它为它分配一个字符串,但是我无法编译它,但出现错误,是什么这个逻辑错了吗?这就是我要尝试的事情:

char *pointer = malloc(sizeof(char) * 12); *pointer = "Hello world";

能否请您帮助我更多地了解指针和内存分配?非常感谢你! :)

4 个答案:

答案 0 :(得分:1)

长问题,但答案很简单。首先,您需要了解什么是指针。

 componentDidMount() {
  var headers = {
    "Content-Type": "application/json",
    Authorization: `Token ${authToken}`
  };
  axios
    .get(`${serverURL}users/${this.props.match.params.id}`, {
      headers: headers
    })
    .then(res => {
      //console.log(res.data);
      let userdetails = res.data;
      this.setState({
        first_name: userdetails.first_name,
        last_name: userdetails.last_name,
        email: userdetails.email,
      });
    })
    .catch(function(error) {
      console.log(error);
    });
}

在这里,您尝试为char分配一个指针。如果您删除*,则会将指针分配给 *pointer = "Hello world"; 的字符串文字。

除非您使Assign运算符过载,否则它将不会将其复制到分配的内存中。当您为指针分配新值时,malloc毫无意义,而由malloc分配的内存将丢失

您需要代替它

  

这些信息住在哪里?

取决于实现的字符串文字的存储位置。它可以在任何地方。请记住,您不能修改字符串文字。尝试这样做是未定义的行为

答案 1 :(得分:1)

  

1)如果我只是初始化一个char指针并为其分配一个字符串,则该信息在哪里?在堆中?在堆栈中?例如:char * pointer =“ Hello world”;

字符串文字"Hello world"具有静态存储持续时间。这意味着只要程序正在运行,它就存在于程序可访问的内存中。

确切的位置是特定于实现的。

  

2)我尝试使用malloc初始化我的char指针,并在以后使用它为它分配一个字符串,但是我无法编译它,但出现错误,此逻辑有什么问题?这就是我想要做的:

char *pointer = malloc(sizeof(char) * 12);
*pointer = "Hello world";

这不起作用,因为*pointer是动态分配的内存中的第一个char(由malloc()返回)。字符串文字"Hello world"表示为字符数组。字符数组不能存储在单个char中。

在这种情况下,您实际需要做的是将数据从字符串文字复制到动态分配的内存中。

char *pointer = malloc(sizeof(char) * 12);
strcpy(pointer, "Hello world");            /* strcpy() is declared in standard header <string.h> *

请注意,这不会更改表示字符串文字的数据。它将字符串文字中的数据复制到pointer指向的内存中(并由malloc()动态分配)。

如果您确实希望pointer指向字符串文字的(第一个字符),请执行

const char *pointer = "Hello world";

const代表了一个事实,即修改字符串文字会产生未定义的行为(并且意味着以上内容阻止了使用pointer来修改该字符串文字)。

如果您想编写非常糟糕的代码,也可以这样做

char *pointer = "Hello world";   /*  Danger Will Robinson !!!! */

或(相同的净效果)

char *pointer;
pointer = "Hello world";     /*  Danger Will Robinson !!!! */

pointer现在可用于修改字符串文字的内容-但这会导致未定义的行为。大多数编译器(如果配置正确)都会对此发出警告-这是您不应执行此操作的许多提示之一。

答案 2 :(得分:1)

  

1)如果我只是初始化一个char指针并为其分配一个字符串,   这些信息住在哪里?在堆里?在堆栈中?例如:char *pointer = "Hello world";

无论是在堆栈上还是在堆上。 "Hello world"是一个字符串文字,通常在可执行文件的rodata(只读数据)段中创建。实际上,除非您另外指定,否则编译器可以自由地仅存储"Hello world"的单个副本,即使您将其分配给多个指针也是如此。尽管通常不能将字符串分配给指针,但是由于这是 string文字,因此实际上是为文字本身分配地址-这是唯一起作用的原因。否则,如P__J__所述,您必须将字符串从一个位置复制到另一位置。

  

2)我尝试使用malloc初始化我的char指针并使用它   后来给它分配了一个字符串,但我无法编译它,但出现错误,   此逻辑有什么问题?这就是我要尝试做的事情:

char *pointer = malloc(sizeof(char) * 12);
*pointer = "Hello world";

您在这里混合苹果和橙子。 char *pointer = malloc (12);为12个字符(字节)分配存储空间,然后将该新存储块的起始地址分配为pointer作为其值。 (请记住,指针只是将地址保留为其他值的普通变量)

对于每个分配,都必须有 验证 ,该调用成功,否则您将需要处理失败。分配可以并且确实会失败,并且当分配失败时,malloc, calloc * realloc都将返回NULL。因此,每次分配时,您

char *pointer = malloc(12);       /* note: sizeof (char) is always 1 */
if (pointer == NULL) {            /* you VALIDATE each allocation */
    perror ("malloc-pointer");
    return 1;
}

继续上述情况,您已分配12字节并将新存储块的起始地址分配给pointer。然后,您莫名其妙地取消引用pointer(例如,*pointer现在具有类型char),并尝试将字符串文字的地址分配为该字符。 / p>

*pointer = "Hello world";    /* (invalid conversion between pointer and `char`) */

您要执行的操作是将"Hello world"复制到指针保存的新内存块中。为此,由于您已经知道"Hello world"是12个字符(包括 nul-termination 字符),因此您可以简单地:

memcpy (pointer, "Hello world", 12);

注意:,如果您已经有长度,则无需调用strcpy并使其再次扫描字符串末尾)

现在,新分配的内存块包含"Hello world",并且该内存是可变的,因此您可以更改任何喜欢的字符。

由于已分配存储空间,因此free (pointer);由您决定,该存储空间不再使用。

简而言之,这是将字符串文字的地址分配给指针,还是分配存储并将新存储块中的第一个地址分配给指针,然后将您喜欢的任何内容复制到该新块之间的区别(只要您保持在分配的内存块的分配范围内)。

仔细检查一下,如果还有其他问题,请告诉我。

答案 3 :(得分:1)

  

我知道声明的数组的名称就像是指向数组第一个元素的指针,…

这是不正确的。数组在许多表达式中的行为与指针类似(因为它会自动转换),但它的表现与第一个元素的指针不同。当用作sizeof或一元&的操作数时,数组将是一个数组;它不会转换为指针。另外,不能像指针一样分配数组。您不能为数组分配值。

  

…但是该数组将存在于内存堆栈中。

数组的存储取决于其定义。如果在任何函数之外定义对象,则该对象具有静态存储持续时间,这意味着该对象存在于整个程序执行过程中。如果在没有_Thread_localstatic的函数中定义它具有自动存储持续时间,则意味着它存在直到其相关代码块的执行结束为​​止。 C实现绝大多数将堆栈用于具有自动存储期限的对象(忽略了优化经常不需要使用堆栈这一事实),但是可以选择。

  

另一方面,当我们想使用内存堆时,我们使用malloc,但是我发现您可以初始化一个char指针并在同一条声明行上为其分配一个字符串,所以我有一些有关此问题的问题:

     

1)如果我只是初始化一个char指针并为其分配一个字符串,那么此信息在哪里?在堆里?在堆栈中?例如:char * pointer =“ Hello world”;

对于字符串文字"Hello world",C实现会创建一个具有静态存储持续时间的字符数组,就像您在文件范围内写入char MyString[12];int x;一样。假设此数组未通过优化消除或更改,则C实现是在内存的某些常规区域中用于程序中内置的数据(可能是“ .rodata”或类似的只读部分)。

然后,对于char *pointer,C实现创建一个指针。如果此定义出现在函数之外,则它具有静态存储持续时间,并且C实现为此使用一些常规的内存区域。如果它出现在函数内部,则它具有自动存储时间,并且C实现可能为此使用堆栈空间。

然后,对于= "Hello world",C实现使用该数组初始化pointer。为此,它将数组转换为指向其第一个元素的指针,并将该指针用作pointer的初始值。

  

2)我尝试使用malloc初始化我的char指针,并在以后使用它为它分配一个字符串,但是我无法编译它,但出现错误,此逻辑有什么问题?这就是我想要做的:

     

char *pointer = malloc(sizeof(char) * 12);

     

*pointer = "Hello world";

第二行是错误的,因为*pointer在声明中的作用与在表达式语句中的作用不同。

char *pointer = …;中,*pointer呈现了应该是char的“图片”。这就是声明在C中的工作方式。它说*pointerchar,因此pointer是指向char的指针。但是,要定义和初始化的事物不是*pointer,而是pointer

相反,在*pointer = "Hello world";中,*pointer是一个表达式。它使用指针pointer并将*运算符应用于它。由于pointer是指向char的指针,因此*pointerchar。然后*pointer = "Hello world";尝试将"Hello world"分配给char。这是一个错误,因为"Hello world"不是char

您要执行的操作是将指向"Hello world"的指针分配给pointer。 (更正确地说,是指向"Hello world"的第一个字符的指针。)为此,请使用:

pointer = "Hello world";