如何在 C 中为字符串数组动态分配内存?
How do I dynamically allocate memory for an array of strings in C?
我阅读了前面关于 C 中动态数组的问题,但是我无法将答案与我的问题联系起来。
我正在使用 fgets 从 stdin
获取命令,删除换行符,然后想将每个由 space 分隔的命令存储在动态分配的字符串数组中。然而,我在分配和重新分配内存的正确方法上遇到了很多麻烦。我正在使用 clang
进行编译并不断收到分段错误 11。然后我使用 -fsanitize=address
并不断收到:
==2286==ERROR: AddressSanitizer: heap-buffer-overflow on address
0x60200000eeb8 at pc 0x000108fb6f85 bp 0x7fff56c49560 sp 0x7fff56c49558
WRITE of size 8 at 0x60200000eeb8 thread T0
这是我的代码:
// Sets a delimiter to split the input
const char *seperator = " ";
char *token = strtok(line, seperator);
char **cmds = (char **) malloc(sizeof(char) * sizeof(*cmds));
// Adds first token to array of delimited commands
cmds[0] = token;
int count = 1;
while (token != NULL) {
token = strtok(NULL, sep);
if (token != NULL) {
cmds = (char **) realloc(cmds, sizeof(char) * (count + 1));
// Adds next token array of delimited commands
cmds[count] = token;
count++;
}
}
您没有分配足够的内存。 cmds
是一个指针数组,所以每个元素是 sizeof(char *)
字节,而不是 sizeof(char)
字节。
在初始分配中,您需要 1 char *
,然后在后续分配中,您需要 count + 1
。
此外,don't cast the return value of malloc
,因为这可以隐藏其他问题,并且不要忘记检查故障。
char **cmds = malloc(sizeof(char *) * 1);
if (cmds == NULL) {
perror("malloc failed");
exit(1);
}
...
cmds = realloc(cmds, sizeof(char *) * (count + 1));
if (cmds == NULL) {
perror("reallocfailed");
exit(1);
}
首先,根据定义,sizeof(char)
始终为 1。编码并不能使您的代码更具可读性。
但是指向 char
的指针需要 sizeof(char*)
字节(取决于机器 & ABI, that is often 8 or 4 bytes). I would at least suggest to compile your code with gcc -Wall -Wextra -g
if using GCC。
最后,我发现你的代码有点低效。您在每个循环中都调用 realloc
。我会维护一个包含分配大小的变量
int allocsize = 4; // allocated size in number of elements
char **cmds = malloc(allocsize*sizeof(char*));
if (!cmds) { perror("malloc"); exit(EXIT_FAILURE); };
(顺便说一句,总是检查 malloc
的结果;它可以 失败)。
并且为了避免每次 realloc
-ing,我会以几何方式增加分配的大小,所以在循环内:
if (count>=allocsize) {
int newallocsize = (4*allocsize)/3+10;
cmds = realloc (cmds, newallocsize*sizeof(char*));
if (!cmds) { perror("realloc"); exit(EXIT_FAILURE); };
allocsize = newallocsize;
}
或者,您可以使用以 flexible array member 结尾的单个 struct
(和保持其分配和使用的大小)。
- 第一个 malloc 是错误的。当您在分配 cmd 之前通过 *cmd 取消引用它时,您会得到什么?
- 它也使用了sizeof(char),这是错误的..
正确的方法是..
// strtok modifies the string. So use writable string
char line[80] = "Hello my name is anand";
char *token = strtok(line, sep);
int count = 0;
// Alloc array of char* for total number of tokens we have right now
char **cmds = (char **) malloc(sizeof(char*) * (count + 1));
while (token != NULL)
{
/**
* Alloc memory for the actual token to be stored..
* token returned by strtok is just reference to the existing string
* in 'line'
*/
cmds[count] = malloc(sizeof(char) * ((strlen(token) + 1)));
// Adds tokens to array of delimited commands
strcpy(cmds[count], token);
count++;
token = strtok(NULL, sep);
if (token != NULL)
{
// resize array of tokens to store an extra token
char ** newCmds = (char **) realloc(cmds, sizeof(char*) * (count + 1));
// only if realloc was successful then use it.
if (newCmds != NULL)
{
cmds = newCmds;
}
}
}
我阅读了前面关于 C 中动态数组的问题,但是我无法将答案与我的问题联系起来。
我正在使用 fgets 从 stdin
获取命令,删除换行符,然后想将每个由 space 分隔的命令存储在动态分配的字符串数组中。然而,我在分配和重新分配内存的正确方法上遇到了很多麻烦。我正在使用 clang
进行编译并不断收到分段错误 11。然后我使用 -fsanitize=address
并不断收到:
==2286==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60200000eeb8 at pc 0x000108fb6f85 bp 0x7fff56c49560 sp 0x7fff56c49558 WRITE of size 8 at 0x60200000eeb8 thread T0
这是我的代码:
// Sets a delimiter to split the input
const char *seperator = " ";
char *token = strtok(line, seperator);
char **cmds = (char **) malloc(sizeof(char) * sizeof(*cmds));
// Adds first token to array of delimited commands
cmds[0] = token;
int count = 1;
while (token != NULL) {
token = strtok(NULL, sep);
if (token != NULL) {
cmds = (char **) realloc(cmds, sizeof(char) * (count + 1));
// Adds next token array of delimited commands
cmds[count] = token;
count++;
}
}
您没有分配足够的内存。 cmds
是一个指针数组,所以每个元素是 sizeof(char *)
字节,而不是 sizeof(char)
字节。
在初始分配中,您需要 1 char *
,然后在后续分配中,您需要 count + 1
。
此外,don't cast the return value of malloc
,因为这可以隐藏其他问题,并且不要忘记检查故障。
char **cmds = malloc(sizeof(char *) * 1);
if (cmds == NULL) {
perror("malloc failed");
exit(1);
}
...
cmds = realloc(cmds, sizeof(char *) * (count + 1));
if (cmds == NULL) {
perror("reallocfailed");
exit(1);
}
首先,根据定义,sizeof(char)
始终为 1。编码并不能使您的代码更具可读性。
但是指向 char
的指针需要 sizeof(char*)
字节(取决于机器 & ABI, that is often 8 or 4 bytes). I would at least suggest to compile your code with gcc -Wall -Wextra -g
if using GCC。
最后,我发现你的代码有点低效。您在每个循环中都调用 realloc
。我会维护一个包含分配大小的变量
int allocsize = 4; // allocated size in number of elements
char **cmds = malloc(allocsize*sizeof(char*));
if (!cmds) { perror("malloc"); exit(EXIT_FAILURE); };
(顺便说一句,总是检查 malloc
的结果;它可以 失败)。
并且为了避免每次 realloc
-ing,我会以几何方式增加分配的大小,所以在循环内:
if (count>=allocsize) {
int newallocsize = (4*allocsize)/3+10;
cmds = realloc (cmds, newallocsize*sizeof(char*));
if (!cmds) { perror("realloc"); exit(EXIT_FAILURE); };
allocsize = newallocsize;
}
或者,您可以使用以 flexible array member 结尾的单个 struct
(和保持其分配和使用的大小)。
- 第一个 malloc 是错误的。当您在分配 cmd 之前通过 *cmd 取消引用它时,您会得到什么?
- 它也使用了sizeof(char),这是错误的..
正确的方法是..
// strtok modifies the string. So use writable string
char line[80] = "Hello my name is anand";
char *token = strtok(line, sep);
int count = 0;
// Alloc array of char* for total number of tokens we have right now
char **cmds = (char **) malloc(sizeof(char*) * (count + 1));
while (token != NULL)
{
/**
* Alloc memory for the actual token to be stored..
* token returned by strtok is just reference to the existing string
* in 'line'
*/
cmds[count] = malloc(sizeof(char) * ((strlen(token) + 1)));
// Adds tokens to array of delimited commands
strcpy(cmds[count], token);
count++;
token = strtok(NULL, sep);
if (token != NULL)
{
// resize array of tokens to store an extra token
char ** newCmds = (char **) realloc(cmds, sizeof(char*) * (count + 1));
// only if realloc was successful then use it.
if (newCmds != NULL)
{
cmds = newCmds;
}
}
}