您的位置:首页 > 编程语言 > C语言/C++

【C语言】指针基础

2019-06-30 22:11 21 查看
版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/Sudley/article/details/94357827

文章目录

运算符&

获得变量的地址,操作数必须是变量
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

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: