Как передать точку 2D-массива другим функциям? - PullRequest
0 голосов
/ 02 августа 2020

У меня вопрос. Я хочу передать свой собственный 2D-массив функции pass. И в этой функции я изменю свой собственный массив. Итак, есть return. Что я точно знаю, так это то, что кодовый удар может быть принят компилятором. Но я не понимаю, почему это так. Когда я беру int (* aaa)[3]; из функции main, он работает хорошо, но когда он находится внутри main, возникает исключение, которое unable to use the uninitialized aaa. Интересно, почему это могло произойти.

int* pass(int (*a)[3]) {
    a=(int*)malloc(sizeof(int*)*2);
    a[0][1] = 1;
    a[0][2] = 2;
    return a;
}
int (* aaa)[3];
int main() {
    aaa = pass(aaa);
    printf("%d", aaa[0][2]);
}

это могло сработать.

int* pass(int (*a)[3]) {
    a=(int*)malloc(sizeof(int*)*2);
    a[0][1] = 1;
    a[0][2] = 2;
    return a;

}

int main() {
    int (* aaa)[3];
    aaa = pass(aaa);
    printf("%d", aaa[0][2]);
}

но это не сработает.

Ответы [ 2 ]

1 голос
/ 02 августа 2020

Когда int (* aaa)[3]; появляется вне какой-либо функции, он aaa автоматически инициализируется нулевым указателем. Когда он появляется внутри функции, он не инициализируется.

Код aaa = pass(aaa); передает aaa подпрограмме с именем pass. Это использование значения aaa. Когда aaa был инициализирован, это нормально. Но когда aaa не инициализирован и вы пытаетесь передать его значение, поведение не определяется стандартом C. Это то, о чем вас предупреждает компилятор.

Затем давайте рассмотрим этот код:

int* pass(int (*a)[3]) {
    a=(int*)malloc(sizeof(int*)*2);
    a[0][1] = 1;
    a[0][2] = 2;
    return a;
}

Этот код никогда не использует значение a, которое ему передается. Когда функция вызывается, ее параметру, в данном случае a, присваивается значение (которое получается из аргумента, переданного вызывающей стороной). Этот параметр является отдельной переменной от аргумента. Присвоение a значения с помощью a=(int*)malloc(sizeof(int*)*2); не изменяет значение aaa в вызывающей подпрограмме. Таким образом, этот код присваивает новое значение a без использования старого значения.

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

int (*pass(void))[3] {
    int (*a)[3] = malloc(2 * sizeof *a);
    a[0][1] = 1;
    a[0][2] = 2;
    return a;
}

void в этом случае означает, что pass не принимает никаких аргументов.

Обратите внимание, что я изменил * С 1031 * на malloc(2 * sizeof *a). sizeof(int*)*2 неверно, потому что он запрашивает место для двух указателей на int. Но a указывает на массивы из трех int, поэтому, чтобы получить два из них, вам нужно место для двух массивов из трех int. Это 2 * sizeof(int [3]). Однако проще записать это как malloc(2 * sizeof *a), что означает «два из того, на что указывает a». Это также лучше, потому что снижает частоту, с которой совершаются ошибки: даже если объявление a изменено, это sizeof *a будет автоматически корректироваться без необходимости редактирования. С sizeof(int [3]) любое редактирование объявления a потребует другого редактирования sizeof.

Кроме того, я удалил (int*), чтобы привести результат malloc. В C void *, который является типом, возвращаемым malloc, будет автоматически преобразован в любой тип указателя объекта, которому он назначен. Нет необходимости в явном приведении, а использование явного приведения может замаскировать определенные ошибки. (Однако, если вы скомпилируете программу с помощью компилятора C ++, он будет жаловаться на отсутствие преобразования, потому что правила в C ++ другие.)

Поскольку функция возвращает указатель на массив из трех int, а не указатель на int, я изменил его объявление на int (*pass(void))[3].

С этими изменениями программа могла быть:

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

int (*pass(void))[3]
{
    int (*a)[3] = malloc(2 * sizeof *a);
    a[0][1] = 1;
    a[0][2] = 2;
    return a;
}

int main(void)
{
    int (*aaa)[3] = pass();
    printf("%d\n", aaa[0][2]);
}
0 голосов
/ 02 августа 2020

может быть, это немного поможет вам увидеть, что C является «гибким», когда дело доходит до массивов.
Потому что в первой части предполагаемое объявление массива дается datalen в mallo c функции initAAA и возвращает указатель на выделенную память. И все же в for l oop мы можем получить доступ к данным с помощью индекса.

Вторая часть main объявляет только те же данные 'bbb', что и первые 'aaa', но на этот раз not как указатель, и начало полей данных с нулями (0) выполняется с помощью фигурных скобок. {}. Скука для l oop через все индексы и установка каждого поля данных с int 0 тоже будет делать это. Но кому нужно больше кода, чем нужно.

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

int *initAAA(int *p, uint entrys) {
    size_t datalen = entrys * sizeof *p;
    p = malloc(datalen); // p is a pointer here.
    // copy character '0' starting at address of p up to datalen addresses
    // easier then writing a for loop to initiate safely.
    memset(p, 0, datalen);  // defined in string.h
    return p;
}

int main(void) {
    const uint maxAssets = 3;
    const uint entrysPerAsset = 2;
    int *aaa = NULL; // always a good idea, to set pointers to NULL before allocating memory for it. Because you can check if (aaa==NULL) initAAA(...
    uint entrys = maxAssets * entrysPerAsset;
    aaa = initAAA(aaa,entrys);
    printf("address:%p items:%d \n",aaa, entrys);
    for (uint i = 0; i < entrys; i++) {
        printf("%d ", aaa[i]);
    }
    free(aaa); // malloc without free, bad idea!

    printf("\n---\n");
    
    int bbb[maxAssets][entrysPerAsset] = {0,0,0,0,0,0};
    for (uint a = 0; a < maxAssets; a++) {
        for (uint e = 0; e < entrysPerAsset; e++) {
            printf("%d ", bbb[a][e]);
        }
    }
    // bbb does not need free(bbb); because it is released with the function end.
    // and yep, there was no malloc for bbb. so we are done.
}

и кстати. добро пожаловать в C.

...