gpt4 book ai didi

c - 动态分配不在循环中工作

转载 作者:行者123 更新时间:2023-11-30 16:12:07 25 4
gpt4 key购买 nike

我正在尝试将包含条形符号|的字符串str分解为字符串数组(output),并使用分隔符为 |,不会包含在字符串数组中。 output 中将有 20 个元素。这段代码属于一个将返回output指针的函数,这就是我需要动态分配的原因。

我尝试使用 sscanf() 函数来执行此操作。

示例:如果 str"abc|def||jk" 那么这就是 output 最后的样子(更少超过 20 个用于演示目的的元素):

output[0]=="abc"

output[1]=="def"

output[2]==""

output[3]=="jk"

但是,我总是收到错误退出代码,例如:

Process finished with exit code -1073740940 (0xC0000374)

在调试时,我发现第一个字符串元素被正确解析为输出,但第二个元素有时会正确生成,有时我会遇到麻烦。

代码如下:

char **output = (char**) calloc(20, 20*sizeof(char));
int begin = 0;
int end = 1;
// index that counts output element
int arrayIndex = 0;
int i;
for(i = 0; i < strlen(str); i++) {
end = i;
bool endOfString = false;
// there is no '|' symbol at the end of the string
if (*(str+i) == '|' || (endOfString = (i+1)==strlen(str))) {
end = endOfString ? (end+1):end;

// problem here. Assembly code poped up when debugging (see image below)
char *target = (char*) calloc(end-begin+1, sizeof(char));

// give proper value to target
strcpy(target, str+begin);
*(target+end-begin) = '\0';
*(output+arrayIndex) = target;
// increase proper indexes
begin = i + 1;
arrayIndex++;

}
}

最糟糕的是我无法对其进行调试,因为在调试时会弹出一个包含汇编代码的窗口,其中我会跳过 calloc 函数。 Assembly code window

我也用过gdb,但是没用:

56 char target = (char) calloc(length, sizeof(char));

(gdb) n

warning: Critical error detected c0000374

Thread 1 received signal SIGTRAP, Trace/breakpoint trap.

0x00007ffded8191f3 in ?? ()

(gdb) bt

#0 0x00007ffded8191f3 in ?? ()

Backtrace stopped: previous frame identical to this frame (corrupt stack?)

(gdb) continue

Continuing.

gdb: unknown target exception 0xc0000374 at 0x7ffded819269

最佳答案

(编辑)索引编制正常。一些注意事项:sizeof(char) 始终为 1 ——只需使用 1。此外,不需要强制转换malloc的返回值,这是不必要的。请参阅:Do I cast the result of malloc? 。另外,您调用了多少次strlen(str)? (希望优化将循环条件限制为单个调用,但您可能会为每次迭代调用 strlen(str))。与 endOfString = (i+1)==strlen(str) 相同。在进入循环之前保存字符串的长度,然后使用保存的值进行比较。

虽然您可以计算索引并逐个字符循环查找分隔符,但让 strchr (pointer, '|') 前进到下一个分隔符 (或返回 NULL 表示不再保留分隔符)。然后,不必担心索引,只需保留指针 p 和结束指针 ep 来向下推进字符串,例如

#define NFIELDS 20
...
char **splitstr (const char *s, const char delim, size_t *n)
{
const char *p = s, /* pointer for parsing */
*ep = s; /* end pointer for parsing */
*n = 0; /* zero string counter */
while (*n < NFIELDS && *p) { /* loop while less than NFIELDS */
size_t len;
if ((ep = strchr (p, delim))) /* get pointer to delim */
len = ep - p;
else
len = strlen (p); /* or get length of final string */
if (!(output[*n] = malloc (len + 1))) { /* allocated for string */
...
memcpy (output[*n], p, len); /* copy chars to output[n] */
output[(*n)++][len] = 0; /* nul-terminate to make string */
if (!ep) /* if delim not found, last */
break;
p = ++ep; /* update p to 1-past delim */
}
...

添加适当的错误检查并将指针返回到分配的字符串,您可以这样做:

char **splitstr (const char *s, const char delim, size_t *n)
{
const char *p = s, /* pointer for parsing */
*ep = s; /* end pointer for parsing */
char **output = calloc (NFIELDS, sizeof *output); /* pointer to output */

if (!output) {
perror ("calloc-output");
return NULL;
}

*n = 0; /* zero string counter */
while (*n < NFIELDS && *p) { /* loop while less than NFIELDS */
size_t len;
if ((ep = strchr (p, delim))) /* get pointer to delim */
len = ep - p;
else
len = strlen (p); /* or get length of final string */
if (!(output[*n] = malloc (len + 1))) { /* allocated for string */
perror ("malloc-output[n]");
while ((*n)--) /* free prior allocations on failure */
free (output[*n]);
free(output);
return NULL;
}
memcpy (output[*n], p, len); /* copy chars to output[n] */
output[(*n)++][len] = 0; /* nul-terminate to make string */
if (!ep) /* if delim not found, last */
break;
p = ++ep; /* update p to 1-past delim */
}

return output; /* return pointer to allocated strings */
}

在您的情况下,一个完整的简短示例是:

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

#define NFIELDS 20
#define MAXC 1024

char **splitstr (const char *s, const char delim, size_t *n)
{
const char *p = s, /* pointer for parsing */
*ep = s; /* end pointer for parsing */
char **output = calloc (NFIELDS, sizeof *output); /* pointer to output */

if (!output) {
perror ("calloc-output");
return NULL;
}

*n = 0; /* zero string counter */
while (*n < NFIELDS && *p) { /* loop while less than NFIELDS */
size_t len;
if ((ep = strchr (p, delim))) /* get pointer to delim */
len = ep - p;
else
len = strlen (p); /* or get length of final string */
if (!(output[*n] = malloc (len + 1))) { /* allocated for string */
perror ("malloc-output[n]");
while ((*n)--) /* free prior allocations on failure */
free (output[*n]);
free(output);
return NULL;
}
memcpy (output[*n], p, len); /* copy chars to output[n] */
output[(*n)++][len] = 0; /* nul-terminate to make string */
if (!ep) /* if delim not found, last */
break;
p = ++ep; /* update p to 1-past delim */
}

return output; /* return pointer to allocated strings */
}

int main (void) {

char buf[MAXC], /* buffer for input */
**output = NULL; /* pointer to split/allocated strings */
size_t n = 0; /* number of strings filled */

if (!fgets (buf, MAXC, stdin)) { /* validate input */
fputs ("error: invalid input.\n", stderr);
return 1;
}
buf[strcspn (buf, "\n")] = 0; /* trim newline from buf */
/* split buf into separate strings on '|' */
if (!(output = splitstr (buf, '|', &n))) {
fputs ("error: splitstr() failed.\n", stderr);
return 1;
}

for (size_t i = 0; i < n; i++) { /* loop outputting each & free */
printf ("output[%2zu]: %s\n", i, output[i]);
free (output[i]); /* free strings */
}
free (output); /* free pointers */
}

示例使用/输出

$ echo "abc|def||jk" | ./bin/splitstr
output[ 0]: abc
output[ 1]: def
output[ 2]:
output[ 3]: jk

内存使用/错误检查

在您编写的动态分配内存的任何代码中,对于分配的任何内存块,您都有两个责任:(1) 始终保留指向起始地址的指针内存块,因此,(2) 当不再需要它时可以释放

您必须使用内存错误检查程序来确保您不会尝试访问内存或在分配的 block 的范围之外进行写入,尝试读取或基于未初始化的值进行条件跳转,最后,以确认您释放了已分配的所有内存。

对于 Linux,valgrind 是正常选择。每个平台都有类似的内存检查器。它们使用起来都很简单,只需通过它运行您的程序即可。

$ echo "abc|def||jk" | valgrind ./bin/splitstr
==32024== Memcheck, a memory error detector
==32024== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==32024== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==32024== Command: ./bin/splitstr
==32024==
output[ 0]: abc
output[ 1]: def
output[ 2]:
output[ 3]: jk
==32024==
==32024== HEAP SUMMARY:
==32024== in use at exit: 0 bytes in 0 blocks
==32024== total heap usage: 5 allocs, 5 frees, 172 bytes allocated
==32024==
==32024== All heap blocks were freed -- no leaks are possible
==32024==
==32024== For counts of detected and suppressed errors, rerun with: -v
==32024== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

始终确认您已释放分配的所有内存并且不存在内存错误。

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

关于c - 动态分配不在循环中工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58404044/

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