C语言基础知识---指针

本文详细介绍了C语言中的指针概念,包括指针的定义、使用方法、解引用、指针运算及常见问题。通过示例阐述了指针在函数参数传递、内存管理、数组操作等方面的作用,并探讨了空指针、野指针及其避免策略。此外,还讨论了二级指针、函数指针、指针数组和数组指针等高级话题。
摘要由CSDN通过智能技术生成

    什么是指针:

        1、指针是一种数据类型,使用它可以定义指针变量,简称指针。

        2、指针变量中存储的是内存地址(整数,便签的编号),可以通过它访问对应的内存。

        3、以32位系统为例,指针变量需要占用4字节内存空间(64系统需要8字节),指针变量的取值范围:0x00000000~0xffffffff,每个整数代表一个字节的内存,指针变量最大可以访问4G内存(64位系统的指针变量则需要占用8字节内存空间)。

        4、可以使用printf("%p\n",ptr) 显示指针变量的值。

如何使用指针:

    定义指针变量:类型* 指针变量名;

        1、指针变量与普通变量的使用方法不同,因此为区别与普通变量,一般指针变量以p结尾。

        2、指针变量不能连续定义,一个*只能定义出一个指针变量。

        指针变量    int* p1,p2; //  p1是,p2普通的int类型变量

                               int *p1,*p2; // p1,p2都是指针变量

        3、指针变量中存储的整数只代表一个字节,当通过指针变量访问内存时,具体访问多少个字节由指针变量的类型决定,也就是说指针变量中存储的是一块内存的首地址。

        4、指针变量的默认值与普通变量一样是随机的(野指针),一般为了安全要给指针变量初始化,如果没有合适的内存地址可以先初始化NULL(空指针)

    给指针变量赋值:指针变量 = 内存地址;

        // 定义指针变量时初始化

        int* p = # // 获取变量的地址赋值给指针变量,num变量的类型要与指针变量相同,否则编译器会产生警告,在解引用时也可能产生段错误

        // 定义完指针变量后再赋值

        p = malloc(4); // 把堆内存的地址赋值给指针变量,堆内存的使用后续会详细讲解

    根据指针变量中存储的内存地址访问内存(解引用)*指针变量

        int num = 1234;

        int* p = #

        *p <=> num; // *p 等价于 num

    指针变量解引用时,具体访问多个少字节数由指针变量的类型决定:

            char* p; // *p 访问一个字节

            short* p; // *p 访问两个字节

            double* p; // *p 访问4个字节

            int* p; // *p 访问4字节内存

            long long* p; // *p 访问8字节内存

    指针变量解引用时可能出现段错误的原因:

        1、指针变量中存储的是无效的内存地址(不在maps文件里的地址范围内)。

        2、指针变量中存储的是具有只读权限的内存地址,通过指针变量修改内存时也会产生段错误。

        const int num = 1234;   // num使用的是代码段内存

        int main()

        {

            int* p = (int*)&num;

            *p = 6666; // 强行修改只读权限的内存,会产生段错误

        }

        3、指针变量中存储的是NULL,解引用时肯定产生段错误。

      4、内存块的大小与指针的类型不匹配

                int num;

                long long* p = (long long*)&num;

                *p = 0xffffffffffffffffull; // 内存越界,可能产生段错误

        总结:当指针变量解引用时产生段错误,要在指针变量赋值时改正。

为什么要使用指针:

    1、使用指针可以在函数之间共享变量

        使用全局变量可以在函数之间共享变量,但使用全局变量容易造成命名冲突,并且在程序运行期间全局变量所使用的data、bss、text内存不会被释放,这多使用全局变量容易造成内存浪费,尽量少使用全局变量,最好不用。

        当函数需要返回多个执行结果时,需要在函数之间共享变量,也就是共享变量地址,例如:scanf函数。

    2、适当的使用指针可以提高函数的传参效率

        c语言的函数传参是值传递(赋值、内存拷贝),比如:double,long double,long long,自定义类型(结构、联合、类),它们的字节数 > 4,如果直接传递变量的值则最少需要拷贝8字节内存数据,而传递变量的地址,只需要拷贝4字节内存数据。

        // 以下代码传递变量的地址比直接传递变量的值要节约一半的时间

        void func(long double* p)

        {

        }

        int main()

        {

            long double f = 3.14;

            for(int i=0; i<2000000000; i++)

            {

                func(&f);

                f+=1;

            }

        }

    3、使用堆内存必须与指针变量配合

        当 int num; 语句时,系统会分配4字节内存(text、data、bss、stack),并让这4字节内存与变量名num建立联系,在之后的代码中使用num就相当于4字节内存,我们把这种功能叫做给内存取名字。

        而堆内存无法取名字,当向系统申请一块内存时,系统会返回这块内存的首地址,这块内存无法与变量名建立联系,也就是无法取名字,需要指针变量存储内存的地址以便之后使用这块堆内存,所以说堆内存必须与指针变量配合使用。

   

练习1:实现一个交换两个整型变量的函数。

#include <stdio.h>

void swap(int* p1,int* p2)

{

int tmp = *p1;

*p1 = *p2;

*p2 = tmp;

/* 此方法只能适用于数值型变量交换

*p1 = *p1 + *p2;

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值