malloc数组字符动态vs静态C

时间:2015-09-15 20:17:48

标签: c char malloc

所以我基本上尝试输入字母scanf(它们之间没有间距),将每个字母放入一个数组中,并使用动态分配的数组(malloc)将相应的字母吐出到数组中。

崩溃

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

int main () {

    char *userInput = malloc(sizeof(char)*3); /* dynamic */
    scanf("%s", &userInput);
    printf("user inputed %c", userInput[1]);
    free(userInput);

    return 0;
}

奔跑

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

int main () {

    char userInput [3];  /* array */
    scanf("%s", &userInput);
    printf("user inputed %c", userInput[1]);

    return 0;
}

输入: ASD

输出: 小号

我对动态分配数组的理解是char userInput [3];等同于char *userInput = malloc(sizeof(char)*3);,但显然从这种情况来看并非如此?有人在乎解释/帮助吗?

2 个答案:

答案 0 :(得分:2)

欢迎使用Stack Overflow!巧合的是,您的代码的主要问题是它容易受到堆栈溢出的影响。 scanf无法知道userInput有多大,因为你没有告诉它,并且很乐意在你的非常短的数组结束后继续填充内存。

如果要准确捕获三个字符(没有nul终止符),请改用scanf("%3c", userInput)。请注意,如果没有NUL,您不能期望将userInput视为字符串;例如,通过printf打印它会导致随机数量的乱码,因为C不知道字符串的结束位置。

现在,回答你关于“malloc和静态数组之间有什么区别”的实际问题:区别在于范围。如果你在创建函数userInput之前只使用return,那么没有实际的区别,但是当你尝试做这样的事情时你会遇到麻烦:

int function1 {
     char my_string[3];

     scanf("%3c", my_string);

     return my_string; /* WRONG! DANGER! */
}

上例中的return将愉快地将指针my_string返回给调用函数。但是,只要function1返回,堆栈就会回滚,占用的内存my_string基本消失(并且可能已经重新使用)。结果是不可预测的,但几乎普遍对你的程序非常不利。

但是,如果您使用malloc(),则可以安全地返回my_string指针,内存将持续存在,直到有人后来调用free(my_string)(其中my_string为指针到原来的my_string;它不需要命名相同!)。

这突出了另一个区别:使用诸如char my_string[3];之类的堆栈变量,你不需要担心(实际上不能)free()内存,就好像内存是{{1}一样相反,如果你想收回内存,你必须 malloc()

上面有一些细微差别,例如文件范围的变量和free()函数变量,我将其留作主题以供进一步阅读。

答案 1 :(得分:1)

正如Giorgi的answer所指出的,主要问题是地址 - 运算符&的使用不正确。

然而,为什么它在一个案例中运作的原因以及它为什么不在另一个案例上工作的原因非常有趣

  1. char array[3]:声明该数组时,将为其分配内存空间,array将成为该位置的标签(内存地址)。当您将array传递给scanf(或在其他地方使用而无需订阅[])时,您就会将地址传递给该功能。因此,当您在标签&上使用array运算符时,会向您返回相同的地址,但不同的类型T(*)[3]),您的编译器可能抱怨。但是,由于内存地址有效,它按预期工作。

  2. char *array = malloc():当你声明那个变量时,内存也是为它保留的,但这次是在另一个地方而且保留的空间是sizeof T(*),所以它可以保存一个内存地址。此变量在内存中也有一个地址,您也可以使用&array获取该地址。然后你malloc一些内存,malloc返回一个你现在可以使用的内存块的地址。只需执行array即可获得该内存地址。因此,当您使用scanf 致电&array时,您正在传递变量地址而不是阻止地址。这就是它崩溃的原因(我猜你没有输入两个字符)。

  3. 检查此代码:

    #include <stdio.h>
    #include <stdio.h>
    
    int main(void)
    {
        char *array[3];
        char *ptr = malloc(3 * sizeof(char));
    
        printf ("array : %p\n", array);
        printf ("&array: %p\n\n", &array);
        printf ("ptr   : %p\n", ptr);
        printf ("&ptr  : %p\n", &ptr);
    
        scanf("%s", &ptr);
    
        printf ("ptr   : %p\n", ptr);
    
        return 0;
    }
    

    哪个输出:

    $ ./draft
    array : 0x7ffe2ad05ca0
    &array: 0x7ffe2ad05ca0
    
    ptr   : 0x19a4010
    &ptr  : 0x7ffe2ad05c98
    ABCD
    ptr   : 0x44434241
    

    scanf获取了指针的地址,因此当它保存从stdin读取的值时,它会覆盖我们从malloc获取的地址!我们的内存块现在已经消失,内存正在泄漏......现在,这很糟糕,因为我们正在覆盖堆栈中的内容,内存泄漏,并且会崩溃。

    观察最后一个输出:ptr(以前是已分配块的地址)的值现在是0x44434241(DCBAASCII Table)!

    有多好