Ошибка сегментации для всех элементов, кроме первого

#c #struct #segmentation-fault

#c #структура #ошибка сегментации

Вопрос:

итак, у меня есть структура с именем «библиотека», в которой хранятся объекты структуры «книги», и она инициализируется списком из 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] = amp;CurrentBook;
}

void printLibrary(lib library)
{
    for(int i = 0; i < library.number_of_books; i  )
    {
        printf("Author:%sn",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;
}
 

Комментарии:

1. Массив не является указателем. Включите предупреждения компилятора.

2. Код не компилируется: library.booklist[i]->title должно быть library.booklist[i].title

3. Когда я делаю это, я теперь получаю предупреждения о том, что у меня отсутствуют скобки вокруг инициализации библиотеки, и при запуске программы я получаю (нулевые) значения для имен авторов. Могу ли я в любом случае просто использовать указатели и переместить их для печати следующего символа автора?

4. Вы хотите, чтобы библиотека содержала указатели на объекты книги или копии?

Ответ №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] указывает на вторую строку и так далее….

Вы определяете массив указателей на книги (2D-массив) : book* booklist [MAXBOOKS]
Но list является массивом book (1-D массив). После выполнения этого оператора lib CurrentLibrary = {3,{list}}; list массив будет сохранен в booklist[0] строку. Но все остальные указатели booklist[1], booklist[2],..... booklist[9] не указывают ни на один элемент. Но вы обращаетесь booklist[1] к , booklist[2] , и booklist[3] в printLibrary функции. Это является причиной ошибки сегментации.

Для получения дополнительной информации (для двумерного массива), пожалуйста, выведите следующие строки:

printf("Title %sn", library.booklist[0][0].title); печатает -> Заголовок Пробная printf("Title %sn", library.booklist[0][1].title); печать -> Заголовок Скрытый страх
printf("Title %sn", library.booklist[0][2].title); выводит—>Заголовок Коллекция рассказов Доры

Но попытка доступа 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:%sn",library.booklist[i].title);
        printf("Author:%sn",library.booklist[i].author);
        printf("Book ID:%dn",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
 

Комментарии:

1. Большое вам спасибо. Но почему {book* booklist [MAXBOOKS];} определяет 2D-массив?

2. book* booklist [MAXBOOKS] представляет собой массив из 10 указателей. Найдите около массива указателей.

3. Прочитайте эту статью: google.com/amp/s/www.geeksforgeeks.org /…

4. Я не вижу вашего утверждения о 2D-массиве , поскольку это массив указателей на книги… вы можете хранить массив или одну книгу … без 2D-массива.

5. @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:nnTitle: %snAuthor: %snID: %dnn",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: %snAuthor: %snID: %dn", library->list[i]->title, library->list[i]->author, library->list[i]->id);
    }
    printf("nn");
}

int main()
{

    Library *library = newLibrary();

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

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

    printLibrary(library);

    freeLibrary(library);

    return 0;
}
 

РЕДАКТИРОВАТЬ: я только что видел, что на это был дан ответ после того, как я опубликовал и обновил страницу. Тем не менее, код является допустимым решением и правильно управляет памятью и обрабатывает большинство ошибок, которые могут возникнуть при обработке данных со структурой.

Ответ №3:

Ну, первое, что нужно сказать, это то, что я попытался заставить ваш код работать, внеся минимальный набор изменений и указав места, в которых вы делаете неправильные (или непонятные) вещи. Во-первых, вы уже зарезервировали место в своей программе для своих книг, поскольку вы создали и инициализировали три экземпляра типа struct book в main , поэтому вы можете назначить их ссылки на свой lib объект без необходимости выделять место ни для них, ни для массива, который уже выделен в lib структуре, поэтомукогда вы создаете lib объект в main, вы также можете инициализировать массив только адресами этих экземпляров, таким образом:

 #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] = amp;CurrentBook;
}

void printLibrary(lib library)
{
    for(int i = 0; i < library.number_of_books; i  )
    {
        printf("Author:%sn",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, { amp;b_1, amp;b_2, amp;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(amp;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: %sn", 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:     %dn", b->id);
        printf("Title:  %sn", b->title);
        printf("Author: %sn", 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;
}