C语言指针详解

目录

前言

一.指针概念

1.1 指针的类型

1.2 指针所指向的类型

1.3 指针的值

1.4 &和*

1.5 指针的运算

二.指针与一维数组

2.1 一维数组

2.1.1 一维数组的初始化

2.2 指针与一维数组

三.指针与二维数组

3.1 二维数组

3.1.1 二维数组的初始化

3.2 二维数组与指针

3.2.1 二维数组与指针的关系

3.3 数组指针

3.4 指针数组

3.5 指针数组和数组指针

四.指针与字符串

4.1 字符数组

4.2 字符指针

五.指针函数与函数指针

5.1 指针函数

5.2 函数指针 


前言

        指针是C语言中的一个重要概念及其特点也是掌握 C语言比较困难的部分。 指针也就是内存地址 ,指针变量是用来存放内存地址的变量,不同类型的指针变量所占用的存储单元长度是相同的,而存放数据的变量因数据的类型不同,所占用的 存储空间 长度也不同。 有了指针以后,不仅可以对数据本身,也可以对存储数据的变量地址进行操作。 

一.指针概念

1.1 指针的类型

去掉指针本身剩下的就是指针的类型

  • int*ptr;//指针的类型是int*
  • char*ptr;//指针的类型是char*
  • int**ptr;//指针的类型是int**
  • int(*ptr)[3];//指针的类型是int(*)[3]
  • int*(*ptr)[4];//指针的类型是int*(*)[4]                                                                                        

1.2 指针所指向的类型

去掉指针本身和指针前面的*剩下的就是指针所指向的类                                                         

  • int*ptr; //指针所指向的类型是int
  • char*ptr; //指针所指向的的类型是char
  • int**ptr; //指针所指向的的类型是int*
  • int(*ptr)[3]; //指针所指向的的类型是int()[3]
  • int*(*ptr)[4]; //指针所指向的的类型是int*()[4]   

1.3 指针的值

        指针的值是指针本身存储的数值,这个值将被编译器当作一个地址,而不是一个一般的数值。在32 位程序里,所有类型的指针的值都是一个32 位整数,因为32 位程序里内存地址全都是32 位长。64位也是如此,在64位程序中,所有类型的指针的值都是64位整数。指针所存储的值是地址。

1.4 &和*

  • &:&在指针运算中为取地址符号
  • * :   *在指针运算中为获取地址所指向内存单元的值的符号
int* p;                      //定义指针
int a=1;                     //定义变量
p=&a;                        //赋值指针
printf("p:%d,a:%d",*p,a);  
运行结果
p:1a:1

&*p和*&p的区别:

因为*和&具有相同的优先级,且是右结合性(从右向左),故分析可得:

        1)&*p:相当于&(*p),首先进行一次*p运算再取地址。若p是一个非指针变量,*p是非法的;若p是一个指针变量,&(*p)=p;
        2)*&p:相当于*(&p),先取地址再做*运算。若p是一个非指针变量,*(&p)=p;若p是一个指针变量,*(&p)=p。

1.5 指针的运算

        对于指向数组的指针变量,可以加上或减去一个整数n,这意味着把指针从当前指向的位置(指向的某个数组元素)向后或向前移动n个位置。

这里应当注意:
        (1)数组指针变量向前向后移动一个位置和地址加1或减1在概念上是不同的。因为数组的元素可以由不同的数据类型,所占用的字节长度也是不同的。如指针变量加1,即表示指针变量指向下一个元素的首地址,而不是在原地址的基础上加1;
        (2)指针变量的加减运算只能对数组指针变量进行,对只想其他数据类型的指针变量做加减运算是毫无意义的。
        (3)两个指针变量之间的运算:只有指向同一数组的两个指针变量才能进行运算,否则运算是毫无意义的。
        (4)两指针变量相减:两指针变量相减所得之差,是两个指针所指向的数据元素之间相差的元素个数,乘以该数组每个数据元素的长度(字节数);
        (5)两指针变量相加:两指针变量不能进行加法运算,毫无实际意义。

int*p; //p所指向的类型为int类型

p++; //p+1地址数增加四个字节

char* p1; //p1所指向的类型为char类型

p1++; //p1+1地址数增加1个字节

二.指针与一维数组

2.1 一维数组

2.1.1 一维数组的初始化

(1)在定义数组时对所有数组元素赋初值

int data[5]={100,99,98,97,95};

(2)对数组部分元素赋初值

int data[5]={100,99};

将100、99赋给data[0]、data[1],其余数组元素自动赋值0。

(3)对全部数组元素赋处置,省略数组长度

int data[]={100,99,98,97,95};

将初值依次赋值给数组的各个元素,数组长度由初值个数决定

2.2 指针与一维数组

在c语言中,获取数组首地址的方法有两种:

        第一种用&运算符获取数组中头一个元素的地址,如&a[0]。

        第二种用数组名代表数组的首地址,所以语句“p=&a[0]”等价于“p=a”

        对于数组元素的访问,下标法和指针法是等价的。假设有一个数组a,指针p指向数组a的首地址,数组a的元素的表示方法有以下两种:

        (1)下标法:a[i]或p[i]

        (2)指针法:*(a+i)或*(p+i)

三.指针与二维数组

3.1 二维数组

3.1.1 二维数组的初始化

(1)按行给二维数组初始化

int socre[4][3]={{99,98,97},{96,95,94},{93,92,91},{90,89,88}}

999897
969594
939291
908988

(2)按排列数序初始化

int score=[4][3]{99,98,97,96,95,94,93,92,91,90,89,88}

(3)对部分元素赋初值

int socre[4][3]={{99,98},{96,95,}}

int score[4][3]={99,98,97,96,95,94,93,92}

对二维数组进行赋值,为赋初值的数组元素,系统自动赋值为0

(4)初始化时省略第一维长度

int socre[][3]={{99,98},{96,95,}}

int score[][3]={99,98,97,96,95,94,93,92}

3.2 二维数组与指针

3.2.1 二维数组与指针的关系

        在c语言中,二维数组可以看作是一维数组的嵌套而构成的,一个二维数组可以按行分解成多个一维数组。例如,有如下定义:

int a[3][4];

        二维数组a可分解为三个一维数组,其数组名分别为a[0],a[1],a[2]。每个一维数组有四个元素。

        c语言规定数组名代表数组的首地址,因此a[i]是第i行第0列的数组元素(a[i][0])的地址,即a[i]与&a[i][0]等价,即a[i]+j就是第i行第j列的数组元素a[i][j]的地址,即a[i]+j与&a[i][j]等价。所以对于二维数组a有以下关系:

(1)a[i]+j等价于&a[i][j]

(2)*(a[i]+j)等价于a[i][j]

        根据一维数组与指针的关系可知:a[i]等价于*(a+i),进而可推出二维数组与指针的关系:

(1)*(a+i)+j等价于&a[i][j]

(2)*(*(a+i)+j)等价于a[i][j]

3.3 数组指针

数组指针:指向数组的指针。

int(*p)[i];

p++;

首先要明确优先级顺序:()>[]>*

        (* p)[n]:根据优先级,先看括号内的,p是一个指针,指向一个一维数组,数组的长度是n,这是指向数组的指针,叫做数组指针。

        指针的类型为int(*)[i],指针所指向的类型为int()[i],在运行p+1时,p所指向的地址在原有的地址上增加sizeof(int)*i。

3.4 指针数组

指针数组:装着指针的数组。

int* p[4];
p++;

         *p[n]:根据优先级,先看[],则p是一个数组,再结合*,这个数组的元素是指针类型,共n个元素,是装着指针的数组,叫做指针数组。

        指针数组++是指将指向指针数组第一个元素的指针向后移动一个元素的位置。具体来说,如果有一个指针数组p,其中包含n个指针,每个指针指向不同的内存地址,那么p++将把指针向后移动一个元素的位置,即指向p[1]的指针。如果再执行p++,则指针将指向p[2],以此类推。

3.5 指针数组和数组指针

        指针数组和数组指针是两个不同的概念。

        指针数组是一个数组,其中的每个元素都是一个指针,每个指针指向不同的内存地址。例如,`int *ptrArr[10]`定义了一个包含10个指向int类型的指针的数组,每个指针都可以指向不同的int类型变量。

        数组指针是一个指针,它指向一个数组的首地址。例如,`int (*arrPtr)[10]`定义了一个指向包含10个int类型元素的数组的指针。在这种情况下,`arrPtr`指向的是整个数组,而不是数组中的一个元素。

        因此,指针数组和数组指针的本质区别在于它们的类型不同,一个是数组,一个是指针。指针数组中的每个元素都是一个指针,而数组指针指向的是一个数组。在使用时需要根据具体情况选择合适的类型。

问题指针数组名到底是数组名还是指针名?

        指针数组名既可以被视为指针名,也可以被视为数组名,具体取决于它的上下文环境。

        在指针数组作为函数参数传递时,指针数组名被视为指针名。因为在函数调用时,指针数组会被转换为指向其首元素的指针,并传递给函数。因此,指针数组名被视为指向数组首元素的指针名。

例如,下面的函数原型中,`ptrArr`被视为指向数组首元素的指针名:

void func(int *ptrArr[], int len);

        在指针数组被定义时,指针数组名被视为数组名。因为指针数组本质上是一个数组,指针数组名表示整个数组。在定义指针数组时,需要指定数组的长度,这个长度就是数组的元素个数。

例如,下面的定义中,`ptrArr`被视为数组名:

int *ptrArr[10];

        因此,指针数组名既可以被视为指针名,也可以被视为数组名,具体取决于它的上下文环境。

四.指针与字符串

4.1 字符数组

对字符数组的初始化有以下几种情形

(1)和其他数组一样,对字符数组逐个初始化

char str[5]={'a','b','c','d','\0'};

注意:c语言规定以字符'\0'作为字符串的结束标志。如果没有'\0',只能说数组str中存储了一串字符,但不能说str存储了字符串。

(2)用字符串直接初始化字符数组

char str[6]={"hello"};

char str[6]="hello";

        编译器将双括号括起来的字符依次赋值给字符数组的各个元素,并自动在末尾补上字符结束标志字符'\0',一起存在数组str中,所以数组的个数要比字符串中字符的个数要多一个。在输出字符串时,末尾'\0'不输出,只用于判断字符串是否结束。

char str[]="hello";

        按这种方式定义和初始化字符串数组,不必指定数组的大小,编译系统会根据字符串中字符的个数确定数组的大小。由于字符串常量"hello"的末尾字符时'\0',因此字符数组的长度为字符串的额中世纪的个数加1,即:字符数组str的长度为6。

4.2 字符指针

        字符指针时指向字符型数据的指针变量。每个字符串在内存中都占用一段连续的存储空间,并有唯一的首地址。因此,只要把字符串的首地址赋值给字符指针,即可让字符指针指向字符串。

char* p;

p="hello";

char str[]="hello";

char* p;

p=str; 

五.指针函数与函数指针

5.1 指针函数

1.指针函数的概念

        指针函数是一种特殊类型的函数,其特点是其返回值的类型为某一类型的指针。也就是说,这种函数的返回值是一个地址,这个地址指向函数内部某种特定类型的变量或者数据结构。

2.指针函数的定义

指针类型 * (函数名称)(函数的参数列表类型) 

3.指针函数的使用 

#include <stdio.h>

int *find_max(int a[], int n) {
    int *p = &a[0]; // 定义一个指向数组首元素的指针
    for (int i = 1; i < n; i++) {
        if (*p < a[i]) {
            p = &a[i]; // 如果当前元素大于指针所指向的元素,则更新指针的值
        }
    }
    return p; // 返回指向最大元素的指针
}

int main() {
    int arr[] = {3, 5, 2, 7, 1};
    int n = sizeof(arr) / sizeof(arr[0]);
    int *max_ptr = find_max(arr, n); // 调用find_max函数,将最大元素的地址赋给max_ptr指针变量
    printf("Max value is %d", *max_ptr); // 输出最大值
    return 0;
}

5.2 函数指针 

1.函数指针的概念

        函数指针是一种特殊类型的指针,它指向函数而非变量。这种指针在内存中储存的是函数的入口地址,我们可以通过这个地址来调用相应的函数。

2.函数指针的定义

函数的返回值类型(*指针名)(函数的参数列表类型)

3.函数指针的使用
        下面是一个函数指针的使用,首先定义一个max函数,然后在主函数内声明函数指针,再将max函数地址传递给函数指针,最后调用函数指针即可。

#include <stdio.h>

int max(int x, int y) {
    return x > y ? x : y;
}

int main() {
    int (*func_ptr)(int, int); // 声明一个函数指针变量
    func_ptr = max; // 将函数max的地址赋给函数指针变量
    printf("Max value is %d", func_ptr(10, 20)); // 输出最大值
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值