简体   繁体   English

指针和typedef结构,在C中调用函数时该怎么做

[英]Pointers and typedef structs, what to do when you call a function in C

I have a program that has to use ShowMe (int *p) and from the main function when it is called it needs to pull the values out of typedef Pyramid A. this is the typedef struct declaration 我有一个必须使用ShowMe (int *p)的程序,调用它时需要从main函数中将值从typedef Pyramid A中拉出。这是typedef结构声明

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

I have gotten incompatible errors, I understand they're not the same type. 我遇到了不兼容的错误,我知道它们不是同一类型。 I have tried casting and have been told I can't do that. 我已经尝试过投放,但被告知无法这样做。 I have tried every-way I'm currently aware of to get this to work. 我已经尝试了我目前知道的所有方法来使它起作用。 So how would I call the function ShowMe (int *p) in main and pass it the values of Pyramid A? 那么我该如何在main中调用function ShowMe (int *p)并将金字塔A的值传递给它呢? I will post the code if asked. 如果需要,我将发布代码。 But I'm tired of being told what I'm doing wrong (which I mostly had already figured out from the errors) without any direction on what to do right. 但是我厌倦了被告知自己在做错什么(我大多数人已经从错误中弄清楚了),却没有任何正确方法的指导。 I will emphasize again. 我会再次强调。 I'm new to C and I'm very tired and have worked on something for more than a couple of days before I post. 我是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

Casting the type Pyramid* as an int* will violate the strict aliasing rule and could cause some undefined behaviors. Pyramid*类型转换为int*将违反严格的别名规则,并可能导致某些未定义的行为。 Passing a char* instead of an int* for ShowMe() is a possible workaround, since char pointers are an exception to the strict aliasing rule. 为ShowMe()传递char*而不是int*是一种可能的解决方法,因为char指针是严格的别名规则的例外。 For more information and workarounds, check this post . 有关更多信息和解决方法,请查看此文章

Your stumbling block is more about handling the struct as a parameter. 您的绊脚石更多是关于将结构作为参数进行处理的。 A struct is simply a data type in C. It is passed as a parameter just as any other data type ( int , long , char , etc...) and follows the same rules. struct只是C中的一种数据类型。它像其他任何数据类型( intlongchar等)一样作为参数传递,并遵循相同的规则。

The convenience of a typedef allows you to specify the parameter as Pyramid var rather than having to use the full struct Pyramid var as you would without it. typedef的便利性使您可以将参数指定为Pyramid var而不必像不使用它一样使用完整的struct Pyramid var In fact, you don't even need the _Pyramid name for the struct when using a typedef , eg 实际上,当使用typedef ,甚至不需要_Pyramid作为结构名称,例如

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

Above, the typedef simply aliases an unnamed struct containing an array of doubles to the pyramid_t name, which you can use in declaring instances of the struct, eg 上面, 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}}};

Whether you include _Pyramid or not is up to you. 是否包含_Pyramid由您决定。 (without it, you simply lose the ability to refer to struct _Pyramid as a declared type). (如果没有它,您将简单地失去将struct _Pyramid为声明的类型的能力)。

Your declaration of int data[N*N]; 您声明的int data[N*N]; is a red-herring, a distraction of no consequence that isn't relevant to what you are attempting to do. 是一条红色的鲱鱼,与您尝试执行的操作无关的任何干扰。 You initialize an instance of your struct in main() . 您可以在main()初始化struct的实例。 You simply need to pass the struct (or better, a pointer to your struct) to your showme [1] function in order to have the values available for printing there. 您只需要将结构(或更好的是,指向结构的指针)传递给showme [1]函数,以使值可用于在那里打印。

For example, including the typedef to specify you are passing the struct as a parameter (where the function receives a copy of the struct) you output the values using the dot '.' 例如,包括typedef以指定您将结构作为参数传递(函数将在其中接收结构的副本),您将使用dot '.'输出值'.' operator as you have in your function, eg 您在功能中使用的运算符,例如

/* 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 */
    }
}

You would then call your function in main() as: 然后,您可以在main()以以下方式调用函数:

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

( note: the function receives a copy of the struct -- so try changing some of the array values and then print the contents again back in main() ... any changes made are lost) 注意:该函数接收到该结构的副本-因此,请尝试更改一些数组值,然后再次将内容打印回main() ...所做的任何更改都将丢失)

A more efficient way of passing the struct would be to pass a pointer to the struct, so that all that is being passed is the address of where the structure is stored in memory. 传递该结构的一种更有效的方法是传递一个指向该结构的指针,以便所传递的只是结构在内存中存储的地址。 Not only does that avoid making a copy of the struct, but by passing the address, any changes you make to the structure values are then preserved (because you are directly changing the values of the original struct in memory -- not simply making changes to a copy). 这样不仅避免了复制结构,而且通过传递地址,您对结构值所做的任何更改都将保留下来(因为您直接在内存中更改了原始结构的值,而不仅仅是更改了复印件)。 When you pass a pointer to a struct (or anytime you are accessing values of a struct through a pointer), you use the arrow operator ( -> ) to access the struct members. 当您将指针传递给结构时(或任何时候通过指针访问结构的值),都可以使用arrow operator-> )访问结构成员。 For example, you could have just as easily have declared showme() to take a pointer to pyramid_t instead of a struct, eg 例如,您可以很容易地声明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 */
    }
}

To pass a pointer to your struct in main() , you simply use the unary '&' operator ( address of ) to pass the address of a , eg 将指针传递到你的结构main()您只需使用一元'&'运营商( 地址 )来传递的地址a ,如

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

Now if you made changes to the array values in the function, the changes would be visible back in main() because you changed the values where they were stored in memory rather than operating on a copy passed to the function. 现在,如果您对函数中的数组值进行了更改,则这些更改将在main()可见,因为您更改了存储在内存中的值,而不是对传递给函数的副本进行操作。

Look at both examples and understand the differences both in declaring the showme() function and how it is called in main() . 查看这两个示例,并了解在声明showme()函数以及在main()如何调用它的区别。 The first example passing a copy of the struct and using the dot-operator to access the member would be: 第一个传递该结构的副本并使用点运算符访问该成员的示例为:

#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 */

}

To pass a pointer containing the address of the original struct, you would simply change the declaration of showme() and the operator used to access the struct members: 要传递包含原始结构的地址的指针,只需更改showme()的声明和用于访问结构成员的运算符:

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

And, as explained above, you would simply call showme() with the address of a , eg 而且,如上所述,您只需拨打showme()与地址a ,如

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

In either case the output would be the same, eg 无论哪种情况,输出都是相同的,例如

Example Use/Output 使用/输出示例

> 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

Look things over and understand the differences, and let me know if you have further questions. 仔细研究一下,了解它们之间的差异,如果还有其他问题,请告诉我。

footnotes: 脚注:

[1] While not an error, C style generally avoids the use of MixedCase or camelCase variables and the use of all-uppercase names (reserving all uppercase names for constants or macros), instead using variables names of all lowercase. [1]尽管不是错误,但C样式通常避免使用MixedCasecamelCase变量,而避免使用全大写的名称(为常量或宏保留所有大写的名称),而不是使用所有小写的变量名称。 While this is an issue of style, and completely up to you, it can lead to the wrong first-impressions in some settings. 虽然这是样式问题,完全由您决定,但在某些情况下可能导致错误的第一印象。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM