Указатели и typedef структуры, что делать, когда вы вызываете функцию в C - PullRequest
0 голосов
/ 30 сентября 2018

У меня есть программа, которая должна использовать ShowMe (int *p), и из основной функции, когда она вызывается, ей нужно извлечь значения из пирамиды typedef A. Это объявление структуры typedef

typedef struct _Pyramid
{
double element [N][N];
} Pyramid;

Я получил несовместимые ошибки, я понимаю, что они не одного типа.Я пробовал кастинг, и мне сказали, что я не могу этого сделать.Я пытался всеми способами, которые я в настоящее время знаю, чтобы заставить это работать.Итак, как бы я назвал function ShowMe (int *p) в основном и передать ему значения пирамиды А?Я отправлю код, если спросят.Но я устал от того, что мне говорят, что я делаю неправильно (что я в основном уже выяснил из ошибок) без какого-либо указания, что делать правильно.Я еще раз подчеркну.Я новичок в C, и я очень устал и работал над чем-то больше, чем за пару дней до публикации.

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

#define N 8

typedef struct _Pyramid{
double stone [N][N];
} Pyramid;



int data[N*N];



Pyramid ShowMe(int *p)  // pass in data and return Pyramid
 {
      int i;
      int j; 
        for (i=0; i<N; i++)
        {
            for (j=0; j<N; j++)
            {
                printf("%g ", a.stone[i][j]);
            }//Inner for
            printf("\n");
        }//Outer For
 }//IZZ




int main(int argc, char **argv)
{
    // special case that allows us to initialize this way
    Pyramid A =    {10,  4, 2,  5, 1, 0, 0, 0,
                    3,  9, 1,  2, 1, 0, 0, 0,
                   -7, -5, 1, -2, -1, 0, 0, 0,
                   -3, -5, 0, -1, 0, 0, 0, 0,
                   -2,  1, 0,  0, 0, 0, 0, 0,
                    0,  0, 0,  0, 0, 0, 0, 0,
                    0,  0, 0,  0, 0, 0, 0, 0,
                    0,  0, 0,  0, 0, 0, 0, 0};





    ShowMe(int *A);


}//main

Ответы [ 2 ]

0 голосов
/ 30 сентября 2018

Ваш камень преткновения больше относится к обработке структуры как параметра.Структура - это просто тип данных в C. Она передается как параметр, как и любой другой тип данных (int, long, char и т. Д.), И следует тем же правилам.

Удобство typedef позволяет вам указать параметр как Pyramid var, вместо того, чтобы использовать полный struct Pyramid var, как без него.На самом деле, вам даже не нужно имя _Pyramid для структуры при использовании typedef, например

typedef struct {    /* you can simply typedef a struct */
    double stone [N][N];
} pyramid_t;

Выше, typedef просто псевдоним неназванной структуры, содержащей массив значений типа doubleна имя pyramid_t, которое вы можете использовать при объявлении экземпляров структуры, например,

    /* explicit way to initilize 2D array as 1st member of struct */
    pyramid_t a = {{{10,  4, 2,  5,  1, 0, 0, 0},
                    { 3,  9, 1,  2,  1, 0, 0, 0},
                    {-7, -5, 1, -2, -1, 0, 0, 0},
                    {-3, -5, 0, -1,  0, 0, 0, 0},
                    {-2,  1, 0,  0,  0, 0, 0, 0},
                    { 0,  0, 0,  0,  0, 0, 0, 0},
                    { 0,  0, 0,  0,  0, 0, 0, 0},
                    { 0,  0, 0,  0,  0, 0, 0, 0}}};

Независимо от того, включаете вы _Pyramid или нет, зависит от вас.(без этого вы просто теряете возможность ссылаться на struct _Pyramid как на объявленный тип).

Ваша декларация int data[N*N]; - это «красная сельдь», отвлечение, которое не имеет никакого отношения кчто вы пытаетесь сделать.Вы инициализируете экземпляр вашей структуры в main().Вам просто нужно передать структуру (или, точнее, указатель на вашу структуру) в вашу функцию showme [1] , чтобы значения там были доступны для печати. ​​

ДляНапример, включая typedef, чтобы указать, что вы передаете структуру в качестве параметра (где функция получает копию структуры), вы выводите значения, используя оператор dot '.', как в вашей функции, например,

/* function type is void if it returns no value */
void showme (pyramid_t p)
{
    int i, j; 

    for (i = 0; i < N; i++) {
        for (j = 0; j < N; j++)
            printf("%3g ", p.stone[i][j]);
        putchar('\n');  /* use putchar() to output single char */
    }
}

Затем вы вызываете свою функцию в main() как:

    showme (a);     /* passing a copy of the struct to showme() */

( note: функция получает копию структуры - так что попробуйтеизменив некоторые значения массива, а затем снова напечатайте содержимое обратно в main() ... все сделанные изменения будут потеряны)

Более эффективный способ передачи структуры - передача указателя на структуру,так что все, что передается, это адрес того, где структура хранится в памяти.Это не только предотвращает создание копии структуры, но и путем передачи адреса все изменения, которые вы вносите в значения структуры, затем сохраняются (потому что вы напрямую изменяете значения исходной структуры в памяти, а не просто вносите изменения вкопия).Когда вы передаете указатель на структуру (или в любое время, когда вы получаете доступ к значениям структуры через указатель), вы используете arrow operator (->) для доступа к членам структуры.Например, вы могли бы просто объявить showme(), чтобы взять указатель на pyramid_t вместо структуры, например,

/* function type is void if it returns no value */
void showme (pyramid_t *p)
{
    int i, j; 

    for (i = 0; i < N; i++) {
        for (j = 0; j < N; j++)
            printf("%3g ", p->stone[i][j]);
        putchar('\n');  /* use putchar() to output single char */
    }
}

Чтобы передать указатель на вашу структуру в main(), выпросто используйте унарный оператор '&' ( адрес ), чтобы передать адрес a, например,

    showme (&a);    /* pass pointer to prevent duplicating struct */

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

Посмотрите на оба примера и поймите различия как в объявленииshowme() функция и как она вызывается в main().Первый пример, передающий копию структуры и использующий оператор точки для доступа к члену:

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

#define N 8     /* good job - if you need a constant, #define one (or more) */

typedef struct {    /* you can simply typedef a struct */
    double stone [N][N];
} pyramid_t;

/* function type is void if it returns no value */
void showme (pyramid_t p)
{
    int i, j; 

    for (i = 0; i < N; i++) {
        for (j = 0; j < N; j++)
            printf("%3g ", p.stone[i][j]);
        putchar('\n');  /* use putchar() to output single char */
    }
}

int main (void) {   /* unless using argc, argv, use void */

    /* explicit way to initilize 2D array as 1st member of struct */
    pyramid_t a = {{{10,  4, 2,  5,  1, 0, 0, 0},
                    { 3,  9, 1,  2,  1, 0, 0, 0},
                    {-7, -5, 1, -2, -1, 0, 0, 0},
                    {-3, -5, 0, -1,  0, 0, 0, 0},
                    {-2,  1, 0,  0,  0, 0, 0, 0},
                    { 0,  0, 0,  0,  0, 0, 0, 0},
                    { 0,  0, 0,  0,  0, 0, 0, 0},
                    { 0,  0, 0,  0,  0, 0, 0, 0}}};

    showme (a);     /* passing a copy of the struct to showme() */

    return 0;       /* main() is type 'int' and returns a value */

}

Чтобы передать указатель, содержащий адрес исходной структуры, вы просто изменили бы объявлениеshowme() и оператор, используемый для доступа к членам структуры:

/* function type is void if it returns no value */
void showme (pyramid_t *p)
{
    ...
            printf("%3g ", p->stone[i][j]);
    ...
}

И, как объяснено выше, вы просто позвоните showme() с адресом a, например,

    showme (&a);    /* pass pointer to prevent duplicating struct */

В любом случае выходные данные будут одинаковыми, например,

Пример использования / Вывод

> bin\pyramid-struct.exe
 10   4   2   5   1   0   0   0
  3   9   1   2   1   0   0   0
 -7  -5   1  -2  -1   0   0   0
 -3  -5   0  -1   0   0   0   0
 -2   1   0   0   0   0   0   0
  0   0   0   0   0   0   0   0
  0   0   0   0   0   0   0   0
  0   0   0   0   0   0   0   0

Посмотрите вещи и поймите различия, и позвольте мнезнать, если у вас есть дополнительные вопросы.

сноски:

[1] Хотя стиль С не является ошибкой, он обычно избегает использования переменных MixedCase или camelCase и использования имен в верхнем регистре (резервируя все имена в верхнем регистре для констант или макросов)., вместо того, чтобы использовать имена переменных всех строчных.Хотя это вопрос стиля и полностью зависит от вас, он может привести к неправильным первым впечатлениям при некоторых настройках.

0 голосов
/ 30 сентября 2018

Преобразование типа Pyramid* в int* нарушит правило строгого псевдонима и может привести к неопределенному поведению.Передача char* вместо int* для ShowMe () является возможным обходным путем, поскольку указатели на символы являются исключением из строгого правила псевдонимов.Для получения дополнительной информации и обходных путей, проверьте этот пост .

...