我的C代码出了问题。
int split(char* source, char*** target, char* splitChar) {
int i;
int currentLength;
int splitCharPosition;
char* currentSubstring = source;
int splitCount = charcount(source, splitChar) + 1;
*target = (char**) malloc(splitCount * sizeof(char**));
for(i=0;i<splitCount;i++) {
splitCharPosition = indexOf(currentSubstring, splitChar);
substring(currentSubstring, target[i], 0, splitCharPosition);
currentLength = strlen(currentSubstring);
substring(currentSubstring, ¤tSubstring, splitCharPosition + 1, curr entLength-splitCharPosition);
}
return splitCount;
}
问题是如果我使用调试器,在第一次运行for循环后,指向splitChar的指针将设置为0x0。 有人知道它为什么设置为0x0?
编辑:
int indexOf(char* source, char* template) {
int i;
int j;
int index;
for (i = 0; source[i]; i++) {
index = i;
for (j = 0; template[j]; j++) {
if (source[i + j] != template[j]) {
index = -1;
break;
}
}
if (index != -1) {
return index;
}
}
return -1;
}
EDIT2:
int charcount(char* source, const char* countChar) {
int i;
int count = 0;
for(i=0;source[i];i++) {
if(source[i] == countChar[0]) {
count++;
}
}
return count;
}
EDIT3:
char* substring(char* source, char** target, int start, int length) {
*target = (char*) malloc(length + 1);
strncpy(*target, source + start, length);
target[length] = '\0';
return *target;
}
EDIT4: 我刚注意到,如果我添加
char* sndfpgjps = splitChar;
到我的split()代码,它不会删除引用。谁知道为什么?
答案 0 :(得分:3)
这一行: -
substring(currentSubstring, ¤tSubstring, splitCharPosition + 1, curr entLength-splitCharPosition);
...会导致内存泄漏,并且效率极低。旧的子串留下悬空。并且永远不会被释放。
写
会好得多currentSubString += splitCharPosition + 1;
我不认为这是 问题,但它是 问题。
另外,当您使用strlen()
等C库函数时,为什么不使用strtok
或更好,strtok_r
?
答案 1 :(得分:2)
我对代码有一些保留意见,但这在valgrind
下干净利落(没有泄漏,没有滥用)。除了常量字符串标记为常量之外,我已经将子函数基本保持不变。 split()
中的代码已经过简化。正如我在评论中提到的,我建议编写主split()
函数,以便您拥有一个分配和填充的本地char **string_list;
。然后,当您即将返回时,指定*target = string_list;
。这将使您更容易理解正在发生的事情。三重间接是令人讨厌的。你可以在这里证明它(只是),但是最大限度地减少你使用三指针的时间。修订采用了这一策略。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
extern int split(const char *source, char ***target, const char *splitStr);
static int
indexOf(const char *source, const char *template)
{
int i;
int j;
int index;
for (i = 0; source[i]; i++)
{
index = i;
for (j = 0; template[j]; j++)
{
if (source[i + j] != template[j])
{
index = -1;
break;
}
}
if (index != -1)
return index;
}
return -1;
}
static int
charcount(const char *source, const char *countChar)
{
int count = 0;
for (int i = 0; source[i]; i++)
{
if (source[i] == countChar[0])
count++;
}
return count;
}
static char *
substring(const char *source, int start, int length)
{
char *target = (char *)malloc(length + 1);
if (target != 0)
{
memmove(target, source + start, length);
target[length] = '\0';
}
return target;
}
int
split(const char *source, char ***target, const char *splitStr)
{
int splitCount = charcount(source, splitStr) + 1;
char **result = (char **)malloc(splitCount * sizeof(*result));
if (result == 0)
return -1;
int splitLength = strlen(splitStr);
char **next = result;
const char *currentSubstring = source;
for (int i = 0; i < splitCount; i++)
{
int splitCharPosition = indexOf(currentSubstring, splitStr);
if (splitCharPosition < 0)
break;
*next++ = substring(currentSubstring, 0, splitCharPosition);
currentSubstring += splitCharPosition + splitLength;
}
*next++ = substring(currentSubstring, 0, strlen(currentSubstring));
*target = result;
return (next - result); /* Actual number of strings */
}
static void print_list(int nstrings, char **strings)
{
for (int i = 0; i < nstrings; i++)
{
if (strings[i] != 0)
printf("%d: <<%s>>\n", i, strings[i]);
}
}
static void free_list(int nstrings, char **strings)
{
for (int i = 0; i < nstrings; i++)
free(strings[i]);
free(strings);
}
int main(void)
{
const char source[] = "This is a string; it is really!";
char **strings;
int nstrings;
nstrings = split(source, &strings, " ");
printf("Splitting: <<%s>> on <<%s>>\n", source, " ");
print_list(nstrings, strings);
free_list(nstrings, strings);
nstrings = split(source, &strings, "is");
printf("Splitting: <<%s>> on <<%s>>\n", source, "is");
print_list(nstrings, strings);
free_list(nstrings, strings);
return 0;
}
请注意,在第二个示例中,charcount()
返回6,但只有4个字符串。这导致对源代码的后期调整。 (你可以realloc()
result
所以这是正确的大小,但它可能不值得担心除非差异真的被标记 - 比如'超过10个条目'。)错误处理并不完美;它在分配失败后不会访问无效内存,但它也不会停止尝试分配。它也没有报告分配单个字符串的失败 - 它无法分配指针数组。
我可能会通过创建一个结构来避免三重指针:
typedef struct StringList
{
size_t nstrings;
char **strings;
} StringList;
然后,您可以将指向其中一个的指针传递到split()
,并传递到实用程序功能,例如free_list()
和print_list()
。然后free_list()
函数将修改结构,以便在释放结构指向的数据后将两个元素归零。
我也很想使用indexOf()
的不同实现:
int indexOf(const char *haystack, const char *needle)
{
const char *pos = strstr(haystack, needle);
if (pos != 0)
return (pos - haystack);
return -1;
}
答案 2 :(得分:1)
我不知道子串是做什么的,也不知道它有什么签名,但是在行
中substring(currentSubstring, target[i], 0, splitCharPosition);
target [i]仅针对i == 0定义。我相信你想写
substring(currentSubstring, (*target)[i], 0, splitCharPosition);
答案 3 :(得分:0)
查看您的调试器是否也支持数据断点,即如果修改了内存中的某个位置则中断。然后将一个放在splitChar的实际地址,另一个放在它指向的地址。 (因为您没有指定指针是否为null或指向nil。)查看它的中断位置。它可能是一个完全无关的地方;这表示缓冲区溢出。
另外,你至少可以使用splitChar指向const的指针。你真的不想修改它,对吗?更好的想法,使它成为一个字符,而不是一个指针,因为它的名字表明只有一个字符可以拆分,而不是字符串。
答案 4 :(得分:0)
对substring
的第一次调用看起来不正确:
substring(currentSubstring, target[i], 0, splitCharPosition);
我怀疑它应该像下面那样索引分配的实际内存:
substring(currentSubstring, &((*target)[i]), 0, splitCharPosition);
首先需要获取目标指向(*target
)的值,然后将其索引并传递该阵列位置的地址。