「C 语言」6 初识指针

初始指针

指针(pointer)是什么

一个变量,存放内存单元的地址

int a = 10;//内存中开辟一块空间
int* p = &a;//对变量a取出它的地址,用&操作符
            //将a的地址放在变量p中,p是一个指针变量,类型是int*

32位机器指针大小是4字节

64位机器指针大小是8字节

指针和指针类型

既然指针的大小都一样,那为什么要分int*, char*, 这些类型呢?

int main()
{
    int a = 0x11223344;
    int* pa = &a;
    char* pc = &a;
    printf("%p\n",pa);
    printf("%p\n",pc);//两个地址一样
    return 0;
}

指针类型的意义

解引用

实验:

int main()
{
    int a = 0x11223344;
    int* pa = &a;
    char* pc = &a;
    *pa = 0;//内存中a = 00000000
    *pc = 0;//内存中a = 00332211
    return 0;
}

类型决定指针解引用时访问空间的大小

即访问时的权限

指针+整数

int main()
{
    int a = 0x11223344;
    int* pa = &a;
    char* pc = &a;
    printf("%p\n",pa);//x
    printf("%p\n",pa+1);//x+4
    
    printf("%p\n",pc);//x
    printf("%p\n",pc+1);//x+1
    return 0;
}

指针类型决定了指针走一步走多远,即步长

应用

int main()
{
    int arr[10] = {0};
    int* p = arr;//数组名 - 首元素地址
    int i = 0;
    for (i = 0;i < 10;i++)
    {
        *(p+i) = 1;//将所有元素改为1
    }
    return 0;
}

野指针

野指针就是指针指向的未知是不可知的(随机的、不正确的、没有明确限制的)

分类

  1. 指针未初始化

    int* p,未初始化放的是随机值

    访问时就是非法访问

  2. 指针越界访问

    #include<stdio.h>
    
    int main()
    {
        int arr[10] = {0};
        int* p = arr;
        for (int i=0;i<=12;i++)
            *(p++) = i;//作用范围已经超过数组,即越界
        return 0;
    }
  3. 指针指向的空间释放

    int* test()
    {
        int a = 10;
        return &a;
    }
    
    int main()
    {
        int* p = test();
        *p = 20;//使用时已经释放
    }

规避方法

  1. 指针初始化

  2. 小心指针越界

  3. 指针指向空间释放即使置NULL

    int main()
    {
        int a = 10;
        int* pa = &a;
        int *p = NULL;//NULL - ((void*)0)
    }
  4. 指针使用前检查有效性

    if (pa != NULL)

指针运算

  • 指针+-整数
  • 指针-指针
  • 指针的关系运算

指针+-整数

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

指针-指针

int main()
{
    int arr[10] = {1,2,3,4,5,6,7,8,9,10};
    printf("%d",&arr[9] - &arr[0]);//打印中间元素的个数 - 9
    printf("%d",&arr[0] - &arr[9]);//-9
}

相减的两个指针一定要指向一个类型

模拟实现 strlen函数

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

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

指针的关系运算

即比较大小

//代码1
#define N_VALUES 5
float values[N_VALUES];
float* vp;
for (vp = &values[N_VALUES];vp>&values[0];)
{
    *--vp = 0;
}

//代码2
#define N_VALUES 5
float values[N_VALUES];
float* vp;
for (vp = &values[N_VALUES-1];vp>=&values[0];vp--)
{
    *vp = 0;
}

我们要用第一种方法来写

标准规定

允许指向数组元素的指针与指向最后一个元素后面的那个内存位置的指针比较,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较。

指针与数组

数组名是数组首元素的地址

  1. &arr,取的时整个数组的地址

    int arr[10] = {0};
    printf("%p\n",arr);//x
    printf("%p\n",arr+1);//x+4
    
    printf("%d\n",&arr[0]);//x
    printf("%d\n",&arr[0]+1);//x+4
    
    printf("%p\n",&arr);//x 整个数组的地址
    printf("%p\n",&arr+1);//x+40
  2. sizeof(arr),计算整个数组的大小

二级指针

int a = 10;
int* pa = &a;
int** ppa = &pa;//二级指针
int*** pppa = &ppa;//三级指针

指针数组

  • 指针数组 - 数组,存放指针的数组
  • 数组指针 - 指针
int main()
{
    int a = 10;
    int b = 20;
    int c = 30;
    int* arr[3] = {&a, &b, &c};
    for (int i = 0;i<3;i++)
    {
        printf("%d\n", *(arr[i]));
    }
}
#C #笔记
0%