目录
一.初始指针
1.引入 关于内存和地址
我们知道计算上CPU(中央处理器)在处理数据的时候,需要的数据是在内存中读取的,处理后的数 据也会放回内存中,那这些内存空间如何⾼ 效的管理呢? 其实也是把内存划分为⼀个个的内存单元,每个内存单元的⼤⼩取1个字节。
1byte = 8bit
1KB = 1024byte
1MB = 1024KB
1GB = 1024MB
1TB = 1024GB
1PB = 1024TB
其中,每个内存单元,相当于⼀个学⽣宿舍,⼀ 个⼈字节空间⾥⾯能放8个⽐特位,就好⽐同学们 住的⼋⼈间,每个⼈是⼀个⽐特位。 每个内存单元也都有⼀个编号(这个编号就相当 于宿舍房间的⻔牌号),有了这个内存单元的编 号,CPU就可以快速找到⼀个内存空间。
在计算机中我们把内存单元的编号称为地址,C语⾔中给地址起 了新的名字叫:指针
2.各指针变量基本含义
理解指针,首先要了解取地址操作符(&)
#include <stdio.h> int main() { int a = 10; printf("%p\n", &a);//%p打印出&a取出的地址,即a的地址 return 0; }
而这样的地址值存放在哪⾥呢?答案是:指针变量中。
#include <stdio.h> int main() { int a = 10; int* pa = &a;//取出a的地址并存储到指针变量pa中 //这⾥pa左边写的是int* ,*是在说明pa是指针变量,⽽前⾯的int 是在说明pa指向的是整型(int)类型的对象 return 0; }
要通过指针找到其指向的对象,这⾥必须学习⼀个操作符叫解引⽤操作符(*)
#include <stdio.h> int main() { int a = 100; int* pa = &a; *pa = 0; //a的值变为0 return 0; }
类型
①整形指针 int *p
②字符指针 char *p
③数组指针变量
int arr[10] = {0}; &arr;//得到的就是数组的地址 //如果要存放个数组的地址,就得存放在数组指针变量中,如下: int(*p)[10] = &arr
④函数指针
函数名就是函数的地址
函数指针变量的使用
#include <stdio.h> int Add(int x, int y) { return x+y; } int main() { int(*pf)(int, int) = Add; printf("%d\n", (*pf)(2, 3)); printf("%d\n", pf(3, 5)); return 0; }
输出结果:
5
8
3.野指针
成因
1.指针未初始化
2.指针越界访问
3. 指针指向的空间释放
#include <stdio.h> int* test() { int n = 100; return &n; } //离开函数text,n的空间被释放了 int main() { int*p = test(); printf("%d\n", *p); return 0; }
4.⼆级指针
指针变量也是变量,是变量就有地址,那指针变量的地址存放在哪⾥?
①含义
指向指针的地址,对其解引用得到指针指向的变量的地址
#include<include.h> int main() { int a=0; int *pa=&a; int **ppa=&pa; return 0; }
二.指针的使用
1.指针的运算
①指针+-整数
(1)
#include <stdio.h> int main() { int n = 10; char *pc = (char*)&n; int *pi = &n; printf("%p\n", &n); printf("%p\n", pc); printf("%p\n", pc+1); printf("%p\n", pi); printf("%p\n", pi+1); return 0; }
运行之后可以看出, char* 类型的指针变量+1跳过1个字节,int* 类型的指针变量+1跳过了4个字节, 这就是指针变量的类型差异带来的变化。
(2)
#include <stdio.h> int main() { int arr[10] = {1,2,3,4,5,6,7,8,9,10}; int *p = &arr[0]; int i = 0; int sz = sizeof(arr)/sizeof(arr[0]); for(i=0; i<sz; i++) { printf("%d ", *(p+i));//p+i } return 0; }
因为数组在内存中是连续存放的,只要知道第⼀个元素的地址,顺藤摸⽠就能找到后⾯的所有元素。
②指针-指针
#include <stdio.h> int my_strlen(char *s) { char *p = s; while(*p != '\0' ) p++; return p-s; //得出两指针之间的元素数 } int main() { printf("%d\n", my_strlen("abc")); return 0; }
只有在同一区域同类型的指针可以做差
③指针的关系运算
指针可以比较大小
2. 使⽤指针访问数组
①数组名的理解
一般表示表示数组首元素的地址
当出现&arr或者sizeof(arr)时,才表示为整个数组
并且arr与&arr的地址值相同,不过二者类型不同
②具体代码
#include <stdio.h> int main() { int arr[10] = {0}; int* p = arr; for(i=0; i<sz; i++) { scanf("%d", p+i); //或者这样 scanf("%d", arr+i); } for(i=0; i<sz; i++) { printf("%d ", *(p+i));//或者这样 printf("%d ", p[i]); } return 0; }
3.指针传参
void test(int arr[])//参数写成数组形式,本质上还是指针 { printf("%d\n", sizeof(arr)); } void test(int* arr)//参数写成指针形式 { printf("%d\n", sizeof(arr));//计算⼀个指针变量的⼤⼩ } int main() { int arr[10] = {1,2,3,4,5,6,7,8,9,10}; test(arr); return 0; }
总结:⼀维数组传参,形参的部分可以写成数组的形式,也可以写成指针的形式。
三. 关于指针较复杂的运用
1.指针数组
指针数组的每个元素都是⽤来存放地址(指针)的, 指针数组的每个元素是地址,⼜可以指向⼀块区域。
指针数组的使用类似于二维数组
#include <stdio.h>
int main()
{
int arr1[] = {1,2,3,4,5};
int arr2[] = {2,3,4,5,6};
int arr3[] = {3,4,5,6,7};
//数组名是数组⾸元素的地址,类型是int*的,就可以存放在parr数组中
int* parr[3] = {arr1, arr2, arr3};
int i = 0;
int j = 0;
for(i=0; i<3; i++)
{
for(j=0; j<5; j++)
{
printf("%d ", parr[i][j]);
}
printf("\n");
}
return 0;
}
2.函数指针
函数指针变量的使用:通过函数指针调⽤指针指向的函数。
#include <stdio.h>
int Add(int x, int y)
{
return x+y;
}
int main()
{
int(*pf3)(int, int) = Add;
printf("%d\n", (*pf3)(2, 3));
printf("%d\n", pf3(3, 5));
return 0;
}
输出结果:
5
8