除第一个元素外的所有元素的分段错误

Posted

技术标签:

【中文标题】除第一个元素外的所有元素的分段错误【英文标题】:Segmentation fault for all elements except the first 【发布时间】:2021-03-11 13:33:48 【问题描述】:

所以我有一个名为 'library' 的结构,它存储结构 'books' 的对象,并由 3 本书的列表初始化,但是当我尝试打印对象的属性时,我得到一个“分段错误(核心转储)”错误。我知道这意味着我正在尝试访问一些我无法访问的内存,但在这种情况下,我可以正确访问第一个元素,所以这让我相信我错误地初始化了一些东西。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAXBOOKS 10

typedef struct books

    char* title;
    char* author;
    int id;
book;

typedef struct library

    int number_of_books;
    book* booklist [MAXBOOKS];
lib;

void storeBook(lib library,book CurrentBook)

    library.booklist[0] = &CurrentBook;


void printLibrary(lib library)

    for(int i = 0; i < library.number_of_books; i++)
    
        printf("Author:%s\n",library.booklist[i]->title);
    



int main()


    book b_1 = "The trial","Kafka",101;
    book b_2 = "The lurking fear","Lovecraft",102;
    book b_3 = "Dora's storytime collection","Valdes",103;

    book* list = (book*)malloc(3*sizeof(book));
    list[0] = b_1; list[1] = b_2; list[2] = b_3;

    lib CurrentLibrary = 3,list;
    printLibrary(CurrentLibrary);
    return 0;

【问题讨论】:

数组不是指针。打开编译器警告。 代码无法编译:library.booklist[i]-&gt;title必须是library.booklist[i].title 当我这样做时,我现在收到警告说我在库初始化周围缺少括号,并且在运行程序时,我得到了作者姓名的 (null) 值。无论如何我可以使用指针并移动它来打印下一个作者字符吗? 您希望图书馆包含指向书籍对象或副本的指针吗? 【参考方案1】:

booklist1[i] = *(booklist1+i),则booklist2[i][j] = *(*(booklist2+i)+j),如果j=0,则*(*(booklist2+i)+j) = *(*(booklist2+i)+0) = *(booklist2[i]) = *booklist2[i]

booklist2[0] 指向第一行,booklist2[1] 指向第二行,依此类推,...

您正在定义一个书本指针数组(二维数组):book* booklist [MAXBOOKS] 但是list 是一本书的数组(一维数组)。执行此语句后,lib CurrentLibrary = 3,list;list 数组将存储到booklist[0] 行中。但是booklist[1], booklist[2],..... booklist[9] 的所有其他指针都没有指向任何元素。 但是,您正在printLibrary 函数中访问booklist[1]booklist[2]booklist[3]。这就是 Segmentation fault 的原因。

如需了解更多信息(二维数组),请打印以下行:

printf("Title %s\n", library.booklist[0][0].title); prints--> 标题审判 printf("Title %s\n", library.booklist[0][1].title);prints--> 标题潜伏的恐惧printf("Title %s\n", library.booklist[0][2].title);prints-->标题朵拉的故事时间合集

但是尝试访问,library.booklist[1][0].title 会抛出分段错误,因为第二行指针没有指向任何元素。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAXBOOKS 10

typedef struct books

    char* title;
    char* author;
    int id;
book;

typedef struct library

    int number_of_books;
    book *booklist;  // It should be 1-D array, since you are passing 1-D array of book
lib;

void storeBook(lib library,book CurrentBook)

    library.booklist[0] = CurrentBook;


void printLibrary(lib library)

    for(int i = 0; i < library.number_of_books; i++)
    
        printf("Title:%s\n",library.booklist[i].title);
        printf("Author:%s\n",library.booklist[i].author);
        printf("Book ID:%d\n",library.booklist[i].id);
    



int main()


    book b_1 = "The trial","Kafka",101;
    book b_2 = "The lurking fear","Lovecraft",102;
    book b_3 = "Dora's storytime collection","Valdes",103;

    book* list = malloc(3*sizeof(book));
    list[0] = b_1; list[1] = b_2; list[2] = b_3;

    lib CurrentLibrary = 3,list; // list is 1-D array of book
    printLibrary(CurrentLibrary);
    return 0;

输出:

Title:The trial
Author:Kafka
Book ID:101
Title:The lurking fear
Author:Lovecraft
Book ID:102
Title:Dora's storytime collection
Author:Valdes
Book ID:103

【讨论】:

非常感谢。但是为什么 book* booklist [MAXBOOKS]; 定义一个二维数组? book* booklist [MAXBOOKS] 是一个包含 10 个指针的数组。查找指针数组。 阅读这篇文章:google.com/amp/s/www.geeksforgeeks.org/… 我没有看到您对 2D 数组 的断言,因为它是指向书籍的指针数组...您可以存储一个数组或一本书...没有二维数组。 @LuisColorado book* booklist [MAXBOOKS]; 是指针数组。请检查我的编辑,以获得清晰的理解。【参考方案2】:

试试这个:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAXBOOKS 10

typedef struct book

    char *title;
    char *author;
    int id;
 Book;

typedef struct lib

    int length;
    Book *list[MAXBOOKS];
 Library;

void freeBook(Book *b)

    free(b->title);
    free(b->author);
    free(b);


void freeLibrary(Library *l)

    for (int i = 0; i < l->length; i++)
    
        freeBook(l->list[i]);
    
    free(l);


Book* newBook(char* title, char* author, int id)

    // param check 
    if( !title || !author || id<0 )
        return NULL;
    

    // allocate memory 
    Book* b = malloc(sizeof(Book));
    b->title = malloc(sizeof(char) * strlen(title) + 1);
    b->author = malloc(sizeof(char) * strlen(author) + 1);

    // copy data into struct
    strcpy(b->title, title);
    strcpy(b->author,author);
    b->id = id;

    // Send back new book
    return b;


Library *newLibrary()

    // allocate memory
    Library *l = malloc(sizeof(Library));
    l->length = 0;

    // return new Library
    return l;


void addBook(Library** library, Book* toAdd)

    // Make sure there is a book to add
    if (toAdd == NULL)
        printf("ERROR: Attempted To Add Invaild Book.\n");
    

    // check if library is NULL
    else if (*library == NULL)
        printf("ERROR: Library is NULL.\n");
        freeBook(toAdd);
    
    // Check if library is full
    else if( (*library)->length >= 10 )
        printf("\nERROR: Library is full. Cannot Store:\n\nTitle: %s\nAuthor: %s\nID: %d\n\n",toAdd->title,toAdd->author,toAdd->id);
        freeBook(toAdd);
    
    else
    
        (*library)->list[(*library)->length] = toAdd;
        (*library)->length++;
    


void printLibrary(Library* library)

    printf("\n------LIBRARY------\n");
    for (int i = 0; i < library->length; i++)
    
        printf("\nTitle: %s\nAuthor: %s\nID: %d\n", library->list[i]->title, library->list[i]->author, library->list[i]->id);
    
    printf("\n\n");


int main()


    Library *library = newLibrary();

    addBook(&library, newBook("The trial", "Kafka", 101));
    addBook(&library, newBook("The lurking fear", "Lovecraft", 102));
    addBook(&library, newBook("Dora's storytime collection", "Valdes", 103));

    //UNCOMMENT IF WANTING TO SEE MAXED OUT LIBRARY
    /*addBook(&library, newBook("The trial", "Kafka", 101));
    addBook(&library, newBook("The lurking fear", "Lovecraft", 102));
    addBook(&library, newBook("Dora's storytime collection", "Valdes", 103));
    addBook(&library, newBook("The trial", "Kafka", 101));
    addBook(&library, newBook("The lurking fear", "Lovecraft", 102));
    addBook(&library, newBook("Dora's storytime collection", "Valdes", 103));
    addBook(&library, newBook("The trial", "Kafka", 101));*/
    
    // UNCOMMENT TO TEST OVER LIBRARY CAPACITY 
    //addBook(&library, newBook("The trial", "Kafka", 101));

    printLibrary(library);

    freeLibrary(library);

    return 0;

编辑:我刚刚看到这个问题在我发布并刷新页面后得到了回答。该代码是一个有效的解决方案,并且可以正确管理内存并处理使用结构处理数据时可能出现的大多数错误。

【讨论】:

【参考方案3】:

嗯,首先要说的是,我已尝试通过进行最少的更改来使您的代码正常工作,并指出您犯错误(或无法理解)的地方。首先,您已经在程序中为您的书籍预订了空间,因为您已经在 main 中创建并初始化了三个 struct book 类型的实例,因此您可以将它们的引用分配给您的 lib 对象,而无需为它们,也不是数组,它已经分配在lib结构中,所以当你在main中创建lib对象时,你也可以只用这些实例的地址初始化数组,这样:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAXBOOKS 10

typedef struct books

    char* title;
    char* author;
    int id;
book;

typedef struct library

    int number_of_books;
    book* booklist [MAXBOOKS];
lib;

void storeBook(lib library,book CurrentBook)

    library.booklist[0] = &CurrentBook;


void printLibrary(lib library)

    for(int i = 0; i < library.number_of_books; i++)
    
        printf("Author:%s\n",library.booklist[i]->title);
    



int main()


    book b_1 = "The trial","Kafka",101;
    book b_2 = "The lurking fear","Lovecraft",102;
    book b_3 = "Dora's storytime collection","Valdes",103;

    /* book* list = (book*)malloc(3*sizeof(book)); // no need to call malloc, you have already reserved memory above (and intialized it) */
    
    /* just use the addresses of the books in the library array of pointers */
    lib CurrentLibrary =  3,  &b_1, &b_2, &b_3 ;

    /* list[0] = b_1; list[1] = b_2; list[2] = b_3; */

    /* lib CurrentLibrary = 3,list; */
    printLibrary(CurrentLibrary);  /* BEWARE:  you are making a copy of the library structure and passing it by value, it is cheaper to pass a reference */
    return 0;

BEWARE: 注释指出您通过值传递lib 结构(将lib 对象复制到函数,并在函数中使用副本)声明效率更高只是对 printLibrary() 函数中对象的引用,将其声明为:

void printLibrary(lib *library)

    ...

然后调用它:

    ...
    printLibrary(&CurrentLibrary);

因为这将只复制引用(它小于您传递的整个内容,并且必须复制)

如果你想使用动态分配的内存,调用 malloc 来完成所有这些,那么你最好使用这种方法:

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

#define MAXBOOKS 10

typedef struct books 
    char* title;
    char* author;
    int id;
 book;

typedef struct library 
    int number_of_books;
    book* booklist [MAXBOOKS];
 lib;

void panic(char *str)

    fprintf(stderr, "PANIC: %s\n", str);
    exit(EXIT_FAILURE);


book *createBook(char *title, char *author, int id)

    /* don't cast the value returned by malloc() */
    /* first create the structure */
    book *ret_val = malloc(sizeof *ret_val);
    if (ret_val == NULL) 
        panic("couldn't allocate memory for book");
    
    /* strdup makes a dynamic memory copy of the string
     * you passed as parameter */
    /* allocate memory and copy the string title to it */
    ret_val->title  = strdup(title);
    if (ret_val->title == NULL) 
        panic("couldn't allocate memory for book's title");
    
    /* allocate memory and copy the string author to it */
    ret_val->author = strdup(author);
    if (ret_val->author == NULL) 
        panic("couldn't allocate memory for book's author");
    
    ret_val->id = id;
    return ret_val;


lib *createLibrary()

    lib *ret_val = malloc(sizeof *ret_val);
    if (ret_val == NULL) 
        panic("couldn't allocate memory for library");
    
    /* initialize the number of books to 0 */
    ret_val->number_of_books = 0;
    return ret_val;


void storeBook(lib *library, book *book)

    /* check that we can add more books */
    if (library->number_of_books >= MAXBOOKS) 
        panic("No space left on library for another book");
    
    /* then add it (BEWARE that, as the books are freed as part of the
     * library destruction, you have only to add books created by
     * createBook() */
    library->booklist[library->number_of_books++] = book;


void printLibrary(lib *library)

    for(int i = 0; i < library->number_of_books; i++)
    
        /* we are using this reference three times below, so we save it
         * to facilitate things and calculations. */
        book *b = library->booklist[i];

        /* separate the books with an empty line after the first. */
        if (i > 0) printf("\n");
        printf("Id:     %d\n", b->id);
        printf("Title:  %s\n", b->title);
        printf("Author: %s\n", b->author);
    


void freeBook(book *b)

    /* first free the references ***INSIDE*** book */
    free(b->title);
    free(b->author);
    /* only after that, we can free() the book instance */
    free(b);


void freeLibrary(lib *library)

    /* as above, we need to first free() the references to the books,
     * calling freeBook() above, then we are able to free the library
     * reference */
    for(int i = 0; i < library->number_of_books; i++) 
        freeBook(library->booklist[i]);
    
    free(library);


int main()


    lib *CurrentLibrary = createLibrary();

    /* create the book and store it in a shot */
    storeBook(CurrentLibrary,
            createBook("The trial", "Kafka", 101));
    storeBook(CurrentLibrary,
            createBook("The lurking fear", "Lovecraft", 102));
    storeBook(CurrentLibrary,
            createBook("Dora's storytime collection", "Valdes", 103));

    printLibrary(CurrentLibrary);

    freeLibrary(CurrentLibrary);

    return EXIT_SUCCESS;

【讨论】:

以上是关于除第一个元素外的所有元素的分段错误的主要内容,如果未能解决你的问题,请参考以下文章

C++中打印链表元素的分段错误

链表中的分段错误

使用 libconfig 传递组元素时出现分段错误

C快速排序(链表)分段错误

测试用例中的分段错误

使用纯 css 隐藏除第一个元素之外的所有元素