C语言中指针的进阶详解(1)

前言

        通过之前我写了一篇指针的基本介绍与使用方法,里面介绍了:

     

   指针的概念: 1. 指针就是个变量,用来存放地址,地址唯一标识一块内存空间。

                          2. 指针的大小是固定的4/8个字节(32位平台/64位平台)。

                          3. 指针有各种各样的类型,指针的类型起到的作用与意义。

                          4. 指针与指针、数组之间的运算,遍历等方法。

                          5.二级指针的含义与使用等。

        这些也只是关于指针的基础性知识,接下来让我们共同走进指针的更高层面的世界吧。

目录

一.

1. 字符指针

2.指针数组 

3.1数组指针

3.2数组指针的用途


一.

1. 字符指针

定义:存放变量为字符的地址的指针称为字符指针。--char*型

        之前我讲过了指针的类型,有int型,short型,float型,double型,还有就是char型。int型指针用来存放而这些指针的类型的作用就是通过指针去存放不同数据类型的变量的地址,以此利用变量地址进而达到间接修改变量值的作用。

int main()
{
    char ch = 'w';
    char *pc = &ch;
    *pc = 'w';
    return 0;
}

        例如上图代码就是通过创建指针去接收到变量ch的地址,指针使用解引用操作被赋值为字符w,也间接的修改了ch的值。此外字符指针还能指向字符串,如下图:

int main()
{
    const char* pstr = "hello bit.";
    printf("%s\n", pstr);
    return 0;
}

        上图代码是将字符串赋值给了字符型指针pstr,指针加const的作用是因为:字符串本身是常量字符串,不可被修改,基于此,那么存放常量字符串的指针也应该设置为常量const。但此题的代码是为了让我们思考一下,这里是把一个字符串放到pstr指针变量里了吗?

        答案肯定是错误的,当指针指向数组时,int*p=arr;也不过才存放了数组首元素的地址,那么字符串也是一样的,字符串中存放了多个字符,而字符指针指向的也必然是字符串的首字符地址。如下图代码执行结果:

C语言中指针的进阶详解(1)_第1张图片

        a. 通过观察可知,pstr被解引用操作后展现的字符为a,更加验证了字符指针指向的一定是字符串首字符地址。

        b.此外我们知道在32位中,一个指针的大小为4字节,"abcdef"加'\0’字符就占7字节空间,4个字节是放不下的,所以也可以确定指针存的是字符串首字符地址。

C语言中指针的进阶详解(1)_第2张图片

通过对字符指针的了解,我们来做一道例题 :

int main()
{
    char str1[] = "hello bit.";
    char str2[] = "hello bit.";
    const char *str3 = "hello bit.";
    const char *str4 = "hello bit.";
    if(str1 ==str2)
 printf("same\n");
    else
 printf("not same\n");
       
    if(str3 ==str4)
 printf("same\n");
    else
 printf("not same\n");
       
    return 0;
}

        代码讲解:这道题想让我们判断两个数组、指针在赋值同样内容的字符串时,是否相等的问题。

        首先来判断两数组是否相等。两个数组在被创建的同时,赋予了相同的值,但每一个数组在内存空间中都是独一无二的,两数组内容虽同,但地址不等就谈不上真正意义上的相等,所以第一个判断为not same。

C语言中指针的进阶详解(1)_第3张图片

         其次,在第二个判断中,两指针会指向同一个字符串,这是为了节省内存(内存中有一个常量字符串就够了,字符串把地址留给指针,让两指针存有相同的地址且能随时进行访问。所以两指针在本质意义上是相等的,所以为same.

C语言中指针的进阶详解(1)_第4张图片

代码调试结构如下:

C语言中指针的进阶详解(1)_第5张图片

2.指针数组 

        指针数组的主语是数组,形容词是指针,通过字面意思就可以了解到它是一个存放元素是指针的数组。

int* arr1[10]; //整形指针的数组

char *arr2[4]; //一级字符指针的数组

char **arr3[5];//二级字符指针的数组

        我们可以通过指针数组去模拟遍历一个二维数组,如下代码:

int main() {

    int arr1[] = { 1,2,3,4,5 };
    int arr2[] = { 2,3,4,5,6 };
    int arr3[] = { 3,4,5,6,7 };
    
    int* ptr[] = { arr1,arr2,arr3 };
    int i = 0;
    for (i = 0; i < 3; i++) {
        int j = 0;
        for (j = 0; j < 5; j++) {
       printf("%d ", *(ptr[i]+j));
        }
        printf("\n");
    }
    //*(ptr+i)==ptr[i]      
    return 0;
}

        代码讲解:通过创建三个整型数组,再创建一个指针数组,就可以将三个数组的数组名存放在这个指针数组中 (数组名一般指当前数组的首元素地址),通过遍历便可以将三个一维数组间接转换成一个二维数组。

3.1数组指针

        数组指针是指针还是数组? 答案是:指针。

        我们已经熟悉: 整形指针:int * ptr; 能够指向整形数据的指针。 浮点型指针:float * pf; 能够指向浮点型数据的指针。 那数组指针应该是:能够指向数组的指针。

        那我们来做一道例题来区分一下:

int *p1[10];
int (*p2)[10];

        第一个语句的意思是:p1[ ]是数组,数组中存放的元素是10个int类型的指针,这是刚才讲到的指针数组。(注:[ ]下标操作符的优先级要高于*操作符,所以程序认定p1先执行下标操作符

        第二个语句的意思是:p2优先作用于*,表明p2是指针,它指向了存放10个元素的整型数组,所以是数组指针。(注:因为有括号,优先级改变,保证p先和*结合。)

总结:优先级的先后能够改变指针与数组之间的含义!

        接着我们再来做两道关于数组指针的题目:填写下面两道题于下划线处。

  练习1.:利用数组指针接收 
    int arr1[10] = { 0 };
    ___________________;

练习2.:如何用数组指针去接收? 
    char* arr2[5] = { 0 };

    __________________;

         练习1讲解:首先题中创建了一个数组,若要利用数组指针去接收,应先判断数组的类型,大小,最后写上指针。那么数组中给到的信息:数组arr1共有10个元素,且每个元素都是int型,所以可以写出 int(*pa)[10]=&arr1;

        练习1讲解:还是先找出题中所给数组的所有信息,数组arr2中共有5个元素,每个元素都是字符型指针,所以可以写出 char*(*pa)[5]=&arr2;

3.2数组指针的用途

        通过之前对于指针的学习,我们了解到指针只能作用于一维数组传参中,而数组指针却是可以作用到二维甚至是三维的数组传参中。我们可以通过数组传参来学习数组指针的用法。

        代码如下:这是一段二维数组遍历元素的代码。

#include 
void print_arr1(int arr[3][5], int row, int col)
{
    int i = 0;
    for(i=0; i

        在此段代码中,二维数组使用函数来遍历其元素,通过之前的学习,我们知道在一维数组遍历元素时,函数有两种接收方法,一种是直接使用数组接收:int arr[ ];另外一种是使用指针去接收数组实参:int* p。二维数组也是如此,但其所用的指针参数不是用普通的指针接收,而是用到了数组指针:int(*p)[5]。

     数组名arr,表示首元素的地址    但是二维数组的首元素是二维数组的第一行    所以这里传递的arr,其实相当于第一行的地址,是一维数组的地址, 那么就需要用到指向数组的地址的指针去接收,即是数组指针。如下图:

void print_arr2(int (*arr)[5], int row, int col)
{
    int i = 0;
    for(i=0; i

C语言中指针的进阶详解(1)_第6张图片

       这里大家应该会关注一个问题:为什么普通指针不能指向一个二维数组?

因为这样会无法运算出移动的距离。比如一维数组:
int a[5];                int *p=a;
在进行数组遍历时,p每次加1都会移动4个字节。
但是对于二维数组:
int a[5][2];        假设可以这样 ,int *p=a;
        那么p+1应该在内存中移动多少字节呢?如果按逻辑上指针在数组的第一维度的移动来看答案是4*2=8字节
但是p作为一级int指针,每次只能移动4字节,也就是说p的每次加1都只会一个元素一个元素的遍历,所以这样指其实是错的,这和你这样写程序的本意不符合。
所有得要写成: int (*p)[2];

这样指针p每+i,就会指向第i行的数组进行遍历。这样编译器就知道每次移动的是4*2=8字节(一整行一整行进行遍历)。

        好了 ,关于字符指针,指针数组和数组指针的知识点就介绍到这里,创作不易,觉得有用的话就点点赞吧!

你可能感兴趣的:(C语言知识点,c语言)