-------------------------------指针---------------------------------
指针?
内存单元的编号也叫做地址。既然根据内存单元的 号或地址就可以找到所需的内存单元,所以通常也把这个地址称为指针。
---总结:对于一个内存单元来说,单元的地址即为指针,其中存放的数据才是该单元的内容。
使用指针好处
a.为函数提供修改调用变量的灵活手段;
b.让函数有多个返回值
c.可以改善某些子程序的效率
>>在数据传递时,如果数据块较大(比如说数据缓冲区或比较大的结构),这时就可以使用指针 传递地址而不是实际数据,即提高传输速度,又节省大量内存。
d.为动态数据结构(如二叉树、链表)提供支持
3、变量的存取方式 存取方式分为两种:直接存取和间接存取
int a = 3; //直接存取:变量的赋值和取值(通过变量名进行存取值) int b = a; printf("%d",b);
间接存取:通过指针(地址)间接操作完成。
int *b = &a; printf("%d",*b);
-----------------------------指针变量
1、指针变量 在C语言中,允许用一个变量来存放指针,这种变量称为指针变量。
因此,一个指针变量的值就是某个内存单元的地址或称为某内存单元的指针。
注意: 严格意义上说,指针是一个地址,是一个常量指针变量是存放一个地址,是一个变量。
定义一个指针变量
对指针变量的定义包括三个内容:
1)指针类型说明,即定义变量为一个指针变量;
2)指针变量名;
3)变量值(指针)
其一般形式为: 类型说明符 *变量名;
----注意:
1)在定义指针时,“*”号表示定义的变量是指针变量,
变量的值只能存放地址。
2)一个类型的指针只能指向同类型的变量,不能指向其他类型的变量。
3)指针也可以被声明为全局、静态局部和局部的。
-----初始化和引用
指针变量初始化的方法有两种:
定义的同时进行初始化和先定义后初始化
1)定义的同时进行初始化
int a = 5; int *p = &a;
2)先定义后初始化
int a; int *p; p=&a;
3)把指针初始化为NULL int *p=NULL;
int *q=0; 不合法的初始化:
1)指针变量不能被赋值一个整数值(因为我们不知道这个整形常量是内存哪块地址
2)被赋值的指针变量前不能再加“*”说明符,如写为*p=&a 也是错误的
---注意点
1、多个指针变量可以指向同一个地址 int a = 5;
2、指针的指向是可以改变的
3、指针没有初始化里面是一个垃圾值,这时候我们这是一个野指针, 如果操作一个野指针
1)可能会导致程序崩溃
2)访问你不该访问数据 所以指针必须初始化才可以访问其所指向存储区域
两个有关的运算符:
& :取地址运算符;
* :指针运算符(或称“间接访问” 运算符)。
&变量名;
*指针变量名 //获取指针变量指向的存储空间的内容 如&a表示变量a的地址,&b表示变量b的地址。变量本身必须预先说明。
-----关于*的使用注意:
1)在定义变量的时候 * 是一个类型说明符,说明定义的这个变量是一个指针变量
int a = 5; int *p = &a; int *p1 = p;
2)在不是定义变量的时候 *是一个操作符,访问指针所指向存储空间
int x = *p;
--------函数实现两变量交换
分析:
常规做法不能实现变量值的交换。
指针地址交换也不能实现
指针指向的值交换可以实现
void swapNum2(int *a,int *b){ int temp; temp = *a; *a = *b; *b = temp; }
主调函数一定要传同一数据类型的地址
------------指针常见的应用场景
1)在被调函数中可以修改主调函数中变量的值
void change(int*num) { *num = 10; }
2)函数返回多个值
void sumAndMinusAndJiAndShang(int num1,int num2,int *sum,int *minus,int *ji,int *shang) { *sum = num1 + num2; *minus = num1 - num2; *ji = num1 * num2; *shang = num1 / num2; }
-------------二级指针
如果一个指针变量存放的又是另一个指针变量的地址,则称这个指针变量为指向指针(地址)的指针变量。也称为“二级指针”
int a = 5;
int * p = &a;
int ** p1 = &p;
p---指向a的地址
*p---a的地址对应的值----也就是5
p1--指针变量p的地址
*p1 ---> p的地址所对应的内容 --- a的地址
* *p1 ----> * a的地址 --> *p --> 5
------------指针为什么要区分类型
一个指针变量所占用的内存空间是固定的。
虽然所有的指针都只占8个字节,但不同类型的变量却占不同的字节数。 就和你租房子为什么知道地址了,还得知道户型一样!
结论:定义什么类型的指针就应该指向什么类型的变量。
----------------数组与指针---------------
1、一维数组指针
指向一维数组的指针
int a[5] = {1,2,3,4,5}; int *p = a;
2、二维数组指针
指向二维数组的指针
int arr[1][3] = {1,2,3}; int (*p)[3] = arr;
注意:
数组名a不代表整个数组,只代表数组首元素的地址。
3.指针数组:数组的每一个元素都是一个指针
或者存放指针的数组,就是指针数组
int a=3,b=4,c=5; int *pa[3]={&a,&b,&c}; int a[2][3]={{1,2,3},{4,5,6}}; int *pa[2]={a[0],a[1]};
4.指针变量之间的运算
前提:两个指针必须指向同一个数组
运算:减法
实质:计算两个指针之间关系,判断指针的位置
p = a; p1 =&a[3]
p1 - p > 0 表示p1在高位置
p1 - p < 0 表示p1在低位置
p1 - p = 0 表示p1和p指向了同一个位置
注意:
指针的运算,不能有加,乘,除运算
5.数组名访问二维数组
int a[3][4] = {{1,2,3,4}, {5,6,7,8}, {9,10,11,12}}; //访问 第一行的第一个元素地址表示: a + 1 = &a[1] = a[1] = &a[1][0] = *(a + 1) // 获取第一行的第一个元素值的方式: *a[1] = a[1][0] = **(a + 1)
----------------指针和字符串
a、字符串指针,用来保存字符串
char *s = "agadsf"; // 有\0
b、用字符数组的方法保存字符串
char ch[]="dafasdf";// 有\0
c、字符串指针变量和字符数组的的区别
1、区别一,能否重新赋值问题
char ch[20]="xxxxx";
ch = "asdfasdf"; // 不可以的 ch是常量,存储的是数组的首地址
char *ss="xxxxxx"; //"xxxxxx" 0x01
ss = "xxx"; // 可以的,ss是指针变量,
2、区别二,存储的区别
char ch[10]="xxxx"; 存放的是栈区(可读可写) x x x x \0 0 0 0 0 0 0 0
ch[4]='A'
char *str ="pppp";存放的是常量区(只读)