C/C++指针、数组和结构体浅析

发布时间:2024年01月11日

在C/C++实际运用中,指针、数组和结构体这三个部分基本上都是同时使用的,并在不同的函数间调用。今天就来浅析一下三者的使用与联系,适用于有一定基础,但理解不是很清的同学~

目录

1.基本概念

1.1指针

1.2结构体

2.数组和指针

3.结构体和指针

4.结构体和数组

5.结构体、数组和指针

6.整合示例


1.基本概念

(指针和结构体的知识比较重要,就再回顾一下基础,数组的知识单用比较简单,就不赘述)

1.1指针

在 C/C++中,指针通常是指针变量,指针变量的内容存储的是其指向的对象的首地址,指向的对象可以是变量(指针变量也是变量),数组函数等占据存储空间的实体。

定义指针变量的一般形式为:类型说明符 *变量名。?

  int *ptr;  // 声明一个指向整数的指针变量
  char *p1;  //表示 p1 是一个指针变量,它的值是某个字符变量的地址。

类型说明符表示指针变量所指向变量的数据类型;*表示这是一个指针变量;变量名表示定义的指针变量名,其值是一个地址。

通常涉及两个运算符:(可以想象自己在一个多层循环嵌套的房间内,指针就是房间外的门牌号)

  • & 取址运算符:返回变量的内存地址(往外走一圈,指向门牌号,我习惯称引用)

  • * 取值运算符:访问指针指向的变量(往里走一圈,指向房间内容,我习惯称解引)

#include <stdio.h>  
int main()
{
    int i = 0x12345678;         
    int* p = &i;              
 
    printf("0x%08x \n", i);      //打印结果: 0x12345678
    printf("0x%08x \n", &i);     //打印结果: 0x004ffed0
    printf("%d \n", sizeof(i));  //打印结果: 4
 
    printf("0x%08x \n", p);      //打印结果: 0x004ffed0
    printf("0x%08x \n", &p);     //打印结果: 0x004ffecc
    printf("%d \n", sizeof(p));  //打印结果: 8
  
    // 指针变量p指向的对象是变量i
    // 1.指向的对象变量i的地址是&i(0x004ffed0)
    // 2.指向的对象变量i的类型是int
    // 3.指向的对象变量i的内容是0x12345678
    // 4.指针变量p本身的地址是&p(0x004ffecc)
    // 5.指针变量p本身的类型是int*
    // 6.指针变量p本身的内容是&i(0x004ffed0)
    return 0;
}

1.2结构体

结构体是一种用户自定义的数据类型,它允许将多个不同类型的变量组合在一起,形成一个逻辑上相关的数据单元。结构体在C/C++中非常常用,可以用来表示复杂的数据结构和实体。

结构体的定义形式:

  struct Person {
       char name[20];
       int age;
       float height;
   };
   

访问成员通常涉及两个运算符:

  • .?成员选择运算符:结构体变量的运算符,它需要两个操作数,左操作数就是结构体变量名,右操作数就是需要访问的成员名。(也叫圆点运算符)
  • -> 指向运算符:结构体指针的运算符,它与成员选择运算符一样,需要两个操作数,左操作数就是结构体变量名,右操作数就是需要访问的成员名(也叫箭头运算符)

下面是成员选择运算符的使用实例。(指向运算符的使用涉及结构体和指针,就放到本文第三节再详细说明)

   struct Person p1;  // 声明一个结构体变量
   strcpy(p1.name, "John");  // 使用strcpy函数将字符串赋给结构体变量的成员name
   p1.age = 25;  // 赋值给结构体变量的成员age
   p1.height = 1.75;  // 赋值给结构体变量的成员height
   printf("Name: %s, Age: %d, Height: %.2f", p1.name, p1.age, p1.height);  // 输出结构体变量的成员值

上述代码的输出如下:

Name: John, Age: 25, Height: 1.75

此外,当使用结构体时,通常同时用typedef关键字,可以通过typedef关键字为结构体定义一个新的类型名称。这样做的好处是可以方便地使用新的类型名称来声明结构体变量,而无需每次都使用struct关键字。

示例如下:

typedef struct {
    char name[20];
    int age;
} Person;

int main() {
    Person p1;  // 使用新的类型名称Person声明结构体变量
    strcpy(p1.name, "John");
    p1.age = 25;
    printf("Name: %s, Age: %d", p1.name, p1.age);
    return 0;
}

在上例中,通过typedef关键字将匿名结构体定义为Person类型。这样,就可以直接使用Person作为新的类型名称来声明结构体变量p1,而无需每次都使用struct关键字,可以使代码更加简洁和易读,特别是在需要频繁使用结构体类型的情况下。

2.数组和指针

事实上,数组名本身就是一个指向数组第一个元素的指针

声明数组指针的形式如下:

   int arr[5];  // 声明一个包含5个整数的数组
   int *ptr;  // 声明一个指向整数的指针变量
   ptr = arr;  // 将数组名赋给指针变量,即指向数组的第一个元素

这样,ptr指针就指向了该数组,再通过解引运算符*就可以访问数组内容

   int arr[5] = {1, 2, 3, 4, 5};
   int *ptr = arr;  // 将数组名赋给指针变量
   printf("%d ", *ptr);  // 输出指针所指向的第一个元素的值
   printf("%d", *(ptr + 1));  // 输出指针所指向的第二个元素的值

再看一下,使用指针遍历数组的过程:

   int arr[5] = {1, 2, 3, 4, 5};
   int *ptr = arr;  // 将数组名赋给指针变量
   for (int i = 0; i < 5; i++) {
       printf("%d ", *(ptr + i));  // 输出指针所指向的元素的值
   }

看下对应的输出:

1 2 3 4 5

?接下来就给把数组指针配合函数来使用了:

  void printArray(int *ptr, int size) {
       for (int i = 0; i < size; i++) {
           printf("%d ", *(ptr + i));  // 输出指针所指向的元素的值
       }
   }
   
   int arr[5] = {1, 2, 3, 4, 5};
   printArray(arr, 5);  // 将数组名作为参数传递给函数(数组名本身就是一个指针)

?这里的输出结果和上面的是一样的,通过循环打印出指针所指向元素的值。

3.结构体和指针

结构体指针允许通过指针来访问和操作结构体变量的成员。

声明结构体指针的形式:

  struct Person {
       char name[20];
       int age;
   };

   struct Person p1;  // 声明一个结构体变量
   struct Person *ptr;  // 声明一个指向结构体的指针变量
   ptr = &p1;  // 将结构体变量的地址赋给指针ptr
   

接下里,就到了使用1.2中提到的指向运算符->来访问成员:

  struct Person {
       char name[20];
       int age;
   };

    struct Person p1;  // 声明一个结构体变量
    struct Person *ptr = &p1;  // 声明一个指向结构体的指针,并将结构体变量的地址赋给指针ptr
    strcpy(ptr->name, "John");  // 使用指针访问结构体变量的成员name,并赋值
    ptr->age = 25;  // 使用指针访问结构体变量的成员age,并赋值
    printf("Name: %s, Age: %d\r\n", ptr->name, ptr->age);  // 使用指针输出结构体变量的成员值
    printf("Name: %s, Age: %d", p1.name, p1.age);  // 使用指针输出结构体变量的成员值
   

看下结果:?

Name: John, Age: 25
Name: John, Age: 25

可以发现,两个输出函数打出的内容是一致的;这是因为ptr是指向p1的结构体指针,对结构体指针进行操作,本质上是对结构体变量p1操作,因此自然p1的值也就改变了。

再看一下,动态分配结构体指针的过程:

  struct Person {
       char name[20];
       int age;
   };

   struct Person *ptr = (struct Person*)malloc(sizeof(struct Person));  // 动态分配一个结构体大小的内存空间
   strcpy(ptr->name, "John");  // 使用指针访问结构体变量的成员name,并赋值
   ptr->age = 25;  // 使用指针访问结构体变量的成员age,并赋值
   printf("Name: %s, Age: %d", ptr->name, ptr->age);  // 使用指针输出结构体变量的成员值
   free(ptr);  // 释放动态分配的内存空间

4.结构体和数组

结构体数组即创建一个数组,其中每个元素都是一个结构体。

声明结构体和结构体数组的形式:

  struct Person {
       char name[20];
       int age;
   };

   struct Person people[5];  // 声明一个包含5个结构体的结构体数组
   

通常,需要带初始值来初始化结构体数组:

  struct Person {
       char name[20];
       int age;
   };

   struct Person people[3] = {
       {"John", 25},
       {"Alice", 30},
       {"Bob", 35}
   };
   

访问结构体数组的元素就比较简单,直接使用成员运算符访问即可:

  struct Person {
       char name[20];
       int age;
   };

   struct Person people[3] = {
       {"John", 25},
       {"Alice", 30},
       {"Bob", 35}
   };

   printf("Name: %s, Age: %d\n", people[0].name, people[0].age);  // 访问结构体数组的第一个元素
   printf("Name: %s, Age: %d\n", people[1].name, people[1].age);  // 访问结构体数组的第二个元素
   printf("Name: %s, Age: %d\n", people[2].name, people[2].age);  // 访问结构体数组的第三个元素
   

5.结构体、数组和指针

当结构体、数组和指针共同使用时,可以实现一些相对更难一点的数据结构和算法。

先简单扩充一下本文第3节中动态分配的例子:

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

struct Person {
   char name[20];
   int age;
};

int main()
{
   struct Person *ptr =  (struct Person*)malloc(2*sizeof(struct Person));  // 动态分配二个结构体大小的内存空间
   strcpy(ptr->name, "John");  // 使用指针访问结构体变量的成员name,并赋值
   ptr->age = 25;  // 使用指针访问结构体变量的成员age,并赋值
   printf("Name: %s, Age: %d\r\n", ptr->name, ptr->age);  // 使用指针输出结构体变量的成员值
   ptr++; //指针后移
   strcpy(ptr->name, "Tom");  // 使用指针访问结构体变量的成员name,并赋值
   ptr->age = 20;  // 使用指针访问结构体变量的成员age,并赋值
   printf("Name: %s, Age: %d", ptr->name, ptr->age);  // 使用指针输出结构体变量的成员值
   free(ptr);  // 释放动态分配的内存空间
   return 0;
}

上面代码中的输出结果如下:

Name: John, Age: 25
Name: TOM, Age: 20

6.整合示例

下面是一个示例代码,演示了如何使用结构体、数组和指针来实现一个简单的学生信息管理系统:

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

// 定义学生结构体
typedef struct {
    int id;
    char name[20];
    int age;
} Student;

// 打印学生信息
void printStudent(Student* student) {
    printf("学生ID:%d\n", student->id);
    printf("学生姓名:%s\n", student->name);
    printf("学生年龄:%d\n", student->age);
}

int main() {
    int numStudents;
    printf("请输入学生人数:");
    scanf("%d", &numStudents);

    // 动态分配内存来存储学生信息
    Student* students = (Student*)malloc(numStudents * sizeof(Student));

    // 输入学生信息
    for (int i = 0; i < numStudents; i++) {
        printf("请输入学生ID:");
        scanf("%d", &(students[i].id));
        printf("请输入学生姓名:");
        scanf("%s", students[i].name);
        printf("请输入学生年龄:");
        scanf("%d", &(students[i].age));
    }

    // 输出学生信息
    for (int i = 0; i < numStudents; i++) {
        printf("第%d个学生信息:\n", i+1);
        printStudent(&(students[i]));
    }

    // 释放内存
    free(students);

    return 0;
}

持续更新中~点赞收藏越多更新越快啦哈哈?

文章来源:https://blog.csdn.net/m0_48465029/article/details/135514099
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。