我正在尝试将包含条形符号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
函数的实例会弹出带有汇编代码的窗口。我也使用过gdb,但是它不起作用:
56个字符target =(char)calloc(length,sizeof(char));
(gdb)n警告:检测到严重错误c0000374
线程1收到信号SIGTRAP,跟踪/断点陷阱。
0x00007ffded8191f3 in ?? ()
((gdb)bt
#0 0x00007ffded8191f3 in ?? ()
回溯停止:前一帧与此帧相同(损坏的堆栈?)
((gdb)继续
继续。
gdb:未知目标异常0xc0000374,位于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
内存使用/错误检查
在您编写的任何可动态分配内存的代码中,对于任何已分配的内存块,您都有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)
始终确认已释放已分配的所有内存,并且没有内存错误。仔细检查,如果还有其他问题,请告诉我。