gpt4 book ai didi

c - char数组的内存分配

转载 作者:行者123 更新时间:2023-12-04 16:23:03 29 4
gpt4 key购买 nike

对于字符串,char *或其他内容,我对C语言有很大的疑问。因此,在这种特殊情况下,我遇到了很大的问题。我想创建一个字符数组,但还不知道它将是多大。我想写这样的东西:

char test[];

但是,在那之后,当我知道将要有多少个元素时,我想编写如下代码:
char test[num_of_elements];

尽管我知道这是错误的,但我无法做到这一点。那么,我该怎么做呢?如何声明数组,然后定义其大小?

最佳答案

声明静态字符数组(字符串)

当您知道(或有一个合理的想法,需要将数组的大小)时,只需声明一个足够大的数组即​​可处理您的输入(即,如果名称不超过25个字符,则可以安全地声明name[26]。字符串,您始终需要至少为number of chars to store + 1(对于以空字符结尾的字符)。

如果可能有几个字符超过25个,则声明数组长度比所需的字节数长就可以防止在数组末尾意外写入,这没什么不对。说name[32]

让我们在下面声明一个5-characters数组,并查看信息如何存储在内存中。

char name[5] = {0}; /* always initialize your arrays */

上面的声明在堆栈上创建了一个 5-contiguous bytes数组供您使用。例如,您可以可视化初始化为零的5字节内存,如下所示:
        +---+---+---+---+---+
name | 0 | 0 | 0 | 0 | 0 |
+---+---+---+---+---+
\
'name' holds the starting address for
the block of memory that is the array
(i.e. the address of the first element
like: 0x7fff050bf3d0)

注意:使用name保留“字符字符串”时,实际字符串不能超过 4 字符,因为您 必须结尾的字符串结尾为终止符为,即空字符'\0'(或仅是数字0,两者都是等效的)

要将信息存储在name中,可以通过一次分配字符 来做到这一点:
name[0] = 'J';
name[1] = 'o';
name[2] = 'h';
name[3] = 'n';
name[4] = 0; /* null-terminate. note: this was already done by initialization */

在内存中,您现在拥有:
        +---+---+---+---+---+
name | J | o | h | n | 0 | /* you actually have the ASCII value for */
+---+---+---+---+---+ /* each letter stored in the elements */

当然,没有人一次以这种方式分配一个字符。您可以使用C提供的功能之一来进行多种选择,例如strcpystrncpymemcpy,或者通过从文件流中读取信息,或者通过使用fgetsgetline的文件描述符读取信息,或者使用简单的loopindex variable进行分配,或者使用一种字符串格式化功能,例如sprintf等。例如,您可以使用以下任一方法完成相同的操作:
/* direct copy */
strcpy (name, "John");
strncpy (name, "John", 5);
memcpy (name, "John", sizeof "John"); /* include copy of the terminating char */

/* read from stdin into name */
printf ("Please enter a name (4 char max): ");
scanf ("%[^\n]%*c", name);

注意:如果使用 NOT 将所有元素初始化为strncpy(最后一个将用作0字符,然后使用null-terminating,则需要手动终止,否则将字符串与strncpy (name, "John", 4);一起终止)将没有有效的字符串(如果您在需要字符串的地方使用name[4] = 0;,则将有一个不终止的char数组,这将导致undefined behavior。)

如果您没有明确理解 STOP ,请阅读并理解name是什么,以及它与null-terminated string的不同之处。认真地说,现在就停止学习吧,这是C语言的基础。(如果它不以array of characters字符结尾-它不是c字符串。

如果我不知道需要存储多少个字符怎么办?

字符串的动态分配

当您不知道需要存储多少个字符(或者通常是多少个数据类型)时,通常的方法是声明一个指向类型的指针,然后分配合理预期的内存量(基于(最好是了解您要处理的内容),然后重新分配以根据需要添加额外的内存。它没有魔术,只是告诉编译器如何管理内存的另一种方式。只要记住,当您分配内存时,您便拥有了它。您有责任(1)保留一个指向存储块起始地址的指针(以便以后可以释放它); (2)完成操作后释放内存。

一个简单的例子会有所帮助。大多数内存分配/释放函数都在null-terminating中声明。
char *name = NULL;  /* declare a pointer, and initialize to NULL */

name = malloc (5 * sizeof *name); /* allocate a 5-byte block of memory for name */

if (!name) { /* validate memory was allocated -- every time */
fputs ("error: name allocation failed, exiting.", stderr);
exit (EXIT_FAILURE);
}

/* Now use name, just as you would the statically declared name above */
strncpy (name, "John", 5);

printf (" name contains: %s\n", name);

free (name); /* free memory when no longer needed.
(if reusing name, set 'name = NULL;')
*/

注意: stdlib.h不会初始化它分配的内存的内容。如果要用零初始化新的内存块(就像我们对静态数组所做的那样),请使用malloc而不是calloc。您还可以使用malloc,然后也调用malloc

如果我分配内存,然后需要更多内存会怎样?

如上所述,讨论动态内存时,一般方案是分配合理的预期数量,然后根据需要分配memset。您可以使用realloc重新分配由realloc创建的原始内存块。 malloc本质上会创建一个新的内存块,将内存从您的旧块复制到新的内存块,然后释放旧的内存块。由于旧的内存块已释放,因此您想使用临时指针进行重新分配。如果重新分配失败,您仍然可以使用原始的内存块。

您可以随意在对realloc的任何调用中添加尽可能少的内存。通常看到的标准方案是从一些初始分配开始,然后在每次用尽时重新分配该数量的两倍。 (这意味着您需要跟踪当前分配了多少内存)。

为了说明这一点,让我们以一个简单的示例结尾,该示例简单读取一个任意长度的字符串作为程序的第一个参数(如果您的字符串包含空格,请使用realloc引用")。然后它将分配空间来容纳字符串,然后重新分配以将更多文本附加到原始字符串的末尾。最后,它将在退出之前释放所有正在使用的内存:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main (int argc, char **argv) {

if (argc < 2) { /* validate input */
fprintf (stderr, "error: insufficient input. usage: %s \"name\"\n",
argv[0]);
return 1;
}

size_t len = strlen (argv[1]); /* length of input */
size_t sz_mem = len + 1; /* memory required */

char *name = malloc (sz_mem * sizeof *name); /* allocate memory for name */

if (!name) { /* validate memory created successfully or throw error */
fputs ("error: name allocation failed, exiting.", stderr);
return 1;
}

printf ("\n allocated %zu bytes of memory for 'name'\n", sz_mem);
memset (name, 0, sz_mem); /* initialize memory to zero (optional) */

strncpy (name, argv[1], sz_mem); /* copy the null-terminator as well */
printf (" name: '%s' (begins at address: %p)\n", name, name);

/* realloc - make name twice as big */
void *tmp = realloc (name, 2 * sz_mem); /* use a temporary pointer */
if (!tmp) { /* check realloc succeeded */
fprintf (stderr, "error: virtual memory exhausted, realloc 'name'\n");
return 1;
}
memset (tmp + sz_mem, 0, sz_mem * sizeof *name); /* zero new memory */
name = tmp; /* assign new block to name */
sz_mem += sz_mem; /* update current allocation size */

printf (" reallocated 'name' to %zu bytes\n", sz_mem);
strncat (name, " reallocated", sizeof " reallocated");

printf ("\n final name : '%s'\n\n", name);

free (name);

return 0;
}

使用/输出
$ ./bin/arraybasics "John Q. Public"

allocated 15 bytes of memory for 'name'
name: 'John Q. Public' (begins at address: 0xf17010)
reallocated 'name' to 30 bytes

final name : 'John Q. Public reallocated'

内存检查

动态分配内存时,您需要验证自己是否正确使用了内存,并跟踪并释放了所有已分配的内存。使用诸如"之类的内存错误检查器来验证您的内存使用是否正确。 (没有任何借口,这样做很简单)只需键入valgrind
$ valgrind ./bin/arraybasics "John Q. Public"
==19613== Memcheck, a memory error detector
==19613== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==19613== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==19613== Command: ./bin/arraybasics John\ Q.\ Public
==19613==

allocated 15 bytes of memory for 'name'
name: 'John Q. Public' (begins at address: 0x51e0040)
reallocated 'name' to 30 bytes

final name : 'John Q. Public reallocated'

==19613==
==19613== HEAP SUMMARY:
==19613== in use at exit: 0 bytes in 0 blocks
==19613== total heap usage: 2 allocs, 2 frees, 45 bytes allocated
==19613==
==19613== All heap blocks were freed -- no leaks are possible
==19613==
==19613== For counts of detected and suppressed errors, rerun with: -v
==19613== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)

在输出中,以下几行特别重要:
==19613== HEAP SUMMARY:
==19613== in use at exit: 0 bytes in 0 blocks
==19613== total heap usage: 2 allocs, 2 frees, 45 bytes allocated

这告诉您在程序执行期间分配的所有内存已正确释放。 (确保关闭所有打开的文件流,它们也是动态分配的)。

同样重要的是valgrind yourprogramexe:
==19613== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)

内存使用没有错误。如果您尝试从块外的位置或统一的位置读取,写入或释放内存,或者使其他内存无法访问,则该信息将显示为错误。

(被抑制的:2中的2仅与系统中不存在的其他调试库有关)

最终的结果比预期的要长,但是如果有帮助,那是值得的。祝你好运。

关于c - char数组的内存分配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32442600/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com