C语言 用于通过指针访问结构数组变量的每个元素的代码

kse8i1jr  于 2023-02-07  发布在  其他
关注(0)|答案(3)|浏览(132)

在以下行中:

struct student *ptr = NULL;

为什么ptr设置为NULL??有人能告诉我吗?

#include <stdio.h>

int main(void) {
    
  // student structure
  struct student {
    char id[15];
    char firstname[64];
    char lastname[64];
    float points;
  };
  
  // student structure variable
  struct student std[3];
  
  // student structure pointer variable
  struct student *ptr = NULL;
  
  // other variables
  int i;
  
  // assign std to ptr
  ptr = std;
  
  // get detail for user
  for (i = 0; i < 3; i++) {
    printf("Enter detail of student #%d\n", (i + 1));
    printf("Enter ID: ");
    scanf("%s", ptr->id);
    printf("Enter first name: ");
    scanf("%s", ptr->firstname);
    printf("Enter last name: ");
    scanf("%s", ptr->lastname);
    printf("Enter Points: ");
    scanf("%f", &ptr->points);
    
    // update pointer to point at next element
    // of the array std
    ptr++;
  }
  
  // reset pointer back to the starting
  // address of std array
  ptr = std;
  
  for (i = 0; i < 3; i++) {
    printf("\nDetail of student #%d\n", (i + 1));
      
    // display result via std variable
    printf("\nResult via std\n");
    printf("ID: %s\n", std[i].id);
    printf("First Name: %s\n", std[i].firstname);
    printf("Last Name: %s\n", std[i].lastname);
    printf("Points: %f\n", std[i].points);
  
    // display result via ptr variable
    printf("\nResult via ptr\n");
    printf("ID: %s\n", ptr->id);
    printf("First Name: %s\n", ptr->firstname);
    printf("Last Name: %s\n", ptr->lastname);
    printf("Points: %f\n", ptr->points);
    
    // update pointer to point at next element
    // of the array std
    ptr++;
  }
  
  return 0;
}
2w2cym1i

2w2cym1i1#

在发布的程序中,初始化为NULL是可选的。您可以删除它,程序将完全等效。

struct student *ptr = NULL;
  int i;
  ptr = std;

完全等价于

struct student *ptr;
  int i;
  ptr = std;

并且还

struct student *ptr = std;
  int i;

初始化变量的原因是"健壮性",而不是正确性,健壮性是关于最小化当你改变程序时出错的风险。
假设你修改了程序,不小心删除了ptr = std;这一行,由于NULL的初始化,当ptr在for循环中使用时,它将是一个空指针,如果你的程序崩溃或出现其他问题,你可以在编译时禁用优化,然后在调试器中运行它。然后,你会可靠地看到它在"如果ptr没有被初始化,那么它的行为可能是任何的,这取决于当时内存中发生了什么,并且它可能无法从一次执行到下一次执行重现,所以很难找到这个bug。
在这个例子中,没有什么强有力的理由让我们更喜欢初始化为NULL而不是直接设置ptr = std。出于不同的原因,这两种方法都可以被认为是很好的卫生措施。将所有指针初始化为null是很好的,因为这是一个简单的规则,而且它将枯燥的初始化过程分开了(你不需要太注意)从有趣的计算中。另一方面,直接将ptr初始化为它所需要的值是很好的,因为它最小化了发生的事情的数量。

rm5edbpk

rm5edbpk2#

NULL对指针的初始化

// student structure pointer variable
struct student *ptr = NULL;

是多余的。
您可以通过其声明中的结构数组的第一个元素来初始化它,如

// student structure pointer variable
struct student *ptr = std;

代码的作者用NULL初始化指针,因为他不想声明一个未初始化的指针,并且程序中的指针至少被重新分配了两次。
所以看起来他想把指针的声明分开,并用std赋值给它。
此外,由于指针仅在for循环中使用,因此最好在for循环语句中声明它,例如

for ( struct student *ptr = std; ptr != std + 3; ++ptr ) {
    printf("Enter detail of student #%d\n", (i + 1));
    printf("Enter ID: ");
    scanf("%14s", ptr->id);
    printf("Enter first name: ");
    scanf("%63s", ptr->firstname);
    printf("Enter last name: ");
    scanf("%63s", ptr->lastname);
    printf("Enter Points: ");
    scanf("%f", &ptr->points);
  }

您应该始终在使用变量的最小作用域中声明变量。
请注意,它会比scanf的这些调用更安全

scanf("%s", ptr->id);
scanf("%s", ptr->firstname);
scanf("%s", ptr->lastname);

写作

scanf("%14s", ptr->id);
scanf("%63s", ptr->firstname);
scanf("%63s", ptr->lastname);

还有一点要注意,与其使用幻数3,不如引入一个命名常量,例如

enum { N = 3 };
struct student std[N];

//...

for ( struct student *ptr = std; ptr != std + N; ++ptr ) {

在这种情况下,你的代码会更加灵活,只需要改变常量N的值就足够了,程序可以正常运行,而不需要对程序做任何额外的修改。

fivyi3re

fivyi3re3#

C标准规定,具有自动存储持续时间的指针在声明时具有不确定的值,即它们未初始化,可能指向内存中的任何内容。
当指针的值不确定时使用指针是未定义的行为,因此在声明时(以及在调用free()之后)将指针设置为NULL被认为是“良好的实践”。
但有必要吗?没有。
如果你声明了一个指针,并立即用一个值初始化它,那么首先将它设置为NULL是没有意义的。
只在需要的地方声明也是一个好习惯。所以不要:

struct student *ptr =  NULL;
  
  // other variables
  int i;
  
  // assign std to ptr
  ptr = std;

你可以这样写:

int i;
struct student *ptr = NULL;

另一个好的做法是避免用不必要的注解使代码混乱。

// assign std to ptr
ptr = std;

上面的注解没有任何意义,很明显std被分配给了ptr

相关问题