分段错误将struct指针传递给函数

时间:2018-01-13 23:53:14

标签: c pointers struct

我是C中的新手,为了了解结构我正在构建一个为 struct ll_string 提供一组有限功能的程序,它基本上是一个链表字符串。

我试图实现的一组函数包括一个 insert_ll_string()函数,它应该将传入的 struct ll_string 元素汇总到另一个元素的末尾< em> struct ll_string 元素但是没有这样做,因为在我的测试用例中调用函数的那一刻,程序崩溃了一个sig错误。这是 test_insert()函数的 STILL WORKS SIG FAULT 注释。

这是它的头文件:

file: ll_string.h

struct ll_string {
    char *string;
    struct ll_string *next;
};

struct ll_string *create_ll_string(char *, struct ll_string *);
void insert_ll_string(struct ll_string *, struct ll_string *);
void remove_item_from_ll_string(struct ll_string *, struct ll_string *);
void free_ll_string(struct ll_string *);
void print_ll_string(struct ll_string *);

这就是它相应的 .c 文件缺少 ll_string.h 中声明的函数的一些定义,但我猜我的问题可能只围绕着无论如何,函数 create_ll_string() insert_ll_string()

file: ll_string.c

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

#include "ll_string.h"

/* create_ll_string: allocates memory for a new struct ll_string and 
 * initializes it with given arguments returns a pointer to new struct */
struct ll_string *create_ll_string(char *string, struct ll_string *next) {
    struct ll_string *new_ll_string;

    if (!string) {
        printf("string can\'t be NULL\n");
        return NULL;
    }

    if (*string == '\0') {
        printf("string needs to be at least 1 char long\n");
        return NULL;
    }

    if (!(new_ll_string = (struct ll_string *) malloc(sizeof(struct ll_string)))) {
        printf("couldn\'t allocate mem for new ll_string\n");
        exit(EXIT_FAILURE);
    }

    new_ll_string->string = strdup(string);
    new_ll_string->next = next;

    return new_ll_string;
}

/* insert_ll_string: concanates item to the end of dest */
void insert_ll_string(struct ll_string *dest, struct ll_string *item) {
    struct ll_string *cur;

    if (!dest) {
        printf("dest and item can\'t be NULL\n");
        return;
    }
    if (!item) {
        printf("item can\'t be NULL\n");
        return;
    }

    cur = dest;
    while (!cur->next) {
        cur = cur->next;
    }

    cur->next = item;

    return ;
}

/* remove_item_from_ll_string: removes item from list src */
void remove_item_from_ll_string(struct ll_string *src, struct ll_string *item) {
    return ;
}

/* printf_ll_string: prints each string in ll_string */
void print_ll_string(struct ll_string *ll_string) {
    if (!ll_string) {
        printf("ll_string is NULL\n");
        return ;
    }

    do {
        printf("%s\n", ll_string->string);
    } while (!(ll_string = ll_string->next));
}

/* free_ll_string: frees all memory pointed to by ll_string */
void free_ll_string(struct ll_string *ll_string) {
    struct ll_string *next;

    if (!ll_string) {
        return ;
    }

    while ((next = ll_string->next)) {
        free(ll_string->string);
        free(ll_string);
        ll_string = next;
    }
}

这是我的测试。一切正常,直到 test_insert()函数引发 insert_ll_struct()。 ( test_create()按预期工作)使用MinUnit框架进行测试。

file: tests_ll_string.c

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

#include "minunit.h"

#include "ll_string.h"

#define MAX_ERROR_MSG_LENGTH 1000

int tests_run = 0;

static char *test_create(void) {
    struct ll_string *test_ll;
    struct ll_string *test_null_ll;
    char *empty_string = strdup("");
    char *null_string = NULL;
    char *correct_string = strdup("this should work");
    char *correct_string2 = strdup("this should also work");
    char *error_msg;

    if (!(error_msg = (char *) malloc(sizeof(char) * MAX_ERROR_MSG_LENGTH))) {
        printf("couldn\'t allocate mem for error msg");
        exit(EXIT_FAILURE);
    }

    // test_ll->string == correct_string
    // test_ll->next == NULL
    test_ll = create_ll_string(correct_string, NULL);
    sprintf(error_msg, "error, test_ll->string != \"%s\" is %s", correct_string, test_ll->string);
    mu_assert(
            error_msg,
            strcmp(test_ll->string, correct_string) == 0);

    // test_ll->next->string == correct_string
    // test_ll->string == correct_string2
    test_ll = create_ll_string(correct_string2, test_ll);
    sprintf(error_msg, "error, test_ll->string != \"%s\" is %s", correct_string2, test_ll->string);
    mu_assert(
            error_msg,
            strcmp(test_ll->string, correct_string2) == 0);

    sprintf(error_msg, "error, test_ll->next->string != \"%s\" is \"%s\"", correct_string, test_ll->next->string);
    mu_assert(
            error_msg,
            strcmp(test_ll->next->string, correct_string) == 0);

    test_null_ll = test_ll;
    test_null_ll = create_ll_string(empty_string, test_ll);
    // test_null_ll == NULL
    mu_assert(
            "error, test_null_ll != NULL",
            test_null_ll == NULL);

    test_null_ll = test_ll;
    test_null_ll = create_ll_string(null_string, test_ll);
    // test_null_ll == NULL
    mu_assert(
            "error, test_null_ll != NULL",
            test_null_ll == NULL);

    sprintf(error_msg, "error, test_ll->string != \"%s\" is \"%s\"", correct_string2, test_ll->string);
    mu_assert(
            error_msg,
            strcmp(test_ll->string, correct_string2) == 0);

    sprintf(error_msg, "error, test_ll->next->string != \"%s\" is \"%s\"", correct_string, test_ll->next->string);
    mu_assert(
            error_msg,
            strcmp(test_ll->next->string, correct_string) == 0);

    free_ll_string(test_ll);
    free(correct_string);
    free(correct_string2);
    free(empty_string);
    free(error_msg);

    return 0;
}

static char *test_insert(void) {
    struct ll_string *ll_test1;
    struct ll_string *ll_test2;
    struct ll_string *ll_test3;

    char *test_string1 = strdup("test_string1");
    char *test_string2 = strdup("test_string2");
    char *test_string3 = strdup("test_string3");
    char *error_msg;

    if (!(error_msg = (char *) malloc(sizeof(char) * MAX_ERROR_MSG_LENGTH))) {
        printf("couldn\'t allocate mem for error msg");
        exit(EXIT_FAILURE);
    }


    ll_test1 = create_ll_string(test_string1, NULL);
    ll_test2 = create_ll_string(test_string2, NULL);
    ll_test3 = create_ll_string(test_string3, NULL);

    // STILL WORKS

    insert_ll_string(ll_test1, ll_test2); // SEG FAULT
    insert_ll_string(ll_test1, ll_test3);

    sprintf(error_msg, "error, ll_test1->string != \"%s\" is \"%s\"", test_string1, ll_test1->string);
    mu_assert(
            error_msg,
            strcmp(ll_test1->string, test_string1) == 0);
    sprintf(error_msg, "error, ll_test1->next->string != \"%s\" is \"%s\"", test_string2, ll_test1->next->string);
    mu_assert(
            error_msg,
            strcmp(ll_test1->next->string, test_string2) == 0);
    sprintf(error_msg, "error, ll_test1->next->next->string != \"%s\" is \"%s\"", test_string1, ll_test1->next->next->string);
    mu_assert(
            error_msg,
            strcmp(ll_test1->next->next->string, test_string3) == 0);

    free_ll_string(ll_test1);
    free_ll_string(ll_test2);
    free_ll_string(ll_test3);
    free(test_string1);
    free(test_string2);
    free(test_string3);

    return 0;
}

static char *all_tests(void) {
    mu_run_test(test_create);
    mu_run_test(test_insert);
    return 0;
}

int main(int argc, char* argv[]) {
    char *result = all_tests();
    if (result != 0) {
        printf("%s\n", result);
    } else {
        printf("ALL TESTS PASSED\n");
    }
    printf("Tests run: %d\n", tests_run);

    return result != 0;
}

这是编译和执行的输出:

>> gcc -Wall -o test ll_string.c tests_ll_string.c
>> ./test
string needs to be at least 1 char long
string can't be NULL
[1]    6789 segmentation fault (core dumped)  ./test

导致此Sigmentation错误的原因是什么?我没有在程序崩溃的部分中访问除局部变量之外的任何内存。我没有解除引用我传递给 insert_ll_struct()的指针,至少在引发函数后不立即。

提前感谢您的帮助

3 个答案:

答案 0 :(得分:1)

我认为答案正在盯着我们。在insert_ll_string()

while (!cur->next) {

应该是

while (cur->next) {

答案 1 :(得分:0)

我要查看free_ll_string()中的逻辑。你确定你没有两次释放记忆吗?在代码中看起来如果释放链中的所有字符串。因此,我认为您将test_ll多次免费test_create。看看你在禁用test_create时是否仍然收到错误,如果没有,那么你发现我认为可能是由于未定义的行为造成的,因为你不止一次地释放东西......

最好在释放指向的内存后将任何释放的指针设置为NULL,然后你就可以避免这个问题了。

/* free_ll_string: frees all memory pointed to by ll_string */
void free_ll_string(struct ll_string *ll_string) {
    struct ll_string *next;

    if (!ll_string) {
        return ;
    }

    while ((next = ll_string->next)) {
        free(ll_string->string);
        free(ll_string);
        ll_string = next;
    }
}

答案 2 :(得分:0)

while(!cur-&gt; next){cur = cur-&gt; next; } 这段代码会导致崩溃,假设cur-&gt;下一次返回null,而不是你试图接受null,那么你应该把mm检查为cur in while循环,就像thiswhile一样(null!= cur&amp;&amp;!cur-&gt; next )