C++中指针的使用方法 最详细的讲解通俗易懂

admin 226 0
CSP-J/S2023第二轮认证怎么报名,详细信息查看https://www.zqdn.net/post/159.html

C++中指针的使用方法

 

刚开始接触C++的时候,被指针(pointer)引用(reference)内存分区等等诸多概念,弄得很头疼吧。其实回头想想,C/C++,python,java...学习起来都有一个共性,那就是敲敲敲,多敲几遍代码,可能会有一些问题,带着问题去学习,整理它。然后将技术不断的应用于工作中的新场景,很快就可以掌握一门新技术了

众所周知c++相对于其它语言的优势就在与c++有「 指针 」

指针是什么?

现在我们来举个例子详细了解一下指针到底是一个什么东东

一个快递员送快递,如果送的是一个老顾客,那么快递员可以直接跑到顾客的办公地点,将快递交给她就行了,这就是直接访问。但是如果现在快递员拿到了一个不认识的人的快递他是一个新顾客,那么快递员跑到他的办公地点,办公地点有很多人,他也分不清谁是谁,于是快递员找到了这里的一个保安问“张三是谁”保安就会给他指出张三就是这个人。然后快递员才能把快递送到顾客手上。此时这个中间来指出张三的人(保安)就是起了指针的作用,快递员无法直接找到张三,因此他只有通过保安才能给他指出张三是谁,这就叫做间接访问。

1、指针也是一种数据类型

1)指针也是一种变量,占有内存空间,用来保存内存地址

//测试指针变量占有内存空间大小

void main()

{

int* p = nullptr;

cout << "指针的大小" << sizeof(p) << endl;

int a = 10;

p = &a;

cout << "指针的大小" << sizeof(p) << endl;

system("pause");

return;

}

2)*p操作内存

在指针声明时,*号表示所声明的变量为指针(int* 代表的是指向地址中存储的数据类型为int)

在指针使用时,*号表示 操作 指针所指向的内存空间中的值

*p相当于通过地址(p变量的值)找到一块内存;然后操作内存

*p放在等号的左边赋值(给内存赋值)

*p放在等号的右边取值(从内存获取值)

3)指针变量和它指向的内存块是两个不同的概念

//含义1 给p赋值p=0x1111; 只会改变指针变量值,不会改变所指的内容;p = p +1; //p++

//含义2 给*p赋值*p='a'; 不会改变指针变量的值,只会改变所指的内存块的值

*p可以理解一个钥匙

//含义3 =左边*p 表示 给内存赋值, =右边*p 表示取值 含义不同切结!

//含义4 =左边char *p

//含义5 保证所指的内存块能修改

4)指针是一种数据类型,是指它指向的内存空间的数据类型

含义1:指针步长(p++),根据所致内存空间的数据类型来确定

p++=è(unsigned char )p+sizeof(a);

结论:指针的步长,根据所指内存空间类型来定。*很重要

简单点说

比如你有一个int类型的变量,里面的内容是10

把这个变量的地址保存在指针里,注意了,指针里面保存的不是这个变量本身,而是变量在内存中的地址

比如你要买一本书,你去了图书馆,查到了这本书在0x6ffe04位置上

你拿到了这个位置,并不代表你拿到了这本书,你要通过这个位置来找到这本书

这下懂了吧

一级指针的定义

int *p;//语法:类型 * 指针变量名;

指针的赋值

由于指针里存的是变量的地址,看这个程序

int *p;//定义一个指针

p=&a;//&是取址符

//或者int *p=&a;

指针的输出

我们写这样一个程序

#include<iostream>

using namespace std;

int main()

{

int a=10;

int *p=&a;

cout<<"指针p:"<<*p<<endl<<"a的地址:"<<&a<<endl<<"a:"<<a;

return 0;

}

运行结果:

指针p:10

a的地址:0x6ffe04

a:10

--------------------------------

Process exited after 0.04383 seconds with return value 0

请按任意键继续. . .

 

可以看到,我们如果要输出a

不管是通过指针输出还是直接输出变量a结果是一样的

 

简单说

 

简单说,二级指针就是指针的指针,二级指针里存放的是指针的地址

二级指针的赋值

 

二级指针的赋值和一级指针一样

 

int a=10;

int *pi=&a;

int **pi=π

 

二级指针的输出

我们写这样一个程序

 

#include<iostream>

using namespace std;

int main()

{

int a=10;

int *p=&a;

int **pp=&p;

cout<<"*p:"<<*p<<endl<<"&a:"<<&a<<endl<<"a:"<<a<<endl<<"**pp:"<<**pp<<endl<<"&pp:"<<&pp<<endl<<"&p:"<<&p;

return 0;

}

 

运行结果:

 

*p:10

&a:0x6ffdfc

a:10

**pp:10

&pp:0x6ffde8

&p:0x6ffdf0

--------------------------------

Process exited after 0.06748 seconds with return value 0

请按任意键继续. . .

由此可见,二级指针和一级指针的输出是一样的

#include <iostream>

#include <stdlib.h>

using namespace std;

int main()

{

int i = 30;

int *pi = &i;

std::cout << "一级指针*pi = " << *pi << std::endl; //一级指针

int **ppi = π

std::cout << "二级指针**ppi = " << **ppi << std::endl; //二级指针

 

*pi = 20;

std::cout << "改变一级指针内容: *pi = " << *pi << std::endl; //改变一级指针值

std::cout << "一级指针*pi = " << *pi << std::endl; //二级指针

 

int b = 10;

*ppi = &b;

std::cout << "改变一级指针指向*pi = " << *pi << std::endl; //改变一级指针的指向

std::cout << "二级指针**ppi = " << **ppi << std::endl;

 

system("pause");

return 0;

}

 

二级指针的步长

 

所有类型的二级指针,由于均指向一级指针类型,一级指针类型大小是 4,所以二级指针的步长也是 4,这个信息很重要。

改变n-1级指针的指向

 

可以通过一级指针,修改 0 级指针(变量)的内容。

可以通过二级指针,修改一级指针的指向。

可以通过三级指针,修改二级指针的指向。

·····

可以通过 n 级指针,修改 n-1

 

当指针遇上函数重载

 

C++编译器会按照函数指针的类型自动选择重载函数

程序

 

看这个程序

 

#include <iostream>

using namespace std;

void print(int a)

{

cout << "a is " << a << endl;

}

void print()

{

cout << "hello world" << endl;

}

 

typedef void (* Fun)(int);

typedef void (* Fun2)();

 

int main()

{

Fun pPrint = print;

Fun2 pPrint2 = print;

pPrint(12);

pPrint2();

return 0;

}

 

运行结果:

 

a is 12

hello world

 

重载函数作为参数传递时,特别形参的类型不是确定的函数指针类型时,如void *,例如Qt中的QObject::connect()函数,重载的信号或槽传入到connect时,可以使用static_cast<>来区别重载函数:

connect(subWidget, static_cast<void(SubWidget::*)()>(&SubWidget::switchWin), this, &MainWidget::switchWinSlot);

 

connect()函数的第2个和第4个形参都是const char *类型,不是指定好的函数指针类型,所以我们可以通过static<>来区分重载函数的版本。

new的用法

new其实就是告诉计算机开辟一段新的空间,但是和一般的声明不同的是,new开辟的空间在堆上,而一般声明的变量存放在栈上。通常来说,当在局部函数中new出一段新的空间,该段空间在局部函数调用结束后仍然能够使用,可以用来向主函数传递参数。另外需要注意的是,new的使用格式,new出来的是一段空间的首地址。所以一般需要用指针来存放这段地址。

指针和数组

普通方法遍历列表

int i, a[] = {3,4,5,6,7,3,7,4,4,6};

for (i = 0; i <= 9; i++)

{

std::cout << a[i] std::endl;

}

用指针遍历列表

int i, a[] = {3,4,5,6,7,3,7,4,4,6};

for (i = 0; i <= 9; i++)

{

std::cout << *(a+i) << std<<endl;;

}

 

这两种的效果是一毛一样的

用指针访问数组元素

int i, *pa, a[] = {3,4,5,6,7,3,7,4,4,6};

pa = a;

for (i = 0; i <= 9; i++)

 

{

std::cout << pa[i] << std::endl;

}

指针数组

指针数组的本质是数组,数组中每一个成员是一个指针。定义形式如下:

char * pArray[10];

语法解析:pArray 先与“[ ]”结合,构成一个数组的定义,char *修饰的是数组的内容,即数组的每个元素。

#include <iostream>

#include <stdlib.h>

using namespace std;

int main()

{

char * pArray[] ={"apple","pear","banana","orange","pineApple"};

for(int i=0; i<sizeof(pArray)/sizeof(*pArray); i++)

{

std::cout << pArray[i] << std::endl;

}

system("pause");

return 0;

}

 

运行结果

 

apple

pear

banana

orange

pineApple

请按任意键继续. . .

 

--------------------------------

Process exited after 1.655 seconds with return value 0

请按任意键继续. . .

 

结构体指针

 

c++结构体指针,顾名思义就是指向结构体的一个指针

定义结构体

 

struct My{

My *left;

My *right;

int val;

My(){}

My(int val):left(NULL),right(NULL),val(val){}

};


学了这么多,不如做点题吧

1.考试成绩

请编写一个程序,动态分配一个足够大的数组来保存用户定义的考试成绩。一旦输入了所有的分数,数组就应该被传递给一个按照升序排序的函数。应该调用另一个函数来计平均分数。程序应该显示已排序的分数列表和平均分,并加上恰当的标题。请尽可能使用指针表示法而不是数组表示法。

输入验证:考试成绩不接受负数。

1. #include <iostream>

2. using namespace std;

3. void sort(double *s,int n)

4. {

5.     for(int i=0;i<n;i++)

6.     {

7.         for(int j=0;j<n-i-1;j++)

8.         {

9.             if(*(s+j+1)>*(s+j))

10.             {

11.                 double tmp=*(s+j+1);

12.                 *(s+j+1)=*(s+j);

13.                 *(s+j)=tmp;

14.             }

15.         }

16.     }

17. }

18.  

19. double adv(double *s,int n)

20. {

21.     double sum=0.0;

22.     for(int i=0;i<n;i++)

23.         sum+=*(s+i);

24.     return sum/n;

25. }

26.  

27. void print(double *s,int n,double advscore)

28. {

29.     cout<<'\t'<<"考试成绩表"<<endl;

30.     cout<<"------------------------"<<endl;

31.     for(int i=0;i<n;i++)

32.     {

33.         cout<<i+1<<'\t'<<*(s+i)<<endl;

34.     }

35.     cout<<"平均成绩为:"<<advscore;

36. }

37. int main()

38. {

39.     double *score=new double[1000];

40.     cout<<"请输入成绩(输入101结束):"<<endl;

41.     int i=0;//计数

42.     while(1)

43.     {

44.         cin>>*(score+i);

45.         if(*(score+i)<0)

46.         {

47.             cout<<"输入非法!请重新输入:"<<endl;

48.             cin>>*(score+i);

49.         }

50.         else if(*(score+i)==9999)

51.              break;

52.         i++;

53.     }

54.     sort(score,i); //排序

55.     double advscore=adv(score,i);//计算平均分

56.     print(score,i,advscore);//输出

57.     return 0;

58. }

59.  


 

考试成绩(2)

修改编程题的程序以允许用户输入名称-分数对。对于每个参加考试的学生,用户先输入代表学生姓名的字符串,然后输入代表学生成绩的整数。修改排序和平均分计算函数,以便它们采用结构数组,每个结构包含单个学生的名称和分数。在遍历数组时,使用指针而不是数组索引。

 

#include <iostream>

#include <string>

using namespace std;

struct student

{

    string name;//名字

    int score;//分数

};

 

void sort(student *s,int n)

{

    for(int i=0;i<n;i++)

    {

        for(int j=0;j<n-i-1;j++)

        {

            if(s[j+1].score>s[j].score)

            {

                student tmp=s[j+1];

                s[j+1]=s[j];

                s[j]=tmp;

            }

        }

    }

}

 

double adv(student *s,int n)

{

    int sum=0;

    for(int i=0;i<n;i++)

        sum+=s[i].score;

    return sum/n;

}

 

void print(student *s,int n,double advscore)

{

    cout<<'\t'<<"考试成绩表"<<endl;

    cout<<"------------------------"<<endl;

    for(int i=0;i<n;i++)

    {

        cout<<i+1<<'\t'<<s[i].name<<'\t'<<s[i].score<<endl;

    }

    cout<<"平均成绩为:"<<advscore;

}

 

int main()

{

    student *p=new student[1000];

    cout<<"请输入姓名和成绩(输入#结束):"<<endl;

    int i=0;//计数

    while(1)

    {

        cin>>p[i].name;

        cin>>p[i].score;

        if(p[i].score<0)

        {

            cout<<"输入非法!请重新输入:"<<endl;

            cin>>p[i].score;

        }

        else if(p[i].score==9999)

             break;

        i++;

    }

    sort(p,i); //排序

    double advscore=adv(p,i);//计算平均分

    print(p,i,advscore);//输出

    return 0;

}

 


 

通过指针间接排序

某公司有一个包含Person类型结构的Person data[10]数组,需要按姓名对该数组排序

struct Person

{

string name;

int age;

};

 

在真实的程序中,Person 结构可能拥有许多成员,占用大量内存。在这种情况下,排序和移动Person 对象都可能消耗大量的计算资源。因此,可以考虑定义一个辅助数组 Person*pData[10],设置pData[k]的每个元都指向data[k]的对应元素。请编写一个程序,对该指针数组进行排序,这样,当按索引k的升序遍历pData数组时,pData[k]元素即指向按字母顺序的升序排序的Person对象。

通过指针间接排序(2)

请编写一个程序,解决刚才那题提出的问题,但是指针数组现在应该指向按年龄降序排序的数据数组。

#include <iostream>

#include <string>

#include <iomanip>

using namespace std;

struct Person

{

string name;

int age;

};

void sort(Person *p,int n)

{

for(int i=0;i<n;i++)

{

for(int j=0;j<n-i-1;j++)

{

if(p[j].age<p[j+1].age)

{

Person x=p[j];

p[j]=p[j+1];

p[j+1]=x;

}

}

}

}

int main()

{

Person data[10];

Person *pData[10];

cout<<"请输入员工的姓名和年龄:"<<endl;

for(int i=0;i<10;i++)

cin>>data[i].name>>data[i].age;

//pData[k]的每个元都指向data[k]的对应元素

for(int i=0;i<10;i++)

pData[i]=&data[i];

sort(*pData,10);

cout<<'\t'<<"姓名排序表"<<endl;

cout<<"----------------------------"<<endl;

for(int i=0;i<10;i++)

cout<<setw(15)<<left<<pData[i]->name<<pData[i]->age<<endl;

return 0;

}


 

馅饼吃货可知否

在统计作业中,一组值得众数是经常出现得值。请编写一个程序,确定大多数人每年吃多少块馅饼。设置一个可以保存30人得回答的整数数组,输入每个人所说的一年中所吃的馅饼块数。然后编写一个函数来查找这30个值得众数,这将是大多数人吃的馅饼的块数。查找和返回众数得函数应该接受两个实参,其中一个是整数数组,另一个是指示数组中有多少元素。

 #include <iostream>

 

using namespace std;

int Mode(int *s,int n)

{

    int num=1,x=1;

    //从大到小排序

    for(int i=0;i<n-1;i++)

    {

        for(int j=0;j<n-i-1;j++)

        {

            if(*(s+j)<*(s+j+1))

            {

                int tmp=*(s+j);

                *(s+j)=*(s+j+1);

                *(s+j+1)=tmp;

            }

        }

    }

    int m;//记录众数的值

    int current=0;//当前正在访问的数字的个数

    int most=0;//目前的众数个数

    for(int i=0;i<n;i++)

    {

        current++;

        if(*(s+i)!=*(s+i+1) || i==n-1)

        {

            if(current>most)

            {

                most=current;

                m=*(s+i);

            }

            current=0;

        }

    }

    return m;

}

 

int main()

{

    int *p=new int[30];

    cout<<"请输入每年吃的馅饼块数:"<<endl;

    int i=0;

    while(1)

    {

        cin>>*(p+i);

        if(*(p+i)<0)

        {

            cout<<"输入有误!不能为负数!请重新输入:"<<endl;

            cin>>*(p+i);

        }

        else if(*(p+i)==0000)

            break;

        i++;

    }

    cout<<"所吃馅饼的众数为:"<<Mode(p,i);

    return 0;

}

 


推荐阅读:

pcb影像测量仪的编程培训(影像测量仪软件的使用方法)

北大青鸟电脑编程培训(北大青鸟编程软件使用方法)

信息学奥赛CSP-J的考试内容是什么?C++、数据结构和算法!

北大青鸟的编程培训(北大青鸟编程软件使用方法)

图形化编程的使用方法(图形化编程介绍)

信奥赛NOI一本通C++版:题解目录(语言及算法基础篇)CSP2023认证成绩查询,详细信息查看https://www.zqdn.net/tags-13223.html

标签: C++ 易懂 指针 使用方法

发布评论 0条评论)

  • Refresh code

还木有评论哦,快来抢沙发吧~