C 中的字符串分割函数

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

我正在尝试用 C 语言编写一个字符串分割函数,与其他高级语言中已经可用的函数非常相似。

为了避免使用标准 C 数组进行常量内存(重新)分配的麻烦,我想我可以尝试使用链表来做到这一点。这是代码:

#include <stdlib.h>
#include <string.h>

struct sList {
    char* str;
    struct sList* next;
};

int splitstr (const char* str, const char del, struct sList* subs) {
    int subs_nb = 1, i = 0, len = 0;
    char* s = str;
    struct sList* sub = subs;

    while (i < strlen(s)) {
        if (s[i] == del) {
            sub = malloc(sizeof(struct sList));
            sub->str = malloc(sizeof(char) * (len + 1));

            strncpy(sub->str, s, len);
            sub->str[len] = '\0';

            s = s+i;

            i = 0;
            len = 0;
            subs_nb++;
            sub = sub->next;
        } else {
            len++;
        }

        i++;
    }
    sub = malloc(sizeof(struct sList));
    sub->str = malloc(sizeof(char) * (strlen(s)+1));
    strcpy(sub->str, s);
    sub->next = NULL;

    return subs_nb;
}

我还编写了一个 getter 函数(我单独测试过),以便通过索引轻松访问链表的任何成员:

struct sList* sList_get(struct sList* list, int a) {
    struct sList* l = list;
    
    int i = 0;
    while(l != NULL) {
        if (i == a) return list;

        l = l->next;
        i++;
    }

    // If the program reaches this line, a is greater than the number of existing elements in the list
    return NULL;
}

最后,我尝试编写一个简单的单元测试来看看这是否按预期工作:

int main () {
    struct sList* list;

    splitstr("bla.bla.bla.bla.bla.", '.', list);

    printf("%s\n", sList_get(list, 0)->str);

    return 0;
}

预期输出是第一次出现

.
之前的子字符串:
bla

像往常一样,在处理动态内存时,我会遇到分段错误。

使用

-g
编译并通过gdb运行程序,我注意到,直到第一个
sub = malloc(...)
sub
subs
都指向相同的地址。然而,一旦到达下一条指令,
sub->str = malloc(...)
sub
突然指向不同的地址:

(gdb)
35              sub = malloc(sizeof(struct sList));
(gdb) print subs
$1 = (struct sList *) 0x555555555100 <_start>
(gdb) print sub
$2 = (struct sList *) 0x555555555100 <_start>
(gdb) n
36              sub->str = malloc(sizeof(char) * (len + 1));
(gdb) print subs
$3 = (struct sList *) 0x555555555100 <_start>
(gdb) print sub
$4 = (struct sList *) 0x5555555592a0

我认为这很可能是内存泄漏,然后我想通过 valgrind 运行它,它在每个

definitely lost
指令处报告一个
sub = malloc(...)

这里有什么问题?

c string split linked-list c-strings
1个回答
0
投票

正如@Barmar 指出的,我的内存分配顺序错误;如果我在将其设置为

sub = malloc(...)
后尝试
subs
,而不是为
subs
分配内存,它会使其变得如此
sub
现在指向由
malloc
返回的内存中完全不同的地址,无论
subs
指向什么。

我重写了代码如下,现在它可以完美地按预期工作:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct sList {

    char* str;
    struct sList* next;

};

int splitstr (const char* str, const char del, struct sList* subs);

struct sList* sList_get(struct sList* list, int a);

int main () {
    struct sList* list = malloc(sizeof(struct sList));

    splitstr("bla.bla.hahaha.bla.bLa", '.', list);

    printf("%s\n", sList_get(list, 2)->str);

    return 0;
}


int splitstr (const char* str, const char del, struct sList* subs) {
    if (subs == NULL) return -1;

    int subs_nb = 1, i = 0, len = 0;
    char* s = str;

    struct sList* sub = subs;

    while (i < strlen(s)) {
        if (s[i] == del) {
            sub->str = malloc(sizeof(char) * (len + 1));

            strncpy(sub->str, s, len);
            sub->str[len] = '\0';

            s = s+i+1;

            i = 0;
            len = 1;
            subs_nb++;
            sub->next = malloc(sizeof(struct sList));
            sub = sub->next;
        } else {
            len++;
        }

        i++;
    }
    sub->str = malloc(sizeof(char) * (strlen(s)+1));
    strcpy(sub->str, s);
    sub->next = NULL;

    return subs_nb;
}


struct sList* sList_get(struct sList* list, int a) {
    struct sList* l = list;
    
    int i = 0;
    for (int i = 0; i < a; i++) {
        if (l == NULL) return NULL;

        l = l->next;
    }

    return l;
}

(我还重写了 getter 函数,因为我认为它表现不佳 - 我不确定它是否真的如此。)

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