为啥在访问二级指针时出现分段错误错误? C语言

Posted

技术标签:

【中文标题】为啥在访问二级指针时出现分段错误错误? C语言【英文标题】:Why am i getting segmentation fault error while accessing a second level pointer?? C language为什么在访问二级指针时出现分段错误错误? C语言 【发布时间】:2021-06-21 02:18:43 【问题描述】:

以下代码在运行时生成分段错误错误...只是因为我尝试 使用p_list3(二级指针)打印其内容或为其分配一些东西...注意:注意每个代码片段中printf(...)的差异...完整代码在最后。

struct node **p_list2 = NULL, **p_list3 = NULL;
    p_list = &list;

    while((*p_list)->next != NULL)  //Start [[WHILE1]]
    
        p_list2 = &(*p_list)->next;
        while(*p_list2 != NULL)  //start [[WHILE2]]
        
            printf("%s   %s   %u\n", (*p_list)->word, (*p_list2)->word, p_list3);
            p_list2 = &(*p_list2)->next;
          //End [[WHILE2]]
        p_list3 = p_list;
        p_list = &(*p_list)->next;
      //End [[WHILE1]]

虽然没有这个

struct node **p_list2 = NULL, **p_list3 = NULL;
    p_list = &list;

    while((*p_list)->next != NULL)  //Start [[WHILE1]]
    
        p_list2 = &(*p_list)->next;
        while(*p_list2 != NULL)  //start [[WHILE2]]
        
            printf("%s   %s   \n", (*p_list)->word, (*p_list2)->word);
            p_list2 = &(*p_list2)->next;
          //End [[WHILE2]]
        p_list3 = p_list;
        p_list = &(*p_list)->next;
      //End [[WHILE1]]

也不是这个

struct node **p_list2 = NULL, **p_list3 = NULL;
    p_list = &list;

    while((*p_list)->next != NULL)  //Start [[WHILE1]]
    
        p_list2 = &(*p_list)->next;
        while(*p_list2 != NULL)  //start [[WHILE2]]
        
            printf("%s   %s   %u\n", (*p_list)->word, (*p_list2)->word, p_list3);
            p_list2 = &(*p_list2)->next;
          //End [[WHILE2]]
        //p_list3 = p_list;
        p_list = &(*p_list)->next;
      //End [[WHILE1]]

不会产生这样的错误..这里发生了什么???

完整代码

/*
@@@@ PROGRAM NAME: knkcch17proj05.c
@@@@ FLAGS: -std=c99
@@@@ PROGRAM STATEMENT: 
Write a program that sorts a series of words 
entered by the user:

    Enter word: foo
    Enter word: bar
    Enter word: baz
    Enter word: quux
    Enter word:
    
    In sorted order: bar baz foo quux

Assume that each word is no more than 20 characters long. Stop reading when the 
user enters an empty word (i.e., presses Enter without entering a word). Store 
each word in a dynamically allocated string, using an array of pointers to keep 
track of the strings, as in the remind2.c program (Section 17.2). After all 
words have been read, sort the array (using any sorting technique) and then use 
a loop to print the words in sorted order. Hint: Use the read_line function to 
read each word, as in remind2.c.
*/
#include <stdio.h>
#include <string.h>  //strcpy()
#include <stdlib.h>  //malloc(), free(), NULL, EXIT_FAILURE
#include <ctype.h>  //isspace()
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
struct node

    char word[10];
    struct node *next;
 *list = NULL;
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
int read_line(char str[], int n);
//------------------------START OF MAIN()--------------------------------------
int main(void)

    printf("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
    printf("File: %s, C Version: %ld, Date: %s, Time: %s\n\n", __FILE__, __STDC_VERSION__, __DATE__, __TIME__);

    char *str;
    struct node **p_list = &list, *new_word;
    //Get words from user
    while(1)
    
        printf("Enter word: ");
        //Allocate memory of size about struct node + 10 bytes
        if((new_word = (struct node *)malloc(sizeof(struct node))) == NULL)
        
            printf("Error: malloc failed.");
            exit(EXIT_FAILURE);
        
        //Read word
        (read_line(str, 10));
        if(!strlen(str))  //If '\n' is detected without reading character.
            break;
        //Read word is stored to node.
        strcpy(new_word->word, str);
        new_word->next = NULL;

        //Load the node to list
        *p_list = new_word;
        p_list = &(*p_list)->next;
    
    
    //Print words in the order they entered
    printf("\nIn Unsorted order: ");
    new_word = list;
    while(new_word)
    
        printf("%s  ", new_word->word);
        new_word = new_word->next;
        
    
    
    //Sorting
    struct node **p_list2 = NULL, **p_list3 = NULL;
    p_list = &list;

    while((*p_list)->next != NULL)  //Start [[WHILE1]]
    
        p_list2 = &(*p_list)->next;
        while(*p_list2 != NULL)  //start [[WHILE2]]
        
            printf("%u   %u   %u\n", p_list, p_list2, p_list3);
            printf("%s   %s   %u\n", (*p_list)->word, (*p_list2)->word, p_list3);
            #if 0
            if((strcmp((*p_list)->word, (*p_list2)->word)) == 1)  //Start [[IF1]]
            
                printf("%s   %s\n", (*p_list)->word, (*p_list2)->word);
                if(p_list3 != NULL)
                    (*p_list3)->next = *p_list2;  //update previous node.
                (*p_list)->next = (*p_list2)->next;
                (*p_list2)->next = *p_list;

                struct node *temp = *p_list;
                *p_list = *p_list2;
                *p_list2 = temp;
                
              //End [[IF1]]
            #endif
            p_list2 = &(*p_list2)->next;
            
          //End [[WHILE2]]
        p_list3 = p_list;
        p_list = &(*p_list)->next;
      //End [[WHILE1]]
    
    printf("\nIn sorted order: ");
    new_word = list;
    while(list)
    
        //print the word
        printf("%s  ", list->word);
        //prepare to free the allocated memory
        new_word = list;
        list = list->next;
        //free the memory.
        free(new_word);
    
    

    printf("\n++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
    return 0;

//-------------------------END OF MAIN()---------------------------------------
int read_line(char str[], int n)

  int ch, i = 0;

  //while (isspace(ch = getchar()))
    //;
  ch = getchar();
  while (ch != '\n' && ch != EOF) 
    if (i < n)
      str[i++] = ch;
    ch = getchar();
  
  str[i] = '\0';
  return i;

//---------------------------------------------------------------------------
//---------------------------------------------------------------------------

【问题讨论】:

如果您向我们展示指针如何获取它们的值以及如何分配内存,我们只能解释为什么指针未指向有效分配的内存。另外,请记住,没有错误并不意味着代码是正确的。允许未定义的行为做字面上的任何事情,包括“它似乎可以工作”。 p_list = &amp;list; 可能是罪魁祸首。 p_list = &amp;list; 不是罪魁祸首,因为p_list 可以遍历链表。 printf() 函数证明了这一点。 您似乎只是为了它而使用**。摆脱无用的第二级间接。修复后,单步执行程序即可找到错误。 我不明白你的观点@Lundin,我没有在程序中的任何一点使用二级间接来访问任何数据....我使用二级指针只是为了直接改变链表.. 【参考方案1】:

只需要指针。str 没有分配内存,char str[21]; 将起作用。read_line() 需要使用if (i &lt; n - 1) 以确保终止的零将在数组内边界。 为简单起见,每个新词都被添加到列表的开头。

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

struct node

    char word[21];
    struct node *next;
;

int read_line(char str[], int n);

int main(void)

    printf("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
    printf("File: %s, C Version: %ld, Date: %s, Time: %s\n\n", __FILE__, __STDC_VERSION__, __DATE__, __TIME__);

    char str[21];
    struct node *p_list = NULL;
    struct node *new_word = NULL;
    //Get words from user
    while(1)
    
        printf("Enter word: ");
        //Read word
        read_line ( str, 21);
        if ( ! strlen ( str))   //If '\n' is detected without reading character.
            break;
        
        if ( ( new_word = malloc ( sizeof *new_word)) == NULL)
        
            printf("Error: malloc failed.");
            exit(EXIT_FAILURE);
        
        //Read word is stored to node.
        strcpy ( new_word->word, str);

        //Load the node to beginning of list
        new_word->next = p_list;
        p_list = new_word;
    

    //Print words in the reversed order they entered
    printf("\nIn Unsorted order: ");
    new_word = p_list;
    while ( new_word)
    
        printf("%s  ", new_word->word);
        new_word = new_word->next;
    
    printf("\n");

    //Sorting
    struct node *p_list2 = p_list;
    struct node *p_list3 = p_list;
    struct node *sort = p_list;

    while ( sort->next != NULL)  //Start [[WHILE1]]
    
        p_list2 = sort->next;
        while ( p_list2 != NULL)  //start [[WHILE2]]
        
            printf("%s   %s   %p\n", sort->word, p_list2->word, (void *)p_list3);
            p_list2 = p_list2->next;

          //End [[WHILE2]]
        sort = sort->next;
        p_list3 = sort;
      //End [[WHILE1]]

    printf("\nIn sorted order: ");
    new_word = p_list;
    while( new_word)
    
        printf("%s  ", new_word->word);
        new_word = new_word->next;
    

    new_word = p_list;
    while( new_word) 
        p_list = new_word;
        new_word = p_list->next;
        //free the memory.
        free( p_list);
    

    printf("\n++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
    return 0;

//-------------------------END OF MAIN()---------------------------------------
int read_line(char str[], int n)

    int ch, i = 0;

    while  ( ( ch = getchar ( )) != '\n' && ch != EOF) 
        if (i < n - 1) // - 1 to provide for terminating zero
            str[i++] = ch;
        
    
    str[i] = '\0';
    return i;

【讨论】:

谢谢@Tim Boddy、@user3121023 和其他花时间回复的人...解决方案解决了分段错误的问题。我无法确定我为char *str 分配内存的错误,因为它将读取的字符串存储到链表中......【参考方案2】:

@Yaachaka 我将非常狭隘地回答你的问题,只是解决分段错误的原因,并且不要评论程序是否有效。

您崩溃的原因是在对 read_line 的调用中,您传递了一个未初始化的 str 值:

char *str;
struct node **p_list = &list, *new_word;
//Get words from user
while(1)

    printf("Enter word: ");
    //Allocate memory of size about struct node + 10 bytes
    if((new_word = (struct node *)malloc(sizeof(struct node))) == NULL)
    
        printf("Error: malloc failed.");
        exit(EXIT_FAILURE);
    
    //Read word
    (read_line(str, 10));
    if(!strlen(str))  //If '\n' is detected without reading character.
        break;
    //Read word is stored to node.
    strcpy(new_word->word, str);
    new_word->next = NULL;

这是一个问题,因为 read_line 期望第一个参数指向可以存储正在读取的行的某个位置。鉴于您已经有一个未使用的缓冲区(new_word->word),您可以通过将上面的代码更改为直接读取 new_node->word:

来修复您的崩溃:
struct node **p_list = &list, *new_word;
//Get words from user
while(1)

    printf("Enter word: ");
    //Allocate memory of size about struct node + 10 bytes
    if((new_word = (struct node *)malloc(sizeof(struct node))) == NULL)
    
        printf("Error: malloc failed.");
        exit(EXIT_FAILURE);
    
    //Read word
    (read_line(new_word->word, 10));
    if(!strlen(new_word->word))  //If '\n' is detected without reading character.
        free(new_word);
        break;
    
    new_word->next = NULL;

【讨论】:

以上是关于为啥在访问二级指针时出现分段错误错误? C语言的主要内容,如果未能解决你的问题,请参考以下文章

返回指针时出现分段错误

在调用函数中取消引用指针时出现分段错误

在 C++ 中使用指针的数组:访问返回的数组时出现分段错误

为啥在编译我的代码C(linux)时出现分段错误(核心转储)[关闭]

打印指针时出现分段错误

在指针迭代中使用 for 循环时出现分段错误