【原创】C++指针详解

指针

一,基础知识
1,内存(memory)
电脑是在CPU里面执行任务的,CPU就相当于人的大脑。CPU计算速度很快,所以我们写程序时,哪怕例如执行100多次循环,看起来似乎都是一秒就能执行好的。然而,CPU的存储能力很差,里面自带的几个寄存器(以32位为例)才只能存储区区32个字节。就算把段寄存器全部用上,也才只有44字节。所以CPU就需要一个东西辅助存储数据。这个存储数据的地方就是内存。
内存就像一个超大规模的住宅区,里面存储着CPU需要执行的数据。相对CPU来说,其实内存是一个外部寄存器。一般来说,程序都是保存在内存中执行的,CPU必须从内存读入执行数据。
2,内存地址
内存很大,为了识别每个内存,我们就需要给每个内存编一个号,这个号码就是内存地址。

二,指针
1,先来看一个例子:
#include<stdio.h>
int main(void) {
  int x=0;
  printf("%i",&x);
}
这个时候程序会输出一个奇怪的数字,不是0。这个数据在每次执行的时候会有一些变化,所以这里就不写出执行后输出的值了。
这里“&”是取地址操作符,表示取变量x的地址。这时候输出的就是x的地址。因为每次重新启动电脑的时候,操作系统都会根据当前内存中空余的地址,重新分配地址,所以每次执行时都会有一些小的变化。
2,什么是指针
先来看一个例子。
#include<stdio.h>
int main(void) {
  int a=10;
  int *p;
  p=&a;
  printf("%i",*p);
}
执行后会输出10。这里我们重点看第4行和第5行。
int *p表示声明指针变量p。p存放的就是一个内存地址,用“*”指针操作符就可以得到p存放的内存地址所指向的内容了。也就是说,p=&a表示把a的地址赋值给p,然后此时*p的值就是&a地址对应的值,就是a。
3,用指针取得最大值
现在有2个数,请用指针变量取得这2个数的最大值。
#include<stdio.h>
int main(void){
  int a,b,*p;
  scanf("%i%i",&a,&b);
  if(a>b)p=&a;//p指向a
  else p=&b;//p指向b
  printf("%i",*p);
}

三,指针的加减运算
1,数组
定义数组,我们一般用如下的语句:
int a[10];
这个时候操作系统就会给数组a分配10个连续的地址。注意是连续的。

2,指针的加减运算
#include<stdio.h>
int main(void) {
  int a[3]={1,2,3};
  int *p;
  p=&a[0];
  printf("%i", *(++p) );
}
此时会输出2.我们看一下我们的内存:
设程序是从地址main开始运行的,那么内存如下
main1(a[0])
main+42(a[1])
main+83(a[2])
我们一开始把p指向a[0]所在的地址。++p,就是p的地址往前一个数,增加了sizeof(int),所以就是main+4,对应的数据就是2.
同理,p--就是往前一个地址,到达前面一个数据的空间。

四,指针和数组
1,
#include<stdio.h>
int main(void) {
  int a[5]={10,20,30,40,50};
  int *p;
  p=&a[0];
  printf("%i\n",*(p+2));
  printf("%i\n",a[2]);
}

输出结果应该是两个30.p的地址就是a[0]的地址,那么p+2就是a[2]的地址,所以*(p+2)就是a[2]。
同理我们知道,其实p就是a(数组名就是数组第一个元素的地址),所以,
*(p+i)=p[i]
其实根据加法交换率,*(p+i)=*(i+p)=i[p]。你可能不相信,把p[i]写成i[p]这样也没错。说白了数组其实就是指针。
为了写起来简便,我们一般把scanf中,&p[i]写作p+i。应该知道为什么吧。

2,(这个是新版本c++语言的写法,老版本c语言不支持)
#include<stdio.h>
int main(void){
  int n,*a,i;
  scanf("%i",&n);
  a=new int [n];
  for(i=0;i<n;i++){
    scanf("%i",a+i);
  }
  for(i=0;i<n;i++){
    printf("%i ",a[i]);
  }
}
首先输入一个数组元素个数,然后输入数组中的元素,最后输出数组。
这里a=new int [n]表示a向操作系统申请n个空间,这样a就可以当作数组使用了。否则a刚定义时,只有一个空间,不能往后继续存储(要不然就是数组越界),必须先向操作系统申请才能继续。
new是c++新引入的操作符:申请空间。这样做可以避免定义大数组时空间浪费。

顺便说一句,这是c++新引入的东西,老版本c语言是不支持的,所以编译的时候要注意。用c语言编译会出错。因为它不知道new是什么东西。
[Error] 'new' undeclared (first use in this function)

五,指针函数参数调用
现在要编写一个自定义函数swap(a,b),交换a,b变量的值。
错误示范1:
void swap(int a,int b){
  a=b;
  b=a;

}
错误:因为在a=b赋值完成后,a已经是b的值了,所以此时执行b=a,a已经不是原来的值了,错误。
错误示范2:
void swap(int a,int b){
  int tmp;
  tmp=a;//先把a保存起来
  a=b;
  b=tmp;
}
还是错误的。不信你运行一下试试,数值根本没变。
然而这么写却是对的。
int main(void){
  int a,b,tmp;
  scanf("%i%i",&a,&b);
  int tmp;
  tmp=a;//先把a保存起来
  a=b;
  b=tmp;
  printf("%i %i",a,b);
}
这是怎么会是呢?我们来了解一下函数的传值机制。
首先执行swap函数,参数把main里面的a和b传递给swap里面的a和b。方便描述,我们这里把main里面的用(main)表示,swap里面的用(swap)表示。
此时(swap)a=(main)a,(swap)b=(main)b。注意此时(swap)a和(main)a,(swap)b和(main)b地址不相等。
然后执行玩函数,(swap)a=(main)b,(swap)b=(main)a
然而(main)a,(main)b一点没变。
所以我们需要换一种传值方法。因为函数按值传递,所以我们传递函数的地址就可以了。
void swap(int *a,int *b){
  int tmp;
  tmp=*a;
  *a=*b;
  *b=tmp;
}
然后再写main。
错误示范3:
int main(void){
  int a,b,tmp;
  scanf("%i%i",&a,&b);
  swap(a,b);
  printf("%i %i",a,b);
}
首先下面出现了几行warning。
[Warning] passing argument 1 of 'swap' makes pointer from integer without a cast
[Warning] passing argument 2 of 'swap' makes pointer from integer without a cast
然后运行时成功崩溃了。
(弹出“xxx已停止工作,windows正在查找该问题的解决方案”)
这又是为什么呢?因为函数中,函数参数传送的是地址,a和b都是地址变量,函数中调用*a和*b才是值,所以参数中应该是地址才对。
基本正确的程序示例:
int main(void){
  int a,b,tmp;
  scanf("%i%i",&a,&b);
  swap(&a,&b);
  printf("%i %i",a,b);
}
运行成功。我们来总结一下:
1,遇到修改变量值的函数,调用时要注意用指针,要不然传送时只修改了自定义函数的值,没有修改main函数中的值。
2,调用时注意加上地址符号“&”。是不是觉得这样写很像我们用scanf的时候,
scanf("%i",&a)
其实scanf也运用了指针,后面需要写传送参数的地址。

六,结构体指针
1,结构体指针就是指向结构体的指针,其内存地址就是该结构体的第一个元素的地址。
如:

struct student a;
struct student *stu;
*stu=&a;

此段代码中stu指针变量指向的就是a。
2,引用
(*stu).name

表示*stu的name成员。注意括号虽然不好看,但是不能省略。
*stu.name相当于:*(stu.name)。

当然,还有一种更加方便的写法,就是用箭头记号,
stu->name。

也就是说,
(*a).b=a->b
(0)

相关推荐

  • C语言中数组的总结

    #目录 # 一维数组的创建和初始化 一维数组的使用 一维数组在内存中的存储 指针的初步介绍 一维数组的指针访问 二维数组的创建和初始化 二维数组的使用 二维数组在内存中的存储 二维数组的指针访问 有关 ...

  • C语言学习篇(15)-----函数传参详解

    https://m.toutiao.com/is/JpuAcLb/ 前面我们已经介绍过什么是指针,指针变量的用法等等,今天我们就来讲讲什么是函数,函数有啥作用,函数的参数有哪些需要注意的地方以及指针与 ...

  • C语言指针学习总结

    作者:driveby 来源:https://www.cnblogs.com/KKSJS/p/9622812.html 上学的时候学习C语言,最烦的就是里面指针,可是指针也恰恰是C语言的灵魂. 最近在重 ...

  • C/C 指针详解之基础篇

    目录 一.变量的内存实质到 1.1变量的实质 1.2 赋值给变量 1.3 变量在哪里? 二. 指针是个什么东西? 三. 二级指针(指针的指针) 3.1 定义与初始化 3.2 间接数据访问 3.2.1  ...

  • C/C 指针详解之提高篇

    目录 一. 堆空间与指针的相爱相杀 1.1 堆上一维空间 1.1.1 返回值返回(一级指针) 1.1.2 参数返回(二级指针) 1.2 堆上二维空间 1.2.1 指针作返值输出 1.2.2 空间申请与 ...

  • 简单粗暴,文艺青年,灭绝师太,许栩原创为你详解安全库存的三种计算方法

    本文为<从头细说安全库存>文字版第2篇,对应我的原创视频第2讲<从头细说安全库存第2讲:安全库存的三种计算方法>(点击直接跳转). 安全库存的三种计算方法,由易到难,我将其分别 ...

  • C++ this指针详解

    this指针: 每个成员函数都有一个隐含的输入参数this指针,this指向当前对象,this指针可以用来访问对象的数据成员. class B {public: void fun1() { } voi ...

  • 原创“三星堆”究竟属于哪个朝代?详解三星堆遗址的时间线|三星堆|宝墩|三星堆遗址|考古发现|青铜

    关于三星堆遗址的时间线,其经理了有2000多年的历史,在这时间里,不同时间的器物都有着很明显的变化,不仅应该分为几个考古文化,而且还得进一步的再细化.'三星堆一期文化'是与'宝墩文化'有所交叉的不同文 ...

  • 西周的南方防线-汉阳诸姬二十一国详解原创历史小驿2019-09-27 21:56:40

    公元前1046年,周武王姬发带领诸侯联军起兵讨伐商纣王,攻克了朝歌城,基本上控制了商朝原来的统治地区,又征服了四周的许多小国.为了控制东方的大片领土,周武王采用"封建亲戚.以藩屏周" ...

  • 【原创教程】promote详解和属性转化_houdini之道02_01_03CG猎人原创完全入门教程发布

    --  微资讯 · 微课程  -- 利用零碎时间,走上超神之路! 教程介绍 教程名字   CGhunter_houdini之道_02_01_03_attributepromote 教程导读 详细介绍了 ...

  • 【原创精选】一文详解这两种常见的过流保护!

    过流保护对电源来说是一种标配了,可以说所以的电源都会有过流保护功能,过流保护可以分为关断保护与限流保护两种. 关断保护是,当过载后,电路检测到电源过流了,电源芯片停止PWM,过流故障解除后也不会重新恢 ...

  • 「原创」MOSFET的驱动技术详解

    MOSFET作为功率开关管,已经是是开关电源领域的绝对主力器件.虽然MOSFET作为电压型驱动器件,其驱动表面上看来是非常简单,但是详细分析起来并不简单.下面我会花一点时间,一点点来解析MOSFET的 ...