4

我的 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, &currentSubstring, 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;
}

编辑2:

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;
}

编辑3:

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() 代码,它不会删除引用。有谁知道为什么?

4

5 回答 5

3

这一行: -

    substring(currentSubstring, &currentSubstring, splitCharPosition + 1, curr  entLength-splitCharPosition);

...将导致内存泄漏,并且效率极低。旧的子字符串悬空。并且从未被释放。

写会好很多

currentSubString += splitCharPosition + 1;

我不认为这是问题,但这是一个问题。

此外,当您使用 C 库函数strlen()时,为什么不使用strtok或更好呢strtok_r

于 2013-04-16T16:30:10.840 回答
2

我对代码有一些保留,但这在valgrind(没有泄漏,没有滥用)下可以正常工作。除了常量字符串被标记为常量外,我基本上没有改变子函数。中的代码split()已被简化。正如我在评论中指出的那样,我建议编写 mainsplit()函数,以便您拥有一个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()and 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;
}
于 2013-04-16T18:09:39.267 回答
1

我不知道 substring 做了什么,也不知道它有什么签名,但在行

substring(currentSubstring, target[i], 0, splitCharPosition);

target[i] 只为 i==0 定义。我相信你想写

substring(currentSubstring, (*target)[i], 0, splitCharPosition);
于 2013-04-16T15:40:29.707 回答
0

查看您的调试器是否还支持数据断点,即如果修改了内存中的某个位置,则中断。然后将一个放在 splitChar 的实际地址,另一个放在它指向的地址。(因为您没有指定指针是 null 还是指向 nil。)看看它在哪里中断。可能是一个完全不相关的地方;这将表明缓冲区溢出。

此外,您至少可以将 splitChar 设为指向 const 的指针。您实际上并不想修改它,对吗?更好的主意,让它成为一个字符,而不是一个指针,因为它的名字暗示你只有一个字符可以分割,而不是一个字符串。

于 2013-04-16T15:30:50.177 回答
0

第一次调用substring看起来不正确:

substring(currentSubstring, target[i], 0, splitCharPosition);

我怀疑它应该像下面这样索引分配的实际内存:

substring(currentSubstring, &((*target)[i]), 0, splitCharPosition);

您首先需要获取目标指向 ( *target) 的值,然后从中索引并传递该数组位置的地址。

于 2013-04-16T15:39:57.280 回答