# 第10章 指针和结构体

10.1 指针

一、什么是指针

指针(Pointer):变量的地址,通过它能找到以它为地址的内存单元。

例子1:理解指针概念

#include <bits/stdc++.h>
using namespace std;
int main(){
    int x=10;
    int* p=&x; // 定义整数指针p,指向x的地址
    cout<<p<<endl; // 输出x的地址(指针值)
    cout<<*p<<endl; // 输出p指向地址对应的值(即x的值)
    *p=*p+2; // 通过指针修改变量x的值(等价于x=x+2)
    cout<<x<<endl;
    return 0;
}

例子2:值拷贝与地址拷贝对比

#include <bits/stdc++.h>
using namespace std;
int main(){
    int x=10;
    // 值拷贝:y是新变量,修改y不影响x
    int y =x;
    y=y+2;
    cout<<x<<endl; // 输出10
    // 地址拷贝:p指向x的地址,修改*p即修改x
    int* p=&x;
    *p=*p+2;
    cout<<x<<endl; // 输出12
    return 0;
}

例子3:&和*的嵌套使用

#include <bits/stdc++.h>
using namespace std;
int main(){
    int x=10;
    int *p=&x;
    cout<<p<<endl; // 输出x的地址
    cout<<*p<<endl; // 输出x的值
    cout<<&(*p)<<endl; // 等价于&x,输出x的地址
    cout<<*&(*p)<<endl; // 等价于*p,输出x的值
    return 0;
}

例子4:p++和(p)++的区别

#include <bits/stdc++.h>
using namespace std;
int main(){
    int x=10;
    int* p=&x;
    cout<<p<<" "<<*p<<endl; // 输出x的地址和10
    // ++优先级高于*,*p++等价于p++(指针地址自增,不修改x的值)
    // *p++; 
    (*p)++; // 先取p指向的值,再自增(x变为11)
    *p=*p+1; // x再自增1(变为12)
    cout<<p<<" "<<*p<<endl; // 输出原地址和12
    return 0;
}

二、指针作用

  1. 通过函数修改变量的值:普通参数传递是值拷贝,指针传递可直接操作原变量
#include <bits/stdc++.h>
using namespace std;
void change1(int x){ x++; } // 值传递,不影响原变量
void change2(int *p){ (*p)++; } // 指针传递,修改原变量
int main(){
    int x=1;
    change1(x);
    cout<<x<<endl; // 输出1
    int p=1;
    change2(&p);
    cout<<p<<endl; // 输出2
    return 0;
}
  1. 让函数返回多个值:通过指针输出额外结果
#include <bits/stdc++.h>
using namespace std;
// 返回平均值,通过指针输出最大值和最小值
double num(int a,int b,int* max,int* min){
    if(a>b){
        *max =a;
        *min =b;
    }else{
        *max =b;
        *min =a;
    }
    return(a+b)/2.0;
}
int main(){
    int a,b,max,min;
    cin>>a>>b;
    double r=num(a,b,&max,&min);
    cout<<max<<" "<<min<<" "<<r<<endl;
    return 0;
}
  1. 在scanf中使用指针:scanf需传入变量地址
#include <bits/stdc++.h>
using namespace std;
int main(){
    int a,b;
    // 变量读入:&取地址
    scanf("%d%d",&a,&b);
    // 变量输出
    printf("%d+%d=%d\n",a,b,a+b);
    printf("%d-%d=%d\n",a,b,a-b);
    int *p =&a;
    printf("%p %d\n",p,*p); // 输出a的地址和值
    return 0;
}

格式说明:%d(整数)、%f(float)、%lf(double)、%c(字符)、%s(字符串)、%p(指针)

三、数组指针

数组本质是指向首元素(a[0])的地址,指针可遍历数组

例子1:数组与指针的关联

#include <bits/stdc++.h>
using namespace std;
int main(){
    int a[5]={10,20,30,40,50};
    cout<<a<<" "<<&a<<" "<<&a[0]<<endl; // 三者均为a[0]的地址
    int *p =a; // 指针p指向数组首元素
    cout<<p<<" "<<a[0]<<endl; // 输出首地址和10
    *p=*p+2; // 修改a[0]为12
    cout<<p<<" "<<a[0]<<endl;
    p++; // 指针指向a[1]
    *p=*p+2; // 修改a[1]为22
    cout<<p<<" "<<a[1]<<endl;
    return 0;
}

例子2:函数中通过指针操作数组

#include <bits/stdc++.h>
using namespace std;
// 数组形式参数
void fun1(int a[],int n){
    for(int i=0;i<n;i++){
        cout<<a[i]<<" ";
    }
    cout<<endl;
}
// 指针形式参数
void fun2(int* a,int n){
    for(int i=0;i<n;i++){
        cout<<*a<<" ";
        a++;
    }
    cout<<endl;
}
// 字符数组遍历(指针方式)
void fun4(char* s){
    while(*s!='\0'){
        cout<<*s<<" ";
        s++;
    }
    cout<<endl;
}
int main(){
    int a[3]={10,20,30};
    fun1(a,3);
    fun2(a,3);
    char s[10]="hello";
    fun4(s);
    return 0;
}

10.2 结构体

一、什么是结构体

结构体是用户自定义的数据结构,可存储不同类型数据项(数组仅存储相同类型)。

例子1:结构体定义与使用

#include <bits/stdc++.h>
using namespace std;
// 定义结构体Student(驼峰命名)
struct Student{
    int num; // 学号
    string name; // 姓名
    double height; // 身高
}s1,s2; // 定义结构体时直接创建变量s1、s2

// 输出结构体成员(struct可省略)
void print(Student s){
    cout<<s.num<<" "<<s.name<<" "<<s.height<<endl;
}

int main(){
    Student s; // 创建结构体变量
    // 赋值
    s.num =1;
    s.name="zhang";
    s.height=178.5;
    print(s);
    // 直接给s1赋值
    s1.num=2;
    s1.name="wang";
    s1.height=182.6;
    print(s1);
    return 0;
}

注意:引用结构体成员用“结构体变量.成员名”

例子2:结构体数组

#include <bits/stdc++.h>
using namespace std;
struct Student{
    int num;
    string name;
    double height;
};
// 输出结构体数组
void print(Student a[],int n){
    for(int i=0;i<n;i++){
        cout<<a[i].num<<" "<<a[i].name<<" "<<a[i].height<<endl;
    }
}
int main(){
    int n;
    Student a[100]; // 结构体数组
    cin>>n;
    for(int i=0;i<n;i++){
        cin>>a[i].num>>a[i].name>>a[i].height;
    }
    print(a,n);
    return 0;
}

例子3:结构体指针

#include <bits/stdc++.h>
using namespace std;
struct Student{
    int num;
    string name;
    double height;
};
int main(){
    Student s;
    s.num=1;
    s.name="wang";
    s.height=185.5;
    // 直接访问成员
    cout<<s.num<<" "<<s.name<<" "<<s.height<<endl;
    // 结构体指针
    Student *p =&s;
    // 指针访问成员:-> 或 (*p).成员名
    cout<<p->num<<" "<<p->name<<" "<<p->height<<endl;
    cout<<(*p).num<<" "<<(*p).name<<" "<<(*p).height<<endl;
    return 0;
}

二、结构体的应用

应用1:期末考试成绩排名(冒泡排序+sort排序)

// 解法一:冒泡排序
#include <bits/stdc++.h>
using namespace std;
struct Student{
    int num;
    string name;
    int score;
};
int main(){
    Student a[110];
    int n,i,j;
    cin>>n;
    for(i=0;i<n;i++){
        cin>>a[i].num>>a[i].name>>a[i].score;
    }
    // 冒泡排序:成绩降序,成绩相同学号升序
    for(i=1;i<=n-1;i++){
        for(j=0;j<=n-i-1;j++){
            if(a[j].score <a[j+1].score || (a[j].score==a[j+1].score && a[j].num>a[j+1].num)){
                swap(a[j],a[j+1]);
            }
        }
    }
    for(i=0;i<n;i++){
        cout<<a[i].num<<" "<<a[i].name<<" "<<a[i].score<<endl;
    }
    return 0;
}

// 解法二:sort排序
#include <bits/stdc++.h>
using namespace std;
struct Student{
    int num;
    string name;
    int score;
};
// 比较函数
bool cmp(Student s1,Student s2){
    if(s1.score>s2.score || (s1.score==s2.score && s1.num<s2.num)){
        return true;
    }else{
        return false;
    }
}
int main(){
    Student a[110];
    int n,i;
    cin>>n;
    for(i=0;i<n;i++){
        cin>>a[i].num>>a[i].name>>a[i].score;
    }
    sort(a,a+n,cmp);
    for(i=0;i<n;i++){
        cout<<a[i].num<<" "<<a[i].name<<" "<<a[i].score<<endl;
    }
    return 0;
}

应用2:遥控飞机争夺赛(求平均成绩并排序)

#include <bits/stdc++.h>
using namespace std;
struct Player{
    int num; // 选手编号
    double score; // 平均成绩
};
bool cmp(Player p1,Player p2){
    if(p1.score>p2.score){
        return true;
    }else{
        return false;
    }
}
int main(){
    int n,i,j,x,s,ma,mi;
    Player a[110];
    cin>>n;
    for(i=0;i<n;i++){
        cin>>a[i].num;
        s=0;
        ma=INT_MIN;
        mi=INT_MAX;
        for(j=0;j<5;j++){
            cin>>x;
            s+=x;
            ma=max(ma,x);
            mi=min(mi,x);
        }
        a[i].score=(s-ma-mi)/3.0; // 去掉最高分和最低分求平均
    }
    sort(a,a+n,cmp);
    // 输出前三名,保留3位小数
    for(i=0;i<3;i++){
        cout<<a[i].num<<" "<<fixed<<setprecision(3)<<a[i].score<<endl;
    }
    return 0;
}

应用3:活动选择(贪心算法)

#include <bits/stdc++.h>
using namespace std;
struct Node{
    int begin; // 活动开始时间
    int end; // 活动结束时间
}a[110];
// 按结束时间升序排序
bool cmp(Node n1,Node n2){
    if(n1.end<n2.end){
        return true;
    }else{
        return false;
    }
}
int main(){
    int n,i,c=0,e;
    cin>>n;
    for(i=0;i<n;i++){
        cin>>a[i].begin>>a[i].end;
    }
    sort(a,a+n,cmp);
    c=1;
    e=a[0].end; // 第一个活动必选
    // 遍历后续活动,选择不冲突的
    for(i=1;i<n;i++){
        if(a[i].begin>=e){
            c++;
            e=a[i].end;
        }
    }
    cout<<c<<endl;
    return 0;
}

应用4:宇宙总统2(统计得票并排序)

#include <bits/stdc++.h>
using namespace std;
struct Node{
    string name; // 名字
    int count; // 得票数
}a[1100];
// 得票数降序,得票相同按名字字典码降序
bool cmp(Node n1,Node n2){
    if(n1.count>n2.count || (n1.count==n2.count && n1.name>n2.name)){
        return true;
    }else{
        return false;
    }
}
int main(){
    int n,k=0,i,j;
    bool f;
    string s;
    cin>>n;
    for(i=1;i<=n;i++){
        cin>>s;
        f=false;
        // 查找是否已有该名字
        for(j=1;j<=k;j++){
            if(a[j].name==s){
                a[j].count++;
                f=true;
                break;
            }
        }
        // 不存在则新增
        if(!f){
            k++;
            a[k].name=s;
            a[k].count=1;
        }
    }
    sort(a+1,a+k+1,cmp);
    for(i=1;i<=k;i++){
        cout<<a[i].name<<" "<<a[i].count<<endl;
    }
    return 0;
}

三、结构体作业

  1. 1730:【入门】购买贺年卡
  2. 1740:【基础】统计每个数出现的次数(提示:结构体存储数及出现次数)
  3. 1346:【入门】等比例缩放照片(提示:结构体存储宽、高及宽高比差值)
  4. 1347:【基础】游览动物园(提示:结构体存储坐标、与小红距离、与出口距离)
  5. 1561:【提高】买木头(提示:结构体存储木头长度和数量)
  6. 1330:【入门】求最大梯形的面积(提示:结构体存储上底、下底、高和面积)
  7. 1482:【提高】花生采摘(提示:结构体存储坐标和花生数量)
posted @ 2025-11-15 17:39  kkman2000  阅读(1)  评论(0)    收藏  举报