передача указателя на рекурсивную функцию в C - PullRequest
1 голос
/ 21 января 2009

Я только начинаю в дороге изучение C и столкнулся с некоторыми трудностями:

Приведенный ниже код дает мне следующую ошибку:

Присоединение к программе: `/ workfolder / cocoa / c_stuff / bookshelf / build / Debug / bookshelf ', процесс 1674.
Невозможно получить доступ к памяти по адресу 0xa0df194
Невозможно получить доступ к памяти по адресу 0xa0df194

// code start

#define MAX_NAME_LENGTH 200
#define MAX_AUTHOR_LENGTH 200
#define MAX_DESCRIPTION_LENGTH 1000
#define MAX_PUBLISHER 200
#define MAX_ISBN 50


//structures<
typedef struct {
    char title[MAX_NAME_LENGTH];
    char author[MAX_AUTHOR_LENGTH];
    char ISBN[MAX_ISBN];
    char description[MAX_DESCRIPTION_LENGTH];
    char publisher[MAX_PUBLISHER];
} Book;


void getUserInput(Book *s[])
{   
    printf("what is the book's title ?\n");
    fgets(s[book_count]->title, MAX_NAME_LENGTH, stdin);

    printf("what is the author's name?\n");
    fgets(s[book_count]->author, MAX_AUTHOR_LENGTH, stdin);

    printf("what is the ISBN?\n");
    fgets(s[book_count]->ISBN, MAX_ISBN, stdin);

    printf("write a short description\n");
    fgets(s[book_count]->description, MAX_DESCRIPTION_LENGTH, stdin);

    printf("what is the book's publisher\n");
    fgets(s[book_count]->publisher, MAX_PUBLISHER, stdin);

    printf("want to add another book ? Y\\N\n");

    book_count++;

    if(tolower(fgetc(stdin)) == 'y') 
    {
        return getUserInput(s);
    } 
    else 
    {
        return;
    }
}


int main (int argc, const char * argv[]) {
    // insert code here...
    Book *book_shelf[100];

    if((book_shelf[0] = (Book *)malloc(sizeof(Book))) == NULL)
    {
        exit(1);
    }

    getUserInput(book_shelf);

    return 0;
}

Код компилируется правильно, и функция запускается нормально с первого раза (все вопросы задаются, а структура получает данные); но когда пользователь вводит 'y', чтобы добавить другую книгу, возникает ошибка mem.

Есть идеи, где происходит ошибка?

Заранее спасибо!

Ответы [ 9 ]

10 голосов
/ 21 января 2009

Вы когда-либо выделяли память только для первой книги в main - после этого она пытается записать следующий слот в массиве, который не указывает на выделенный блок памяти, что вызывает ошибку seg. Вам нужно будет выделить память для каждой книги, в которой вы хотите прочитать.

Кроме того, поскольку C не знает, каков размер массива, вы должны передать эту информацию в вызовы функций. (И я не понимаю, где вы определяете book_count.)

Вы можете попробовать что-то вроде этого:

void getUserInput(Book *s[], int *book_count, int max_book_count)
{
   if (book_count == max_book_count) return; // If we've filled all the slots, we can't add anymore without causing trouble.
   s[book_count] = malloc(sizeof(Book));

   ..

   if(tolower(fgetc(stdin)) == 'y') 
   {
       (*book_count)++;
       getUserInput(s, book_count, max_book_count);
   } 
   return;
}

int main (int argc, const char * argv[]) {
    // insert code here...
    Book *book_shelf[100];

    int book_count = 0;
    getUserInput(book_shelf, &book_count, 100);
    // Make sure to free all the malloc'd data
}

Еще лучше в этой ситуации было бы просто использовать цикл и пропустить весь шаг рекурсии.

int main (int argc, const char * argv[]) {
    // insert code here...
    Book *book_shelf[100];

    char response = 'y';
    int book_count = 0;
    while (book_count < 100 && response == 'y')
    {
        book_shelf = malloc(sizeof(Book));
        response = getUserInput(book_shelf[book_count++]);
    }
    // make sure to free all the allocated data!
}

char getUserInput(Book *book)
{
   // write input straight to book
   printf("what is the book's title ?\n");
   fgets(book->title, MAX_NAME_LENGTH, stdin);

   ...

   return tolower(fgetc(stdin));
}
2 голосов
/ 21 января 2009

Внутри main вы разместили в стеке массив из 100 указателей на структуру книги. Я считаю, что вы намеревались выделить 100 структур, а затем передать адрес этому блоку структур в getUserInput

Изменить основной на:

Book book_shelf[100];
...
getUserInput(book_shelf);
...

РЕДАКТИРОВАТЬ: OOPS Пропустил одну книгу malloc, упомянутую в предыдущем посте. Это правильные для первой книги. Если вы измените, как указано выше, и удалите если (book_shelf [0] ...) отметит, вы добьетесь ожидаемых результатов

2 голосов
/ 21 января 2009

Если я не читаю что-то не так, вы не определили book_count, прежде чем использовать его как индекс массива.

1 голос
/ 21 января 2009

Рекурсия, вероятно, излишня для этой проблемы, когда это делает простое do {...}, а пользователь продолжает отвечать "да". Однако проблема, с которой вы столкнулись, в основном связана с вашей Книгой * book_shelf [100]. Есть несколько способов решить эту проблему.

Сначала измените его на массив книг, подобных samills предлагает:

Book book_shelf[100];

и затем измените ваш getUserInput на что-то вроде этого:

getUserInput(Book *book_shelf, int offset, int length) {
    if(offset < 0 || offset >= length) {
        return;
    }

    //...

    return getUserInput(book_shelf, offset + 1, length)
}

Или вы можете использовать существующий код и изменить функцию getUserInput, чтобы она выглядела примерно так и удалила malloc из main:

getUserInput(Book *book_shelf) {
     book_shelf[book_count] = (Book*)malloc(sizeof(Book));
     // ...
}

поддерживает правильное использование оператора sizeof (я вижу, что эта вещь используется неправильно так часто, что мои глаза кровоточат).

1 голос
/ 21 января 2009
  1. Вы выделяете только место для первой книги, а не для остальных (malloc in main)

  2. Я полагаю, что отсутствует некоторый код, нет объявления и инициализации book_count

  3. Вы должны использовать циклы вместо рекурсии

  4. Используйте не рекурсию, а циклы для такого рода повторений

0 голосов
/ 18 января 2012

факториал с указателем и рекурсией

#include<iostream.h>
#include<conio.h>

int show(int *p)

{

int f;

int x=*p;
if(*p==1)  //boundry checking for recursion

return 1;

else

f=x*show(&(--*p)); //this code is similar to f=x*show(n-1); with non-pointers 

return f;

}

void main()

{

int a=6;

int b=show(&a);

cout<<b;

getch();

}
0 голосов
/ 30 января 2009

Похоже, вы все еще делаете это неправильно:

Книга * book_shelf;

if (book_shelf = (Book *) malloc (sizeof (Book)) == NULL) // код выхода

book_shelf - это только размер указателя. Когда вы делаете malloc, вы выделяете только одну книгу за раз. Это не верно. Вам необходимо выделить непрерывную память для массива объектов Book в одном экземпляре массива.

Как

Книга book_shelf [100];

не

Книга * book_shelf [100];

или используя malloc, используйте указатель, чтобы указать массив, инстанцированный с помощью
100 * таНос (SizeOf (книга)).

Вам может повезти, что между вашими вызовами malloc (sizeof (Book)) не выделяется другая кучная память и что система управления памятью выделяет непрерывную память по умолчанию. Кроме того, book_shelf будет указывать только на последнюю неправильную структуру Book, а не на первую, как вы указали в своем первоначальном вопросе.

Джош также не выделяет достаточно памяти за один раз. Используйте связанный список, если вы хотите продолжать расширять элементы до конца вашей book_shelf по одному.

0 голосов
/ 21 января 2009

Большое спасибо за ответы!

Я понял, что у меня недостаточно памяти для обработки более одного элемента массива структуры (именно то, что говорит Джош). Итак, по существу:

Книга * book_shelf;

if (book_shelf = (Book *) malloc (sizeof (Book)) == NULL) // код выхода

поэтому во второй раз я столкнулся с проблемой памяти.

Еще раз спасибо!

0 голосов
/ 21 января 2009

Как и в ответе Джоша, добавление в код следующих строк должно заставить его работать:

book_count++;

if(tolower(fgetc(stdin)) == 'y') 
{
    if((book_shelf[book_count] = (Book *)malloc(sizeof(Book))) == NULL)
    {
        printf("Cannot allocate memory for Book");
        exit(1);
    }
    return getUserInput(s);
} 
else 
{
    return;
}

Однако я рекомендую вам не использовать рекурсивную функцию для получения ввода. Рекурсивность может привести к трудностям при отладке. Вы можете вместо этого использовать обычный цикл.

Примечание: Я предполагаю, что book_count является глобальной переменной, которая была инициализирована в 0

...