全方面的带你认识指针——指针的详解

本文详细介绍了指针在编程中的基本概念,包括内存地址、操作符应用(如&和*)、一维和二维数组,以及指针的运算和实际利用。同时强调了指针的危险用法,如未初始化的指针和不正确的类型标定。

目录

前言:

一、初识指针

   1.内存和地址

   2.关于指针的操作符(&和*)

       a.&操作符

       b.*操作符

        c.二级指针 

   3. 数组

        a.一维数组

        b.二维数组

 二、指针的运用

   1.指针的运算+ - 

       a. + 操作符

       b. - 操作符

   2.指针的实际利用

3.指针的一些危险用法

        a.没有初始化指针变量就使用

        b.没有正确的对标指针变量


前言:

        指针是我们学习编程避不开的话题,它是编程中最重要的概念之一,很多初学者对它闻之色变、胆战心惊。虽然指针很重要,但并不代表它难如登天。


一、初识指针

   1.内存和地址

        我们知道在计算机处理数据的时候,数据是从内存中读取,处理完成后又放回内存之中,那计算机是如何管理那些内存的呢?

        其实是把内存分为一个一个的内存单元,每一个内存单元的大小为1字节,而1字节在计算机管理中为8个比特位。每个字节都有自己的内存单元编号(也叫地址),在C语言中给地址又取了新的名字:指针

        所以内存单元编号==地址==指针


   2.关于指针的操作符(&和*)

       a.&操作符

        如果我们想要得到一个整形a的地址,我们只需要用到‘&’操作符。(注:这里使用的是x86(也就是32位)的环境,不同的环境打印出来的地址长度可能不同)

#include <stdio.h>
int main()
{
    int a =10;//创建一个整形a。
    printf("a的地址:%p",&a);//%p用来打印地址。
    return 0;
}

结果如下:

       b.*操作符

         如果我们要改变一个数,我们可以直接用它的变量名称来改变,也可以直接“上门”改变(通过指针变量来找到它的地址)它的数。

#include <stdio.h>
int main()
{
    int a =10;//创建一个整形a。
    int* pa = &a;//这里创建一个指针变量来接收a的地址。
    *pa = 20;
    printf("*pa=%d\n",*pa);//打印观察a是否发生变化。
    printf("a=%d\n",a);
    return 0;
}

结果如下:

        c.二级指针 

        那否也能指针变量的地址,然后存到另一个指针变量里面呢?(这里ppa叫做二级指针)

#include <stdio.h>
int main()
{
    int a =10;//创建一个整形a。
    int* pa = &a;//这里创建一个指针变量来接收a的地址。
    int* *ppa = &pa; //这里的ppa叫做二级指针。   
    *pa = 20;
    **ppa = 30;

    printf("**ppa = %d,**ppa);//打印观察a是否发生变化。
    printf("*pa=%d\n",*pa);
    printf("a=%d\n",a);
    return 0;
}

结果如下:

         我们对照可以发现a和*pa的值都变了,所以我们的猜想成立,那是不是可以重复这个操作呢?答案是肯定的,但我们并不需要这么多的指针变量(一般最多就用二级指针)


   3. 数组

        a.一维数组

        数组是一个固定长度的存储相同数据类型的数据结构,数组中的元素被存储在一段连续的内存空间中。它是最简单的数据结构之一。

        但与此同时在一般的编译器里数组名其实是它的首元素的地址。(但有两个例外sizeof(数组名)和&数组名)

#include <stdio.h>
int main()
{
    int a[3] = {1,2,3};
    printf("a = %p\n",a);
    printf("&a = %p\n",&a); 
    return 0;
}

结果如下:

        或许有人发现这俩的地址打印出来的结果一样,那它们俩的作用效果会不会也是一样的呢?

(这里先卖一个小关子,后面我会写出它们的不同) 

        b.二维数组

        二维数组与一维数组差不多


    int a[2][2] = {1,2,3,4};//创建一个数组
    //若要存放一个二维数组的地址&a应该如何存放。
    int (*pa)[2] = &a;//这里的pa其实存放了二维数组a第一行的地址。
    //此时的pa+1就代表了a的第二行的地址

 二、指针的运用

   1.指针的运算+ - 

                下面我用几个例子来解释。

       a. + 操作符

#include <stdio.h>
int main()
{
    int a[10] = {1,2,3,4,5,6,7,8,9,10};//创建一个数组
    int* pa = a;//这里的a是首元素的地址,所以不用&操作符
    for(int i = 0; i < 10; i++)
    {
        (*pa)++;①
        pa++;②
    }
    return 0;
}

        这里最开始的*pa是代表a[0],而操作①是a[0]++,而开始pa指向的是a[0]的地址,当操作②后,pa指向的地址是a[1]了,同时*pa代表a[1],然后循环操作。最终结果应该如下

       b. - 操作符

        既然地址可以用 + 操作符,那 - 操作符呢?

#include <stdio.h>
int main()
{
    int a[10] = {1,2,3,4,5,6,7,8,9,10};//创建一个数组
    int count = &a[10] - &a[0];
    printf("count = %d\n",count);
    return 0;
}

结果如下:

         这里我们其实可以得到一个结论:俩个处于同一块空间的数组的不同地址,相减得到的数的绝对值是它们之间的元素个数。


   2.指针的实际利用

        或许会有人说,想要改变一个值还不简单,直接用它的变量名改就可以了,但真的这么简单就可以完成C语言的基本操作了吗?

        若我们要交换两个值,我们可能会写出下面的代码。

#include <stdio.h>
int main()
{
    int a = 10;
    int b = 20;
    int tmp = a;
    a = b;
    b = tmp;
    return 0;
}

这个代码改变了ab的值吗?答:确实改变了。

        那如果要求在一个Swap()函数里改变两个变量的值呢?

#include <stdio.h>

void Swap(int x,int y)
{
    int tmp = x;
    x = y;
    y =tmp;
}

int main()
{
    int a = 10;
    int b = 20;
    Swap(a,b);
    return 0;
}

上面的代码改变了ab的值了吗?答:并没有。因为在Swap()函数中传过去的是实际参数,而接受的是形式参数,而形式参数的改变并不能改变实际参数。我们只需将上面的代码改为下面的就可以了。

#include <stdio.h>

void Swap(int* x,int* y)
{
    int tmp = *x;
    *x = *y;
    *y =tmp;
}

int main()
{
    int a = 10;
    int b = 20;
    Swap(&a,&b);
    return 0;
}

这样ab的值就交换了,因为我们是直接从地址上找到ab然后改变它们。


3.指针的一些危险用法

        首先,我们要有一个野指针的概念,野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)。

        a.没有初始化指针变量就使用

#include <stdio.h>
int main()
{
    int *p;
    *p = 20;//err
    return 0;
}

 上面的代码就是错误的,产生了野指针。

        b.没有正确的对标指针变量

#include <stdio.h>
int main()
{
    char c = 'a';
    int *p = (int*)&c;//err
    return 0;
}

这里的cchar类型,占1字节,但我们用了4个字节的int类型指针来存放c,若改变了*pc就会改变4个字节,但c若要改变应只要改变1字节,可想而知,可能会发生一些不可预测的错误。

指针是C编程语言中非常重要的概念之一,对于初学者来说可能会感到害怕和困惑。但只要理解了指针的原理和用法,就会发现它其实并不可怕。 首先,指针是一个存储变量地址的变量,它可以指向任何数据类型的变量,包括整型、浮点型、字符型等等。我们可以通过指针访问变量的值,也可以通过指针修改变量的值,这是指针的一大优势。 其次,理解指针的应用场景能够帮助我们更好地使用它。比如,当我们需要在函数之间传递大量的数据时,通过传递指针可以提高程序的执行效率。另外,在动态内存分配和释放中,指针也是一个必不可少的工具。 理解指针的用法也是很重要的。首先,我们需要理解指针的声明和初始化。指针的声明使用“类型 * 变量名”的语法,例如 int *ptr; 表示声明了一个指向整型变量的指针指针的初始化可以通过给指针赋值一个变量的地址或者通过取地址符&获取变量的地址。 然后,我们需要了解指针的运算。指针可以进行四种基本的运算:取地址运算符&,取值运算符*,指针加法和指针减法。取地址运算符&用于获取变量的地址,取值运算符*用于获取指针所指向的变量的值。指针加法和指针减法用于指针地址的增加和减少,不同数据类型的指针相加或相减会有不同的结果。 最后,我们需要注意指针的安性。在使用指针的过程中,需要特别小心避免空指针、野指针等问题的出现,因为这些问题容易引发程序的崩溃或者产生不可预知的结果。 总结来说,指针作为C语言中的重要概念,我们应该尽早学习和掌握。只要理解指针的原理和用法,我们就能够更加灵活地操作内存,提高程序的效率和功能。通过不断的实践和学习,我们可以逐渐摆脱对指针的恐惧,让指针成为我们编程的得力助手。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值