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

Ниже приводится небольшой пример того, что я пытаюсь сделать. Функция loadData получает указатель на главный указатель, так что основному указателю может быть назначена часть памяти через malloc. Данные загружаются и печатаются в функции loadData. Но когда он возвращается в главное, он показывает только правильный контент для первого элемента массива структур. Второй пункт - мусор.

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

typedef struct
{ 
    int dni;
    char cat;
    int weight;
} boxers;

void loadData(boxers *(*xbox), int *xcount)
{
    printf("How many boxers? ");
    scanf("%d", xcount);

    *xbox = (boxers *) malloc(sizeof(boxers) * (*xcount));

    for (int i = 0; i < (*xcount); i++)
    {
        printf("Provide the DNI for boxer number %d: ", i);
        scanf("%d", &xbox[i]->dni);
        printf("Provide the Category for boxer number %d: ", i);
        scanf(" %c", &xbox[i]->cat);
        printf("Provide the Weight for boxer number %d: ", i);
        scanf("%d", &xbox[i]->weight);
    }

    // First print the result of data loading
    for (int i = 0; i < *xcount; i++)
    {
        printf("DNI for boxer number %d, is: %d \n", i, xbox[i]->dni);
        printf("Category for boxer number %d, is: %c \n", i, xbox[i]->cat);
        printf("Weight for boxer number %d, is: %d \n", i, xbox[i]->weight);
    }

}

int main()
{
    boxers *box;
    int count;

    loadData(&box, &count);

    // Second print the result of data loading
    printf("\n\n");
    for (int i = 0; i < count; i++)
    {
        printf("DNI for boxer number %d, is: %d \n", i, box[i].dni);
        printf("Category for boxer number %d, is: %c \n", i, box[i].cat);
        printf("Weight for boxer number %d, is: %d \n", i, box[i].weight);
    }

    free(box);
    
    return 0;
}

Вывод консоли следующий:

How many boxers? 2
Provide the DNI for boxer number 0: 123
Provide the Category for boxer number 0: A
Provide the Weight for boxer number 0: 45
Provide the DNI for boxer number 1: 789
Provide the Category for boxer number 1: B
Provide the Weight for boxer number 1: 56

DNI for boxer number 0, is: 123
Category for boxer number 0, is: A
Weight for boxer number 0, is: 45
DNI for boxer number 1, is: 789
Category for boxer number 1, is: B
Weight for boxer number 1, is: 56


DNI for boxer number 0, is: 123
Category for boxer number 0, is: A
Weight for boxer number 0, is: 45
DNI for boxer number 1, is: 7471203
Category for boxer number 1, is: x
Weight for boxer number 1, is: 7536756
0
Alejandro QA 11 Окт 2021 в 20:33

2 ответа

Лучший ответ

&xbox[i]->dni неверно. Возвращаемое значение из malloc было присвоено *xbox, поэтому *xbox указывает на память, а xbox указывает на этот указатель.

Итак, память находится в *xbox. Первая структура - это **xbox или, что эквивалентно, (*xbox)[0]. Следующая структура - (*xbox)[1] и так далее. Итак, вы хотите (*xbox)[i] для структуры с индексом i. Затем, поскольку это структура, а не указатель на нее, вам понадобится .dni, а не ->dni. Итак, этот участник - (*xbox)[i].dni. Тогда его адрес &(*xbox)[i].dni.

Напротив, поскольку xbox является указателем на указатель, тогда xbox[0] будет этим указателем, а xbox[1] будет указателем после него. Но после этого указателя нет; xbox просто указывает на единственный указатель. Итак, xbox[i] ошибается.

Такое же изменение необходимо и в других ссылках на элементы в подпрограмме.

Чтобы избежать этой простой ошибки, в подпрограммах, в которых передается указатель на указатель, можно определить локальный указатель, чтобы упростить ссылки:

void loadData(boxers **xbox, int *xcount)
{
    …
    boxers *p = *xbox = malloc(xcount * sizeof *p);
    …
        scanf("%d", &p[i]->dni);
    …
}
3
Eric Postpischil 11 Окт 2021 в 18:16

Эти задания

for (int i = 0; i < (*xcount); i++)
{
    printf("Provide the DNI for boxer number %d: ", i);
    scanf("%d", &xbox[i]->dni);
    printf("Provide the Category for boxer number %d: ", i);
    scanf(" %c", &xbox[i]->cat);
    printf("Provide the Weight for boxer number %d: ", i);
    scanf("%d", &xbox[i]->weight);
}

Неверны. Ты должен написать

for (int i = 0; i < (*xcount); i++)
{
    printf("Provide the DNI for boxer number %d: ", i);
    scanf("%d", &( *xbox )[i].dni);
    printf("Provide the Category for boxer number %d: ", i);
    scanf(" %c", &( *xbox )[i].cat);
    printf("Provide the Weight for boxer number %d: ", i);
    scanf("%d", &( *xbox )[i].weight);
}

А потом

for (int i = 0; i < *xcount; i++)
{
    printf("DNI for boxer number %d, is: %d \n", i, ( *xbox )[i].dni);
    printf("Category for boxer number %d, is: %c \n", i, ( *xbox )[i].cat);
    printf("Weight for boxer number %d, is: %d \n", i, ( *xbox )[i].weight);
}

Сравните приведенный выше цикл с этим циклом в main

for (int i = 0; i < count; i++)
{
    printf("DNI for boxer number %d, is: %d \n", i, box[i].dni);
    printf("Category for boxer number %d, is: %c \n", i, box[i].cat);
    printf("Weight for boxer number %d, is: %d \n", i, box[i].weight);
}

Разница в том, что в основном указатель box имеет тип boxers *, а в функции указатель xbox имеет тип boxers **. Поэтому вам нужно сначала разыменовать указатель в функции, такой как ( *xbox ), а затем применить оператор индекса, как вы делаете в main, например, ( *xbox )[i].weight

2
Vlad from Moscow 11 Окт 2021 в 19:45