C指向结构问题-当“*”位于结构的变量之前时,它是什么意思?

C指向结构问题-当“*”位于结构的变量之前时,它是什么意思?,c,pointers,struct,C,Pointers,Struct,下面有一个简单的代码,询问姓氏,以及5个人的2个等级。它也 查找所有等级的平均值以及谁的等级较高。问题是关于*符号 我的教授正在调用一个名为readstudentstudent*pstu的函数; pstu之前的*是什么意思,为什么有必要 另外,当我们通过ReadStudentStudent*pstu时,为什么一年级和二年级有&而名字没有- #include <stdio.h> #include <string.h> typedef struct student {

下面有一个简单的代码,询问姓氏,以及5个人的2个等级。它也 查找所有等级的平均值以及谁的等级较高。问题是关于*符号

我的教授正在调用一个名为readstudentstudent*pstu的函数; pstu之前的*是什么意思,为什么有必要

另外,当我们通过ReadStudentStudent*pstu时,为什么一年级和二年级有&而名字没有-

#include <stdio.h>
#include <string.h>
typedef struct student
{
    char name[20];
    float grade1;
    float grade2;
} TStudent;



void readstudent( TStudent *pstu );
void printstudent( TStudent stu );
int main( void )
{
int N = 5;
        TStudent a[N]; int i, imax; float max, mo, sum;
    for(i=0; i<N; i++)
        readstudent( &a[i] );
        printf("\n Oi karteles twn foitntwv einai:\n");
    for(i=0; i<N; i++)
        printstudent( a[i]);
        sum = 0;
    for(i=0; i<N; i++)
        sum = sum + (a[i].grade1+a[i].grade2)/2;
        mo = (float)sum / N;
        printf("\nO mesos oros bathmologias tns taksns einai %2.2f\n", mo);
        imax = 0;
        max = (a[0].grade1+a[0].grade2)/2;
    for(i=0; i<N; i++)
        if ((a[i].grade1+a[i].grade2)/2 > max)
        {   
            max = (a[i].grade1+a[i].grade2)/2;
            imax = i;
        }
printf("\nO/H foitntns/tria me ton ypsnlotero meso oro (%4.2f) einai o/h %s.\n", max, a[imax].name);
return 0;
}

void readstudent( TStudent *pstu)
{
printf("Eisagwgh foitntn/trias: epwnymo <keno> bathmos1 <keno> bathmos2 <keno>: \n");
    scanf("%s", pstu->name);
    scanf("%f", &pstu->grade1);
    scanf("%f", &pstu->grade2);
}
void printstudent( TStudent stu)
{
    printf("Epwnymo: %s\n", stu.name);
    printf("Bathmos-1: %4.2f\n", stu.grade1);
    printf("Bathmos-2: %4.2f\n", stu.grade2);
}
感谢您的时间,感谢您的帮助

*在不同的上下文中表示不同的事物。请记住,C和C++是上下文相关语言。 当你声明一个变量时,比如;int*foo;*表示foo是指向int的指针

当您编写printf%d这样的语句时,*foo;*表示取消引用存储在foo中的指针,并给我它指向的int值

在函数声明(如void fint*bar)中使用时,表示函数接受指向整数的指针作为其参数

它也可以表示乘法,比如int something=baz*42


或者它可以只是一个普通的字符,在一个字符的文字,没有特殊的意义。比如常量char[]foo=bar*baz*

我先回答一个稍微不同的问题;但是相关的。 什么是学生,学生stu;是吗

答案是它复制了一份论点的副本,然后用它做了些什么。 通过复制数据;无法编辑最初传入的内容

现在我们来看看void readstudent TStudent*pstu;做:

它获取指向某个数据的指针的副本。这将允许它编辑所指向的数据


正如Jesper所说;*还有许多其他用途;但是,这些是理解这种用法所需要知道的基本知识,所以,C语言指针速成课程

首先,为什么我们在C中使用指针?基本上,我们必须使用指针,原因如下:

允许函数修改其参数的步骤 跟踪动态分配的内存 指针在其他方面也很有用,因为它们提供了一种间接方式。它们允许我们操纵其他对象,而不必知道其他对象的名称

间接寻址是编程中一个强大的工具,如果您已经处理过数组,那么您已经看到了它。我们可以创建一个整数数组,并使用下标来引用特定对象,而不是创建100个唯一的整数变量。也就是说,不是写作

int var0 = 0;
int var1 = 1;
int var2 = 2;
...
int var99 = 99;
我们可以写作

int var[100];

for ( int i = 0; i < 100; i++ )
  var[i] = i;
让我们从玩x开始。我们使用运算符的一元和地址将p设置为指向x:

p = &x; // int * = int *
*p = 15; // int = int
变量p的类型为int*。表达式&x的类型是int*,表达式的值是x的地址。然后,我们可以使用一元*间接运算符更改x到p的值:

p = &x; // int * = int *
*p = 15; // int = int
因为变量p的类型是int*,所以表达式*p的类型是int,并且该表达式指定与表达式x相同的对象。在上面的一行中,我们通过p间接地改变存储在x中的值。我们可以用y和z做同样的事情:

好的,很酷,但是为什么不直接分配给x,y和z呢?为什么要经历将地址分配给p和通过*p分配值的痛苦

通常我们不会这样做,但有一种情况是无法避免的。假设我们要编写一个函数来修改其一个或多个参数的值,如下所示:

void foo( int x )
{
  x = 2 * x;
}
这样称呼它:

int main( void )
{
  int val = 2;
  printf( "before foo: %d\n", val );
  foo( val );
  printf( "after foo: %d\n", val );
  return 0;
}
我们想看到的是

before foo: 2
after foo: 4
但我们得到的是

它不起作用,因为C使用了一种称为“按值传递”的参数传递约定-简而言之,函数定义中的形式参数x在内存中指定了一个独立于实际参数val的对象。将新值写入x不会影响val。为了让foo修改实际参数val,我们必须传递一个指向val的指针:

现在我们得到了我们期望的输出-val由foo修改。表达式*x引用的对象与val所引用的对象相同。现在我们可以写这样的东西

 foo( &y );   // x == &y, *x == y
 foo( &z );   // x == &z, *x == z
这是我们的第一个用例-允许函数修改其参数

在程序执行过程中,有时需要分配一些额外的内存。由于此分配发生在运行时,因此无法像对常规变量那样为该额外内存指定名称。瞧,没办法写了

int x = new_memory();
因为变量名在运行时不存在,所以它们不会保留在生成的机器代码中。同样,我们必须通过指针间接引用这个动态分配的内存:

int *p = malloc( sizeof *p ); sizeof *p == sizeof (int)
这为单个int对象分配了足够的空间,并将新空间的地址分配给p。您可以分配任意大小的块:

int *arr = malloc( sizeof *arr * 100 );
为100个int对象分配足够的空间,并将arr设置为指向 第一个

这是我们的第二个用例跟踪动态分配的内存

关于指针语法的简要说明。有两个运算符与指针操作关联。一元运算符&用于获取对象的地址,而一元运算符*取消对指针的引用。假设我们有一个名为x的int对象和一个名为p的int指针:

在声明中,一元*表示被声明的对象具有指针类型:

int *p; // p has type "pointer to int"
在声明中初始化指针时,如

int *p = &x;
char foo[] = "test";
p没有被取消引用。这和写作是一样的

int *p;
p = &x;
*运算符绑定到被声明的对象,而不是类型说明符。您可以编写与相同的声明

int* p;
int       *         p;
int*p;
它将始终解析为int*p

对于任何类型的T,以下是正确的:

 T *p;          // p has type "pointer to T"
 T *p[N];       // p has type "array of pointers to T"
 T (*p)[N];     // p has type "pointer to array of T"
 T *p();        // p has type "function returning pointer to T"
 T (*p)();      // p has type "pointer to function returning T"
复杂的指针声明可能很难读取,因为一元*是前缀运算符,其优先级低于[]和运算符。例如:

T *(*(*foo)())[N];
foo是指向函数的指针,该函数返回指向指向T的指针的N元素数组的指针

对于您的代码,我们正在处理第一种情况-我们希望readstudent函数修改struct student的现有实例的内容。readstudent通过调用scanf将值读入每个单独的成员来实现这一点:

scanf("%s", pstu->name); 
scanf("%f", &pstu->grade1);
scanf("%f", &pstu->grade2);
请记住,scanf希望它的参数是指针——同样,我们试图修改对象的内容,因此必须将指向该对象的指针作为参数传递

&pstu->grade1计算为pstu指向的对象的grade1成员的地址&pstu->grade2计算为pstu指向的对象的grade2成员的地址

pstu->name到底是怎么回事

数组在C中是特殊的。除非它是sizeof或一元&运算符的操作数,或者是用于在字符声明中初始化数组的字符串文字,如

int *p = &x;
char foo[] = "test";
N元素数组类型为T的表达式将转换为指向T的指针类型的表达式,表达式的值将是数组第一个元素的地址


我们不会就此进行深入讨论,但这是Ritchie在第一次创建C语言时深思熟虑的设计决定,它确实起到了一定的作用。这还意味着数组在大多数情况下都会失去其数组属性,最终处理的实际上是指向第一个元素的指针,而不是整个数组本身。在scanf调用的情况下,我们传递的是等价的&pstu->name[0]

我有点担心你为什么要调用函数子程序。这是一个函数。请允许我指出,这可能对你帮助,甚至不是C++。但是legacy C.我担心你知道涉及指针,但你仍然不知道*在这里意味着什么。你的教授根本没有复习过基本的指针语法吗?@Chris那么我担心你知道涉及函数,但你仍然不知道函数是如何工作的。添加关于scanf for float成员的答案。因此,上述所有问题的答案都将是完整的。感谢您的帮助,先生!非常感谢你的解释。
char foo[] = "test";