指针
Byte字节作为内存最小单元
int占用4个字节
1.内存地址和指针
变量存放在内存当中 ------>找到变量在内存当中的位置 就可以操作这个变量
数组元素的首地址--->地址
在形参中传参主要的是传递的地址
指针存放地址的类型 指针通过地址 去访问 去修改变量的值
1.函数传参 2.使用堆内存
2.指针定义和使用方式
指针就是地址
指针变量用来存放地址
1 int *q = (int *)malloc(sizeof(int)* 100);//申请堆内存 第一个(int*)是强转 第二个(int)是申请int大小的空间 2 3 if (q == NULL) 4 { 5 printf("申请失败"); 6 getchar(); 7 return 0; 8 } 9 //q指向了这块空间的首地址 10 *q = 12;//===q[0] 11 *(q + 1) = 13;//===q[1] 12 q[2] = 14;//===(*q+2) 13 q[3] = 15; 14 for (size_t i = 0; i < 4; i++) 15 { 16 printf("%d ", q[i]); 17 } 18 q = (int*)realloc(q, sizeof(int)* 200);//把之前的100个int扩充到200个int 19 printf("重新分配后 "); 20 for (size_t i = 0; i < 4; i++) 21 { 22 printf("%d ", q[i]); 23 } 24 printf("q的值%p ", q); 25 free(q);//释放内存
int类型 double类型
如果只有一个地址 没法判断这个地方是什么类型的数据
指正是有类型的!!!
一个地址里面存放是int类型的值 int* 表示存放int类型的地址
一个地址存放的时候double类型的值
一级指针 地址存放基本数据类型
int float double char
%p输出地址
* 运算符 解引用
如果变量x的地址 存放在指针p 里面 p指向这个变量
int*类型的指针 指向int类型的变量
int y;
int*p;//定义一个指向int类型变量的指针
p=&y;//将y的地址 赋值给指针p
*p=2;//将y存放的内容赋值2 y就为2
printf("%p=%d",&y,y); &y输出y存放的地址
形参不能改变实参
需要在其他函数中 修改实参的值 通过传递地址的方式修改
类型* 指针变量名
int* p;//int* 表示指针类型 p表示变量名
一维数组 也可以用一级指针
数组名 vs 指针
数组名 表示数组的首地址 数组名不可以修改(视为常亮)
指针可以修改
sizeof求大小 数组名 得到的数组的大小
如果得到指针大小
1 void fun(int arr[][5])//形参实际上是指针 int*arr 2 { 3 int a=sizeof(arr[0]);//求的是形参的大小--->指针的大小 4 int b = sizeof(arr); 5 int c = sizeof(arr[0][0]); 6 printf("arr[0]的大小为:%d ", a);//数组定义的第一个元素的大小 7 printf("arr的大小为:%d ", b);//数组指针arr的大小 为4 8 printf("arr[0][0]的大小为:%d ", c); 9 }
int arr[10]
错误用法 arr++
数组名[下标]
数组名和指针 都可以用* []
指针 申请堆内存
程序运行的时候 代码数据 加载内存当中
内存四区
代码区 存放代码二进制
全局静态常量区(全局静态 常量区)
全局函数外定义的变量 作用域是整个程序
静态 static 修饰变量 用static修饰的变量存放在全局静态区
1 void fun2()//全局静态常量区 2 { 3 static int x = 0;//静态变量x 每次调用的时候运算结束 值都会改变 4 ++x; 5 printf("x=%d ", x); 6 }
常量区 存放一些数字常量或者字符常量
没法取到地址
栈区 局部变量(函数 循环里面定义变量) 形参
都会存放在栈区
栈区 小的空间 内存操作系统控制
4M
堆区 1G 需要申请释放 需要用到函数专门申请内存
申请内存需要用到指针
申请内存 malloc 用于申请内存
释放内存 free
realloc 内存重分配 在原有内存的基础上 加/减 内存
传参
int 有int* 一级指针 保留int的地址
int*p ---> p也是变量 p也有地址 如果得到p的地址 定义二级指针来接受p的地址
int** pp=&p; 二级指针
*pp --->得到的是pp指向的内容 也就是p
printf("%d
",x)
一维数组 传参 用一级指针
二维数组 传参 数组指针
int dArr[3][4]---->int (*pd)[4] 数组指针
1 void fun3(int(*pd)[4])//指针数组相当于int dArr[][4] 2 { 3 for (size_t i = 0; i < 12; i++) 4 { 5 printf("%d ",(*pd)[i]);//二维数组传入参数 利用指针可以用一级指针的方式进行保存 6 } 7 printf(" "); 8 for (size_t i = 0; i < 3; i++) 9 { 10 for (size_t j = 0; j < 4; j++) 11 { 12 printf("%d ",pd[i][j]);//二维数组进行二维数组下标的方式进行输出 13 } 14 } 15 }
1 void test()//数组指针vs指针数组 2 { 3 int(*pd)[10];//指针数组 数组的行号不定 列号为10 相当于pd[][10] 4 int* dArr[10];//数组指针需要申请堆内存 5 for (size_t i = 0; i < 10; i++) 6 { 7 dArr[i] = (int*)malloc(sizeof(int)* 4);//申请四个内存的空间 10行4列 相当于dArr[10][4] 8 } 9 for (size_t i = 0; i < 10; i++) 10 { 11 for (size_t j = 0; j < 4; j++) 12 { 13 dArr[i][j] = j; 14 printf("%d ", dArr[i][j]); 15 if (j == 3) 16 printf(" "); 17 } 18 } 19 20 for (size_t i = 0; i < 10; i++)//一个一个释放内存 21 { 22 free(dArr[i]); 23 } 24 }
[] 解引用
p[i]===*(p+i)
基本数据 int x --->实参 写整数或者整形变量
变量地址 修改变量的值 int*px 实参 变量地址
数组名 操作一维数组 int *px /int arr[] 实参一维数组的数组名
const 常属性 不可变 定义的还是变量
通过语法限定 x的值不可以修改 必须先定义后赋值
常量指针
const int* p;//int const *p const限定了p不能修改他指向的内容
指针常量
int* const q;
1 void test1()//const的妙用 2 { 3 int arr[10] = {0,1,2,3,4,5,6,7,8,9}; 4 const int* p;//const限定了这个p不能修改他指定的内容 即*p=0是错误的 5 p = &arr[0];//但是可以修改指针指向的地址 让p指向第一个元素 6 p++;//也可以进行后移一位进行指向下一个地址 7 //const在前*在后 是代表的常量指针 8 printf("p的地址是:%p ", p); 9 printf("p的值是:%d ",*p);//此时的p相当于p[1]===arr[1] 10 11 12 //const在*后面 指针常量 13 int* const q = &arr[0];//const 后面的q q在定义之后不能赋值 14 //q = &arr[0];//q的值不可修改 只能修改*q的值 15 *q = 0;//指针q可以去修改指向的内容 16 //使用指针传参 提高了效率 修改形参值 17 18 }
指针传参 提高效率 修改形参的值
函数指针 返回值为指针的函数 malloc作用申请内存 返回值是一个指针
函数指针 指向函数的指针
函数调用的过程 函数名--->函数 传递形参 计算 得到返回值 回到主函数
1 void *(*pfun)(size_t _Size); 2 pfun=malloc; 3 //pfun指向函数的地址---->利用pfun来调用这个函数 4 int *p=(int*)pfun(100*sizeof(int));
指针地址效果简介
1 #include<stdio.h> 2 int main() 3 { 4 int x=3; 5 int* p=&x; 6 int y=5; 7 *p=y; 8 printf("p的值:%d ",*p); 9 printf("p的地址:%d ",p); 10 printf("x的地址:%d ",&x); 11 printf("x的值:%d ",x); 12 printf("y的地址:%d ",&y); 13 printf("y的值:%d ",y); 14 getchar(); 15 return 0; 16 }
指针效果整体代码
#include<stdio.h> #include<stdlib.h>//malloc void fun(int arr[][5])//形参实际上是指针 int*arr { int a=sizeof(arr[0]);//求的是形参的大小--->指针的大小 int b = sizeof(arr); int c = sizeof(arr[0][0]); printf("arr[0]的大小为:%d ", a);//数组定义的第一个元素的大小 printf("arr的大小为:%d ", b);//数组指针arr的大小 为4 printf("arr[0][0]的大小为:%d ", c); } void fun2()//全局静态常量区 { static int x = 0;//静态变量x 每次调用的时候运算结束 值都会改变 ++x; printf("x=%d ", x); } void fun3(int(*pd)[4])//指针数组相当于int dArr[][4] { for (size_t i = 0; i < 12; i++) { printf("%d ",(*pd)[i]);//二维数组传入参数 利用指针可以用一级指针的方式进行保存 } printf(" "); for (size_t i = 0; i < 3; i++) { for (size_t j = 0; j < 4; j++) { printf("%d ",pd[i][j]);//二维数组进行二维数组下标的方式进行输出 } } } void test()//数组指针vs指针数组 { int(*pd)[10];//指针数组 数组的行号不定 列号为10 相当于pd[][10] int* dArr[10];//数组指针需要申请堆内存 for (size_t i = 0; i < 10; i++) { dArr[i] = (int*)malloc(sizeof(int)* 4);//申请四个内存的空间 10行4列 相当于dArr[10][4] } for (size_t i = 0; i < 10; i++) { for (size_t j = 0; j < 4; j++) { dArr[i][j] = j; printf("%d ", dArr[i][j]); if (j == 3) printf(" "); } } for (size_t i = 0; i < 10; i++)//一个一个释放内存 { free(dArr[i]); } } void test1()//const的妙用 { int arr[10] = {0,1,2,3,4,5,6,7,8,9}; const int* p;//const限定了这个p不能修改他指定的内容 即*p=0是错误的 p = &arr[0];//但是可以修改指针指向的地址 让p指向第一个元素 p++;//也可以进行后移一位进行指向下一个地址 //const在前*在后 是代表的常量指针 printf("p的地址是:%p ", p); printf("p的值是:%d ",*p);//此时的p相当于p[1]===arr[1] //const在*后面 指针常量 int* const q = &arr[0];//const 后面的q q在定义之后不能赋值 //q = &arr[0];//q的值不可修改 只能修改*q的值 *q = 0;//指针q可以去修改指向的内容 //使用指针传参 提高了效率 修改形参值 } void test2() { void *(*pfun)(size_t _Size); pfun = malloc; //pfun指向函数的地址---->利用pfun来调用这个函数 int *p = (int*)pfun(100 * sizeof(int)); } int main() { int arr[4][5]; fun(arr); fun2(); fun2(); fun2(); int dArr[3][4] = {1,2,3,4,5,6,7,8,10,9,11,12}; fun3(dArr); printf(" "); int *q = (int *)malloc(sizeof(int)* 100);//申请堆内存 第一个(int*)是强转 第二个(int)是申请int大小的空间 if (q == NULL) { printf("申请失败"); getchar(); return 0; } //q指向了这块空间的首地址 *q = 12;//===q[0] *(q + 1) = 13;//===q[1] q[2] = 14;//===(*q+2) q[3] = 15; for (size_t i = 0; i < 4; i++) { printf("%d ", q[i]); } q = (int*)realloc(q, sizeof(int)* 200);//把之前的100个int扩充到200个int printf("重新分配后 "); for (size_t i = 0; i < 4; i++) { printf("%d ", q[i]); } printf("q的值%p ", q); free(q);//释放内存 printf("q的值%p ", q); //内存释放后 q指向的空间就不要访问 //q依然指向这个空间 释放之后再用就会出现问题 int x=2; int *p = &x;//一级指针存放x的地址 int **pp = &p; printf("x=%d ",x); printf("p=%d ", p);//x的地址====&x printf("pp=%d ", pp);//p的地址===&p printf("x的地址%d ", &x); printf("p的地址%d ", &p); printf("%d ", *pp);//x存放的地址===&x printf("%d ", **pp);//x的值===x printf("%d ", *p);//x的值===x test(); test1(); test2(); getchar(); getchar(); return 0; }