C语言程序设计——指针

一、指针基础(※以32位机器为例※)

指针是编程语言中的一个对象,利用地址,它的值直接指向存在电脑存储器中某个地方的值。

int a = 10; //在内存中开辟一块空间给a,存储a的值

int *p = &a; //利用&操作符,取出a的地址,存放在p中,p就是一个指针变量

 总结:指针就是变量,是用来存放地址的变量。(存放在指针中的值都当成地址处理

为每一个地址分配一个对应的字节。针对32位机器,有32根地址线,因而可以有2^32个地址。那么编址的空间大小为2^32/1024/1024/1024GB == 4GB。  同理,指针在64位机器上自然就是8个字节。

int main()
{
    printf("%d\n",sizeof(char*)); //4
    printf("%d\n",sizeof(int*)); //4
    printf("%d\n",sizeof(short*)); //4
    printf("%d\n",sizeof(double*)); //4

    return 0;
}

此时不禁发出疑问,既然指针类型的大小都是4个字节,那么不同指针类型之间有什么区别呢?

① 指针类型如果对应错误,可能在部分编译器内无法通过。

② 指针类型决定了在进行解引用操作时能够访问空间的大小。

        int *p;        *p能够访问4个字节

        char *p;        *p能够访问1个字节

        double *p;        *p能够访问8个字节

 所以对于一个int型变量,如果用char*等类型进行访问修改,因为不能完全访问int的所有储存,所以修改不能覆盖到所有空间。

③ 指针的类型决定了指针向前或者向后走一步有多大。

指针+(-)整数  的时候,由于空间大小不同,所以运算所访问的空间也就不同。

int *pa = &a;
char * pc = &a;

pa与pc是相同的,但是pa+1和pc+1就不一样了,前者是int型所以加了四个字节,后者是char型所以加了一个字节。

二、野指针

野指针是指指针指向的位置不可知(随机的、不正确的、没有明确限定的)

野指针形成原因

1.指针未初始化

int main()
{
    int *p;//局部变量指针未初始化,默认为随机值
    *p = 20;
    return 0;
}

2.指针越界访问

int main()
{
    int arr[10] = {0};
    int *p = arr;
    int i = 0;
    for(i = 0;i<11;i++)
    {
        //当指针指向的范围值超出数组arr的范围时,p就是野指针
        *(p++) = i;
    }
    return 0;
}

 3.指针指向的空间释放

int* test()
{
    int a = 10;
    return &a;
}

int main()
{
    int *p = test();
    *p = 20;

    return 0;
}

当地址返回后,变量被注销,地址对应的位置不再是该变量,所以成为了野指针。

在编写代码的过程中一定要避免野指针的出现,当需要一个指针变量但却暂时不需要赋值时,可以置为空:

int *pa = NULL;

 三、指针运算

1.指针加减整数

指针加减整数根据类型而定访问下一个地址,在上文已经介绍。

int main()
{
    int arr[10] = {1,2,3,4,5,6,7,8,9,10};
    int i = 0;
    int sz = sizeof(arr)/sizeof(arr[0]);
    int* p = arr;
    for(i = 0;i<sz;i++)
    {
        printf("%d ",*p);
        p++;
    }
    return 0;
}

2.指针减指针

指针之间的相减的结果是两个位置之间所相隔的元素个数。多用于单个数组内部元素的计算,因为数组的存储是连续的,如果让两个数组之间作差,那么因为不连续所以结果不可知、无意义。

int main()
{
    int arr[10] = {1,2,3,4,5,6,7,8,9,10};
    char ch[5] = {0};
    printf("d\n",&arr[9] - &arr[0]); //9
    printf("d\n",&arr[0] - &arr[9]); //-9
    printf("d\n",&arr[9] - &ch[0]);//error
    return 0;
}

通过指针减指针的方法模拟strlen函数

int my_strlen(char* str)
{
    char* start = str;
    char* end = str;
    while(*end != '\0')
    {
        end++;
    }
    return end - start;
}

int main()
{
    char arr[] = "hello";
    int len = my_strlen(arr);
    printf("%d\n",len);
    return 0;
}

3.指针的关系运算

指针之间可以进行关系运算(即大小比较),判断地址的大小。

四、指针和数组

一般情况下,数组名实际上是数组首元素地址。arr <=> &arr[0]

※有两个例外:

1)&数组名:数组名表示的是整个数组,取出的是整个数组的地址。

2)sizeof(数组名):数组名表示的是整个数组,计算的是整个数组的大小。

int main()
{
    int arr[10] = {0};

    printf("%p\n",arr); //00EFF8E0
    printf("%p\n",arr+1); //00EFF8E4

    printf("%p\n",&arr[0]); //00EFF8E0
    printf("%p\n",&arr[0]+1); //00EFF8E4

    printf("%p\n",&arr); //00EFF8E0
    printf("%p\n",&arr+1); //00EFF908

    return 0;
}

通过代码运算结果,可以发现对arr与&arr[0]进行+1运算,地址变大了4(即一个int空间),而&arr进行+1运算,地址变大了40(arr数组的空间)。

五、二级指针

一个指针变量可以存一个变量的地址,那么创建这个指针变量也需要向系统申请一块空间,所以指针变量也应该具有对应的地址,那么把这个指针变量的地址存在另一个指针变量内,这个指针变量就应该是二级指针。同理可以得到三级等的指针。

int a = 10;

int* pa = &a;

int** ppa = &pa; //二级指针

int*** pppa = &ppa; //三级指针

六、指针数组

顾名思义,就是由指针组成的数组。

int a  = 0,b = 0,c = 0;

int* pa = &a,pb = &b,pc = &c;

int* arr[3] = {pa,pb,pc};

七、const修饰指针变量

const修饰指针有两种情况:

1)const 放在指针变量的*左边:        const int* p = &num;

修饰的是*p,使得*p成为只读变量,不能通过p来改变*p(num)的值。

2)const 放在指针变量的*右边:        int *const p = &num; 

 修饰的是指针变量p本身,使得p成为只读变量,不能再改变p。

#include <stdio.h>
#include <assert.h>

int my_strlen(const char* str)
//const 修饰*str,使得不会在函数内通过指针的方式改变原指向对象变量赋值
{
    int count = 0;
    assert(str != NULL); //断言,以保证指针的有效性,当条件为假时会报错

    while(*str != '\0')
    {
        count++;
        str++;
    }
    return count;
}

int main()
{
    char arr[] = "abcdef";
    int len = my_strlen(arr);
    printf("%d\n",len);
    return 0;
}

本文为学习C语言心得与笔记记录,部分举例来源于B站C语言教学up主鹏哥 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

犀利卓

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值