【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[n]

#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[n];   //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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值