11

我是一个 C 新手,我来自 C#。我一直在学习内存管理和malloc()功能。我也遇到过这段代码:

char *a_persons_name = malloc(sizeof(char) + 2);

我不明白这是分配了多少空间a_persons_name。它是分配2个字符(例如AB)还是其他?

我也知道您有时可以“幸运”malloc并使用未分配的空间(这可能导致数据损坏和段错误)。那么我怎么知道我分配了多少空间以及我需要多少空间呢?

4

6 回答 6

18

该片段为 2 个字符的名称分配了足够的空间。

通常,字符串缓冲区将从某处被填充,即 I/O。如果事先不知道字符串的大小(例如从文件或键盘读取),通常使用以下三种方法之一:

  • 为任何给定字符串定义最大大小,分配该大小 + 1(用于空终止符),最多读取那么多字符,如果提供了太多字符,则错误或盲目截断。不是非常用户友好。

  • 分阶段重新分配(最好使用几何级数,例如加倍,以避免二次行为),并继续阅读直到到达终点。不是很容易编码。

  • 分配一个固定大小并希望它不会被超过,并且当这个假设失败时会可怕地崩溃(或被拥有)。易于编码,易于破解。例如,参见gets标准 C 库。(切勿使用此功能。

于 2009-08-08T04:28:51.560 回答
5

好吧,首先,sizeof(char)总是 1,所以你可以只是malloc(3).

您在其中分配的空间足以容纳三个字符。但请记住,您需要一个用于 C 字符串的空终止符。

您往往会找到如下内容:

#define NAME_SZ 30
: : :
char *name = malloc (NAME_SZ+1);

为名称和终止符获得足够的存储空间(请记住,字符串“xyzzy”在内存中存储为:

+---+---+---+---+---+----+
| x | y | z | z | y | \0 |
+---+---+---+---+---+----+

有时使用非基于字符的数组,您会看到:

int *intArray = malloc (sizeof (int) * 22);

这将为 22 个整数分配足够的空间。

于 2009-08-08T04:28:59.843 回答
3

malloc()如果成功,将分配一块内存并返回指向该内存的指针,如果不成功,则返回 NULL。内存块的大小由malloc's 参数指定,以字节为单位。

运算符以字节为sizeof单位给出其参数的大小。

char *someString = malloc(sizeof(char) * 50)

这将为不包括 NULL 字符的 49 个字符的字符串(C 风格的字符串必须以 NULL ( '\0') 字符终止)分配足够的空间,并指向someString该内存。

看起来您问题中的代码应该是malloc(sizeof(char) * 2);,因为sizeof(char) + 2没有意义。

请注意,sizeof(char)它保证始终等于 1(字节)——但其他类型(如 long)的内存表示可能因编译器而异。

使用动态分配的内存获得(不)幸运的方式是,如果您尝试在分配的内存之外读/写。

例如,

char *someString = malloc(10);
strcpy(someString, "Hello there, world!");
printf("%s\n", someString);

第一行为 9 个字符和一个 NULL 字符分配了足够的空间。
第二行尝试将 20 个字符(19 + NULL)复制到该内存空间中。这会超出缓冲区,并可能导致一些非常机智的事情,例如覆盖相邻的内存或导致段错误。

第三行可能会起作用,例如,如果在 someString 旁边分配了内存,并且“你好,世界!” 跑进那个内存空间,它可能会打印你的字符串加上下一个内存空间中的任何内容。如果第二个空格是 NULL 终止的,它就会停止——除非它不是,在这种情况下它会漂移并最终出现段错误。

这个例子是一个非常简单的操作,但它很容易出错。C 很棘手——要小心。

于 2009-08-08T04:48:32.050 回答
1

第一点 - 永远不要将绝对数字放在 malloc 的参数中,始终使用 sizeof 和倍数是一个好习惯。如上所述,为某些类型分配的内存因编译器和平台而异。为了保证为“blob”类型的数组提供足够的空间,最好使用以下内容:

blob *p_data = malloc(sizeof(blob) * length_of_array);

这样,无论类型是什么,无论它在内存中看起来如何,您都会得到完全正确的数量。

其次,段错误等。C作为一种低级语言,没有边界检查。这意味着没有什么可以检查您正在查看的索引实际上不在数组中。实际上,即使它不属于您的程序,它也不会阻止您在任何地方访问内存(尽管您的操作系统可能,这就是段错误)。这就是为什么每当你在 C 中传递一个数组时,你也需要传递它的长度,以便接收数组的函数知道它有多大。不要忘记“数组”实际上只是指向第一个元素的指针。这在传递字符串时非常无用 - 每个字符串参数都会变成两个参数,因此使用了作弊。任何标准 C 字符串都以 NULL 结尾。字符串中的最后一个字符应为 ASCII 值 0。任何字符串函数都沿着数组工作,直到他们看到然后停止。这样他们就不会超出阵列,但如果由于某种原因它不存在,他们会。那个被理解

strlen("Hello")

是 5,但要存储它,您还需要一个字符。例如:

const char str1 = "Hello";
char *str2 = malloc(sizeof(char) * (strlen(str1) + 1));
strcpy(str2, str1);

是的,sizeof(char) 是不必要的,因为它被定义为 1,但我发现它更清晰,这绝对是一个好习惯。

于 2009-08-08T12:41:16.867 回答
1

您的调用malloc将分配 3 个字节的内存。sizeof(char)是 1 个字节,2 个字节被明确指出。这为您提供了足够的空间来容纳大小为 2 的字符串(以及终止字符)

于 2009-08-08T04:28:31.203 回答
1

这将分配三个字节;1 表示 sizeof(char),再加上 2。只是断章取义地看到那条线,我无法知道为什么它会以这种方式分配,或者它是否正确(对我来说看起来很可疑)。

您需要分配足够的内存来容纳您需要放入其中的任何内容。例如,如果您要分配内存来保存字符串,则需要分配足够的内存来保存预期的最长字符串以及一个用于终止 null 的字节。如果您正在处理 ASCII 字符串,这很简单:每个字符一个字节加一个。如果您使用的是 unicode 字符串,事情会变得更加复杂。

于 2009-08-08T04:31:10.743 回答