动态分配不在循环中工作

问题描述 投票:0回答:1

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

我正在尝试使用sscanf()函数执行此[[无。

示例:如果str"abc|def||jk",则这是最后output的样子(出于演示目的,少于20个元素):

output [0] ==“ abc”

output [1] ==“ def”

output [2] ==“”

output [3] ==“ jk”

但是,我总是收到错误退出代码,类似:

处理完成,退出代码为-1073740940(0xC0000374)

[调试时,我发现第一个字符串元素已正确解析为output,但有时会正确生成第二个元素,而其他时候我遇到了麻烦。

下面的代码:

// there will be 20 arrays, each string inside won't have length longer than 19 char char **output = (char**) calloc(20, 20*sizeof(char)); //inclusive int begin = 0; //exclusive int end = 1; // count which string in output is currently constructed in loop 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))) { // if i is end of string then increase by 1 so the last char is included end = endOfString ? (end+1):end; // target is the segment of str that will become an element of output // ---------------------------- // 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个字符

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

(gdb)n

警告:检测到严重错误c0000374

线程1收到信号SIGTRAP,跟踪/断点陷阱。

0x00007ffded8191f3 in ?? ()

((gdb)bt

#0 0x00007ffded8191f3 in ?? ()

回溯停止:前一帧与此帧相同(损坏的堆栈?)

((gdb)继续

继续。

gdb:未知目标异常0xc0000374,位于0x7ffded819269,

c loops debugging dynamic-memory-allocation string-parsing
1个回答
0
投票
(编辑)索引还可以。注意事项: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

内存使用/错误检查

在您编写的任何可动态分配内存的代码中,对于任何已分配的内存块,您都有2个

职责:(1)始终保留指向起始地址的指针,因此,( 2)当不再需要它时,可以将其freed

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

对于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)

始终确认已释放已分配的所有内存,并且没有内存错误。

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

© www.soinside.com 2019 - 2024. All rights reserved.