Проблема ввода значений в структуру с двойными указателями - PullRequest
2 голосов
/ 25 апреля 2020

Я должен использовать двойной указатель в функции для заполнения элементов в структуре (функция должна быть void). Но это ничего не печатает. Я предполагаю, что проблема заключается в передаче правильного адреса, но не могу его найти.

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

typedef struct nums{
    int num;
    struct nums *ptr;
}sNums;

void addRecords(sNums** head);
sNums* createRecord();
void prinrecords(sNums* head);

int main(int argc, char const *argv[])
{
    sNums* head=NULL;
    printf("%d\n", &head);
    for (int i = 0; i < 3; ++i)
    {
        addRecords(&head);
    }
    system ("pause");
}

Это функция печати сохраненных элементов:

void prinrecords(sNums* head){
    while(head!=NULL){
        printf("{%d} ", head->num);
        head=head->ptr;
    }
}

Вот функция для добавления элементы, использующие двойной указатель:

void addRecords(sNums** head){
    sNums* temp_new=createRecord();
    sNums* fst_position;
    fst_position=*head;
    printf("%d\n", fst_position);
    if (fst_position == NULL)
    {
        fst_position=temp_new;
        return ;
    }
    while(fst_position->ptr!=NULL){
    fst_position=fst_position->ptr;
    }
    fst_position->ptr=temp_new; 
}

sNums* createRecord(){
    sNums *new=(sNums*)malloc(sizeof(sNums));
    printf("Enter Number: ");
    scanf("%d", &new->num);
    new->ptr=NULL;
    return new;
}

Ответы [ 3 ]

2 голосов
/ 25 апреля 2020

Этот фрагмент кода

fst_position=*head;
//...
if (fst_position == NULL)
{
    fst_position=temp_new;
    return ;
}

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

. Функцию можно определить следующим образом:

void addRecords(sNums** head)
{
    while ( *head != NULL ) head = &( *head )->ptr;

    *head = createRecord();
}

Вот и все. Всего два заявления. :)

Хотя в целом дизайн функций не очень хороший. Например, ввод чисел, которые будут добавлены в список, должен быть за пределами функции createRecord.

Кроме того, выделение памяти может быть неудачным. В этом случае ваша программа будет иметь неопределенное поведение.

Ниже приведена демонстрационная программа, показывающая, как ваши функции могут быть переработаны.

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

typedef struct nums
{
    int num;
    struct nums *ptr;
} sNums;

int addRecords(sNums** head, int num );
sNums* createRecord();
void prinrecords( const sNums* head );

sNums * createRecord( int num ) 
{
    sNums *node = malloc( sizeof( sNums ) );

    if ( node != NULL )
    {
        node->num = num;
        node->ptr = NULL;
    }

    return node;
}

int addRecords( sNums** head, int num )
{
    sNums *node = createRecord( num );
    int success = node != NULL;

    if ( success )
    {
        while ( *head != NULL ) head = &( *head )->ptr;

        *head = node;
    }

    return success;
}

void prinrecords( const sNums *head )
{
    for ( ; head != NULL; head = head->ptr )
    {
        printf( "%d -> ", head->num );
    }
    puts( "null" );
}

int main(void) 
{
    sNums* head = NULL;
    const size_t N = 10;

    for ( size_t i = 0; i < N; ++i )
    {
        int num;

        printf( "Enter a number: " );
        scanf( "%d", &num );

        addRecords( &head, num );
    }

    prinrecords( head );

    return 0;
}

Вывод программы может выглядеть как

Enter a number: 0
Enter a number: 1
Enter a number: 2
Enter a number: 3
Enter a number: 4
Enter a number: 5
Enter a number: 6
Enter a number: 7
Enter a number: 8
Enter a number: 9
0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> null
1 голос
/ 25 апреля 2020

Проблема в том, что ваша функция addRecords не изменяет заданный указатель head, когда создает новый список (т.е. при первом вызове)! Вместо этого вы должны сделать следующее:

void addRecords(sNums** head)
{
    sNums* temp_new = createRecord();
    sNums* fst_position;
    fst_position = *head;
//  printf("%d\n", fst_position);
    printf("%p\n", (void*)(fst_position));/// Let's keep the format/argument arrangement cool!
    if (fst_position == NULL) {
    //  fst_position = temp_new; // This WON'T change the 'head' pointer...
        *head = temp_new;        // ... but this will!
        return;
    }
    while (fst_position->ptr != NULL) {
        fst_position = fst_position->ptr;
    }
    fst_position->ptr = temp_new;
    // Here, we don't change the 'head' pointer, so its OK!
}

Примечание. Посмотрите на изменение, которое я внес в вашу строку отчетности по указателю: использование спецификатора формата %d для аргумента указателя является неопределенным поведением и вызовет все виды уродливых проблемы на платформах, где размер указателя не совпадает с размером int.

Примечание 2. Чтобы избежать предупреждений (и возможных ошибок) на строгих, соответствующих стандарту компиляторах, вы должны добавить void внутри Скобки для вашей createRecord функции, чтобы указать, что она не принимает параметров:

sNums* createRecord(void);

Без этого компилятор clang-cl (например) даст вам такой совет:

сообщение: это объявление не является прототипом; добавьте 'void', чтобы сделать его прототипом для функции с нулевым параметром

И, наконец:

Но он ничего не печатает.

Это потому, что вы никогда не звоните prinrecords! Добавьте вызов к вашей функции main:

int main(int argc, char const* argv[])
{
    sNums* head = NULL;
    printf("%p\n", (void*)(&head));// Keep format/agument cool!
    for (int i = 0; i < 3; ++i) {
        addRecords(&head);
    }
    prinrecords(head); // You forgot this!
    system("pause");
    return 0;
}
1 голос
/ 25 апреля 2020

Вы хотите, чтобы вносились минимальные изменения:

void addRecords(sNums** head){
  sNums* temp_new=createRecord();

  if (*head == NULL)
    *head = temp_new;
  else {
    sNums* fst_position = *head;

    while(fst_position->ptr!=NULL){
      fst_position=fst_position->ptr;
    }
    fst_position->ptr=temp_new; 
  }
}

иначе вы никогда не сохраните ни первую, ни следующую ячейки, потому что вы всегда начинаете с пустого списка, не изменяя его

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

typedef struct nums{
    int num;
    struct nums *ptr;
}sNums;

void addRecords(sNums** head);
sNums* createRecord();
void prinrecords(sNums* head);

int main(int argc, char const *argv[])
{
    sNums* head=NULL;

    for (int i = 0; i < 3; ++i)
    {
        addRecords(&head);
    }
    prinrecords(head);
    putchar('\n');
}

void prinrecords(sNums* head){
    while(head!=NULL){
        printf("{%d} ", head->num);
        head=head->ptr;
    }
}

void addRecords(sNums** head){
  sNums* temp_new=createRecord();

  if (*head == NULL)
    *head = temp_new;
  else {
    sNums* fst_position = *head;

    while(fst_position->ptr!=NULL){
      fst_position=fst_position->ptr;
    }
    fst_position->ptr=temp_new; 
  }
}

sNums* createRecord(){
    sNums *new=(sNums*)malloc(sizeof(sNums));
    printf("Enter Number: ");
    scanf("%d", &new->num);
    new->ptr=NULL;
    return new;
}

Компиляция и исполнение:

pi@raspberrypi:/tmp $ gcc -Wall a.c
pi@raspberrypi:/tmp $ ./a.out
Enter Number: 1
Enter Number: 2
Enter Number: 3
{1} {2} {3} 
pi@raspberrypi:/tmp $ 
...