(编辑)索引没问题。几个注意事项: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) 当不再需要它时可以释放。
您必须使用内存错误检查程序来确保您不会尝试访问内存或写入超出/超出分配块的边界,尝试读取或基于未初始化的值进行条件跳转,最后,以确认您释放了已分配的所有内存。
对于 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)
始终确认您已释放已分配的所有内存并且没有内存错误。
检查一下,如果您还有其他问题,请告诉我。