指针和 typedef 结构,在 C 中调用函数时要做什么
Pointers and typedef structs, what to do when you call a function in C
我有一个程序必须使用 ShowMe (int *p)
并且在调用主函数时需要从 typedef Pyramid A 中提取值。
这是 typedef 结构声明
typedef struct _Pyramid
{
double element [N][N];
} Pyramid;
我遇到了不兼容的错误,我知道它们不是同一类型。我试过试镜,但被告知我不能那样做。
我已经尝试了所有我目前知道的方法来让它工作。那么我如何调用 main 中的 function ShowMe (int *p)
并将金字塔 A 的值传递给它呢?
如果被问到,我会 post 代码。但是我厌倦了被告知我做错了什么(我大部分时间已经从错误中弄清楚了)而没有任何关于正确做事的指导。我再强调一下。我是 C 的新手,我很累,在我 post 之前已经做了几天多的事情。
#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
将类型 Pyramid*
转换为 int*
将违反严格的别名规则,并可能导致一些未定义的行为。为 ShowMe() 传递 char*
而不是 int*
是一种可能的解决方法,因为 char 指针是严格别名规则的一个例外。有关详细信息和解决方法,请查看 this post.
您的绊脚石更多是关于将结构作为参数处理。结构只是 C 中的一种数据类型。它像任何其他数据类型(int
、long
、char
等)一样作为参数传递,并遵循相同的规则。
typedef
的便利性允许您将参数指定为 Pyramid var
,而不必像没有它时那样使用完整的 struct Pyramid var
。事实上,在使用 typedef
时,您甚至不需要结构的 _Pyramid
名称,例如
typedef struct { /* you can simply typedef a struct */
double stone [N][N];
} pyramid_t;
上面的 typedef
只是将一个包含双精度数组的未命名结构别名为 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
[=37] 输出值=] 函数中的运算符,例如
/* 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() */
(注意: 该函数接收结构的副本——因此请尝试更改一些数组值,然后在 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()
中传递指向您的结构的指针,您只需使用一元 '&'
运算符( 的地址)传递[的地址=46=],例如
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]);
...
}
并且,如上所述,您只需使用 a
的地址调用 showme()
,例如
showme (&a); /* pass pointer to prevent duplicating struct */
在任何一种情况下,输出都是相同的,例如
例子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
仔细查看并了解差异,如果您有其他问题,请告诉我。
脚注:
[1] 虽然不是错误,但 C 风格通常避免使用 MixedCase
或 camelCase
变量以及使用全大写的名称(为常量或宏保留所有大写名称),而不是使用所有小写的变量名称。虽然这是风格问题,完全取决于您,但在某些设置中可能会导致错误的第一印象。
我有一个程序必须使用 ShowMe (int *p)
并且在调用主函数时需要从 typedef Pyramid A 中提取值。
这是 typedef 结构声明
typedef struct _Pyramid
{
double element [N][N];
} Pyramid;
我遇到了不兼容的错误,我知道它们不是同一类型。我试过试镜,但被告知我不能那样做。
我已经尝试了所有我目前知道的方法来让它工作。那么我如何调用 main 中的 function ShowMe (int *p)
并将金字塔 A 的值传递给它呢?
如果被问到,我会 post 代码。但是我厌倦了被告知我做错了什么(我大部分时间已经从错误中弄清楚了)而没有任何关于正确做事的指导。我再强调一下。我是 C 的新手,我很累,在我 post 之前已经做了几天多的事情。
#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
将类型 Pyramid*
转换为 int*
将违反严格的别名规则,并可能导致一些未定义的行为。为 ShowMe() 传递 char*
而不是 int*
是一种可能的解决方法,因为 char 指针是严格别名规则的一个例外。有关详细信息和解决方法,请查看 this post.
您的绊脚石更多是关于将结构作为参数处理。结构只是 C 中的一种数据类型。它像任何其他数据类型(int
、long
、char
等)一样作为参数传递,并遵循相同的规则。
typedef
的便利性允许您将参数指定为 Pyramid var
,而不必像没有它时那样使用完整的 struct Pyramid var
。事实上,在使用 typedef
时,您甚至不需要结构的 _Pyramid
名称,例如
typedef struct { /* you can simply typedef a struct */
double stone [N][N];
} pyramid_t;
上面的 typedef
只是将一个包含双精度数组的未命名结构别名为 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
[=37] 输出值=] 函数中的运算符,例如
/* 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() */
(注意: 该函数接收结构的副本——因此请尝试更改一些数组值,然后在 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()
中传递指向您的结构的指针,您只需使用一元 '&'
运算符( 的地址)传递[的地址=46=],例如
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]);
...
}
并且,如上所述,您只需使用 a
的地址调用 showme()
,例如
showme (&a); /* pass pointer to prevent duplicating struct */
在任何一种情况下,输出都是相同的,例如
例子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
仔细查看并了解差异,如果您有其他问题,请告诉我。
脚注:
[1] 虽然不是错误,但 C 风格通常避免使用 MixedCase
或 camelCase
变量以及使用全大写的名称(为常量或宏保留所有大写名称),而不是使用所有小写的变量名称。虽然这是风格问题,完全取决于您,但在某些设置中可能会导致错误的第一印象。