【C语言】指针基础
文章目录
运算符&
获得变量的地址,操作数必须是变量
int i;
printf("%p",&i);
比如定义一个整型数组
#include <stdio.h> main() { int num[10]; printf("%p\n",&num); printf("%p\n",num); printf("%p\n",&num[0]); printf("%p\n",&num[1]); return 0; }
输出
我们发现相邻整型数组元素之间的地址差是4,如果数组改成double的会是多少呢?
指针
保存地址的变量称为指针
int i;
int* p = &i;
int* p,q;int *p,q; //p是指针,q是int变量
指针获取变量的地址后可以直接对变量进行读取或修改(比如在其他子函数内修改主函数中的变量)
*p == i
例如
#include <stdio.h> void f(int* p); main() { int i = 6; int* p = &i; f(p); printf("%d\n",i); return 0; } void f(int* p){ printf("%p\n",p); printf("%d\n",*p); *p = 7; }
运行结果如下
&*符号作用相反
&符号区变量值所保存的地址,*符号取地址保存的变量值;
指针应用场景
1、函数需要返回多个值,某些值就只能通过指针返回;
2、 函数返回运行状态,指针返回函数结果;
指针做除法运算实例:
#include <stdio.h> int f(int a,int b,int* result); main() { int a,b; printf("请输入分子分母a b:"); scanf("%d %d",&a,&b); int result = 0; int* p = &result; if ( f(a,b,p) ){ printf("a/b=%d\n",result); }else{ printf("运算失败\n"); } return 0; } int f(int a,int b,int* result){ int ret = 1; if ( b == 0 ){ ret = 0; }else { *result = a/b; } return ret; }
指针与const
方式一
int* const q =&i; //指针地址q是const
*q = 26; //OK
q++; //ERROR
方式二
const int *p = &i; //(*p)是const,指针地址里面的值不能修改,与int const *p一样,关键看*号位置
*p = 26; //ERROR
i = 26;
p = &j;
const数组
const int a[] = {1,2,3,4,};
表明数组的每个单元都是const int,必须通过初始化进行赋值。
指针运算
指针q+1,对于char类型的是加1,int类型的是加4
sizeof(char)=1;sizeof(int)=4
指针的数据类型要与变量的数据类型一致,要不会发生类型转换,输出结果可能会不符合预期。
结合数组使用指针加法,要不得到的地址没有实际应用意义
*p = a[0]
*(p+n)=a
#include <stdio.h> main() { int a[] = {0,1,2,}; double b[] = {0,1,2,}; int *p = a; printf(" p=%p\n",p); printf("p+1=%p\n",p+1); double *q = b; printf(" q=%p\n",q); printf("q+1=%p\n",q+1); return 0; }
使用*p++输出数组(速度比较快)
#include <stdio.h> main() { int a[] = {0,1,2,-1}; int *p = &a[0]; while ( *p != -1 ){ printf("*p=%d\n",*p++); } return 0; }
0地址
物理内存0地址通常是不能随便碰的地址,程序运行的时候都会又一个虚拟0地址;指针不应该具有0值。
一般用NULL符号表示0地址,当指针定义为NULL表示
1、返回的指针是无效的;
2、指针没有真正的初始化(先初始化为0)
试图往0指针地址写东西会导致程序崩溃。
指针类型转换
void* 表示不知道指针地址存储内容的数据类型
指针强制类型转换
int *p = &i;void q = (void)p;
实例演示
#include <stdio.h> main() { int i = 6; int *p = &i; void*q = (void*)p; int *t = (int*)q; double *w = (double*)q; printf("p=%p\n",p); printf("q=%p\n",q); printf("*p=%d\n",*p); printf("*t=%d\n",*t); printf("*w=%f\n",*w); return 0; }
指针应用
1、需要传入较大的数据时使用指针做参数
2、传入数组后对数组做操作
3、函数返回不止一个结果
–>需要函数来修正不止一个变量
4、动态申请内存时
动态内存分布
int *p = (int*)malloc(n*sizeof(int));
给p分配了100个int字节空间的地址
如果是Linux环境可以通过man malloc查看用法
malloc应用实例1
定义大小可变的数组
更规范的可变数组定义请参考链接中的可变数组章节
https://blog.csdn.net/Sudley/article/details/94338680
#include <stdio.h> #include <stdlib.h> main() { int n; printf("请输入数组大小:"); scanf("%d",&n); //int a ; //C99可以直接用变量n定义数组大小 int* a; a = (int*)malloc(n*sizeof(int)); //借用内存,使用动态内存方式定义大小 int i; for (i=0;i<n;i++){ printf("输入第%d个值",i); scanf("%d",&a[i]); } printf("输入的第3个值为:%d\n",a[3]); free(a); //释放内存 return 0; }
如果系统空间不够,malloc申请失败会返回0或者NULL
测试系统提供给C程序的可支配内存大小
#include <stdio.h> #include <stdlib.h> main() { int count=0; void *p; while ( (p=malloc(100*1024*1024)) ){ count++; } printf("内存大小%dG\n",count); return 0; }
这个值在不同计算机以及不同运行状态下都是不一样的,下面是我windows下分别开了一个Linux虚拟机和两个Linux虚拟机的运行结果
free
free内存只能释放malloc定义的首地址,当指针发生运算后无法归还,下面的q可以归还,p++后无法释放p,以为此时的指针不是malloc动态分配的。
#include <stdio.h> #include <stdlib.h> main() { void *p=0; void* q=0; p=malloc(1*1); q = p; p++; printf("p=%p\n",p); printf("q=%p\n",q); free(q); free(p); return 0; }
常见问题
1、申请了没free(忘记或者没找到合适的free时机)、长时间运行导致内存下降甚至是溢出
2、double free
解决要点:
地址变了直接free
- c语言基础案例之指针
- IOS学习---C语言基础学习7(指针)
- C语言-指针的基础学习笔记(2)
- 黑马程序员--ios基础--c语言--指针
- 指针02 - 零基础入门学习C语言42
- C语言—指针基础(2:指针交换两个数)
- c语言基础(九)结构体指针
- C语言基础:C语言指针(3) - 指针的指针
- 指针01 - 零基础入门学习C语言41
- 黑马程序员---iOS基础---C语言中的指针
- 指针08 - 零基础入门学习C语言48
- c语言—指针基础(3:指针和数组的关系)
- 近来对指针基础、一二维数组的心得和linux下c语言的编程
- 黑马程序员-IOS基础之浅谈C语言指针
- C语言-指针的基础学习笔记(1)
- C语言之指针基础篇
- C语言基础:C语言指针(2) - 注意事项
- 指针01 - 零基础入门学习C语言41
- 指针06 - 零基础入门学习C语言46
- 指针08 - 零基础入门学习C语言48