链表的分段错误

时间:2014-10-31 04:30:20

标签: c

我的执行名称是test4。

输入:

$ ./test4 cccc zz abcdef0123456789 aaabbbcccddd

我希望创建一个char *类型的链表,如下所示:

 ---> 12:aaabbbcccddd ---> 12:abcdef0123456789 ---> 2:zz ---> 4:cccc 

每个节点的形式为“n:a”(n是字符串a的长度,n <= 12,如果a的长度大于12,则n = 12)

以下是我的代码:

struct Node *prepend(struct Node *list, char *s)
{
    struct Node *node = (struct Node *)malloc(sizeof(struct Node));
    if (node == NULL)
        return NULL;

    int length_s = strlen(s);
    if (length_s > 12)
        length_s = 12;

    char* temp = NULL;
    sprintf(temp,"%d:%s", length_s, s);

    strcpy(node->data, temp);
    node->next = list;

    return node;
}

prepend函数链接一个新节点列表

struct Node {
    struct Node *next;
    char *data;
};

    int main(int argc, char **argv)
    {
        struct Node *list = NULL;

        argv++;
        while (*argv)
        {
            list = prepend(list,*argv);
            argv++;
        }
        return 0;
    }

假设包含所有必需的库和结构,运行代码时我不断收到分段错误。我如何解决它?我相信问题出在sprintf中,但无法弄清楚原因。

2 个答案:

答案 0 :(得分:2)

您不在此处为temp分配内存:

char* temp = NULL;
sprintf(temp,"%d:%s", length_s, s);

您可以使用静态的字符数组或为其动态分配内存。

为了复制你想要的东西,你应该这样: 如果data Nodechar*

node->data = malloc((length_s + 1) + 1 + digits_of_length);
sprintf(node->data,"%d:%s", length_s, s);

如果data的{​​{1}}是一个字符数组,您应该这样做:

Node

如你所见,这有点令人讨厌,因为你必须找到长度的数字,以便分配内存。

为什么不使用名为str_length的额外字段来扩充sprintf(node->data,"%d:%s", ((length_s + 1) + 1 + digits_of_length), s); ,这将跟踪当前节点所持有的字符串的长度。这样,你可以修改你的功能:

Node

当你去做这个时,不要忘记写一个struct Node *prepend(struct Node *list, char *s) { struct Node *node = (struct Node *)malloc(sizeof(struct Node)); if (node == NULL) return NULL; int length_s = strlen(s); node->data = malloc(length_s + 1); strcpy(node->data, temp); node->str_length = length_s + 1; node->next = list; return node; } ,它将取消分配整个列表。

另外,不要施放malloc返回的内容。 Why?

答案 1 :(得分:1)

问题在于这些陈述

char* temp = NULL;
sprintf(temp,"%d:%s", length_s, s);

您没有分配poointer temp指向的内存。 Sp该程序已定义为begaviour。

如果不使用结构中的指针而使用大小为12 + 1的数组,则可以简化生活,因为复制字符串的长度限制为12个字符。

例如

enum { size = 13 };

struct Node
{
    char data[size];
    Node *next;
};

//...

struct Node *prepend( struct Node *list, const char *s )
{
    struct Node *node = ( struct Node * )malloc( sizeof( struct Node ) );
    if ( node == NULL ) return list;

    strnspy( node->data, s, size );
    node->data[size - 1] = '\0';

    node->next = list;

    return node;
}

如果你需要使用指针而不是字符数组和sprintft而不是strncpy hen你可以写

struct Node *prepend( struct Node *list, const char *s )
{
    const size_t N = 12;

    struct Node *node = ( struct Node * )malloc( sizeof( struct Node ) );
    if ( node == NULL ) return list;

    node->data = malloc( ( N + 1 ) * sizeof( char ) );
    sprintf( node->data, "%*.*s", N, N, s );

    node->next = list;

    return node;
}

当不再需要列表时,您必须删除它。例如

void delete( struct Node *list )
{
    while ( list )
    {
        Node *tmp = list;
        list = list->next;

        free( tmp->data );
        free( tmp );
    }
}