掘金 后端 ( ) • 2024-04-02 09:43

C语言指针是C语言中最重要的概念之一。它是一种特殊的变量,它存储了一个内存地址,这个内存地址指向另一个变量的位置。在C语言中,指针是一种非常有用的工具,可以用来处理内存中的数据,使代码更加高效和灵活。本文将从地址、数组、指针的概念解释、指针的命名、指针变量概念解释、&符号的作用、*符号的作用、指针的偏移、指针常量、常量指针的区别等多个方面,来剖析C语言指针的基础知识。

基本概念解释

在开始学习指针之前,我们需要先了解一些相关的概念。

  • 地址:是数据在内存中的存储位置编号,是一个常量。
  • 数组:是一组相同类型的数据的集合,数组名本身就表示这个数组的首地址。
  • 指针:本质上就是地址。

指针的命名和定义

指针的命名遵循类型 *指针变量名的命名规则,其中*符号表示这是一个指针变量。例如,int *p表示定义了一个指向整型数据的指针变量p。

指针变量的使用

指针变量存储的数据是地址,我们可以使用指针变量来访问对应地址的数据。例如,我们可以通过以下代码来获取数组arr的首地址并赋值给指针变量p:

#include <stdio.h>

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

这里的*p表示访问p所指向的地址上的值,也就是arr[0]的值。
运行输出

为了顺口,指针变量一般简称为指针。

另外所有类型的指针变量,在64位系统中都占8个字节的内存,在32位系统中都占用4个字节的内存,例如以下代码打印不同类型指针变量的内存占用:

#include <stdio.h>

int main()
{
    char *cp = NULL;
    int *ip = NULL;
    double *dp = NULL;
    printf("char p size: %zd\n", sizeof(cp));
    printf("int p size: %zd\n", sizeof(ip));
    printf("double p size: %zd\n", sizeof(dp));
    
    return 0;
}

运行输出

&符号的作用

&符号是取地址符,指针变量取了谁的地址,就指向谁。例如,我们可以通过以下代码来获取变量a的地址并赋值给指针变量p:

#include <stdio.h>

int main()
{
    int a = 0;
    int *p = &a;
    printf("%p\n", p);
    
    return 0;
}

运行输出

*符号的作用

*符号有两个作用:一是指针变量的标识,二是解引用,取内容。例如,我们可以通过以下代码来获取指针p所指向的地址上的值:

#include <stdio.h>

int main()
{
    int a = 0;
    int *p = &a;
    printf("%d\n", *p);
    
    return 0;
}

运行输出

指针的偏移

指针的偏移是指指针变量在内存中向前或向后移动一定的偏移量。例如,我们可以通过以下代码来实现指针的偏移:

#include <stdio.h>

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

指针p += 1,+1代表偏移1次指针对应类型的内存值,运行输出
在char数组中,char指针偏移1个字节相当于指向下一个索引,在int数组中,char指针需要偏移4个字节才能指向下一个索引,以下为演示代码,偏移达到4个字节时,才指向arr[1]

#include <stdio.h>

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

运行输出

指针常量和常量指针

指针常量和常量指针是指针的两种特殊类型。
以下是两者的区别:

指针常量:

  1. 定义时需要初始化
  2. 定义方式:*标识在前,const常量标识在后,如int * const p
  3. 不可改变指向,可改变内容
#include <stdio.h>

int main()
{
    int a = 10;
    int b = 20;
    // int* const p;
    // p = &a; // error: assignment of read-only variable ‘p’
    int* const p = &a; // success
    printf("%d\n", *p);
    
    // p = &b; // error: assignment of read-only variable ‘p’
    *p = 100; // success
    printf("%d\n", *p);
    printf("%d\n", a);

    return 0;
}

运行输出

定义指针常量p时,必须通过一次操作完成初始化,如int* const p = &a;,如果分两次操作int* const p; p = &a;赋值则会报错,因为指针常量不可改变指向(即地址值)。
定义指针常量后可改变内容,如p原来内容为a的值,等于10,通过操作*p = 100;变为了100,同时a的值也变为了100;

常量指针:

  1. 定义时不需要初始化
  2. 定义方式:const常量标识在前,*标识在后,如const int *p
  3. 可改变指向,不可改变内容
#include <stdio.h>

const int* p;

int main()
{
    int a = 10;
    int b = 20;
    
    p = &a;
    printf("%d\n", *p);
    // *p = 100; // error: assignment of read-only location ‘*p’
    p = &b; // success
    printf("%d\n", *p);

    return 0;
}

运行输出

定义常量指针p时,可通过两步操作完成,const int* p; p = &a;,定义后可改变p的指向,如p原先指向a,打印输出为10,指向b后,打印输出为20。
定义常量指针后不可改变其内容,如通过操作*p = 100;赋值会报错。

总结

C语言指针是C语言中最重要的概念之一。它是一种特殊的变量,它存储了一个内存地址,这个内存地址指向另一个变量的位置。在C语言中,指针是一种非常有用的工具,可以用来处理内存中的数据,使代码更加高效和灵活。本文从地址、数组、指针的概念解释、指针的命名、指针变量概念解释、&符号的作用、*符号的作用、指针的偏移、指针常量、常量指针的区别等多个方面,来剖析C语言指针的基础知识。(Ps:前言偷懒当总结)