指针进阶:常量字符串与字符数组、字符指针数组、指针数组模拟实现二维数组

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>

一、深度剖析常量字符串与字符数组

//例1:
int main()
{
    const char* pstr = "hello world";
        //此处的"hello world"是一个常量字符串,这里是把常量字符串的首字母h的地址放到pstr的指针变量里了
    printf("%s\n", pstr);    //hello world
        //这里不是很容易理解的话,可以把上面的常量字符串想象成一个字符数组来帮助理解,下面我们就用字符数组来演示一遍:
    char arr[] = "hello world";
    char* p = arr;
        //数组名arr表示的是数组首元素的地址,p是指向数组arr的首元素的指针
    printf("%s\n", arr);    //hello world
    //注意:
        //1.printf("%s\n", pstr)的打印方式是用指针来打印常量字符串的整体;printf("%s\n", arr)是用数组名来打印字符数组的整体。两种打印方式有所不同,但是都可以用来打印整个字符串
        //2.用数组来帮助理解常量字符串,但是两者有本质的区别:
            //数组可以通过指针修改数组中的元素,但是常量字符串突出的一个就是‘常’字,也就是它是不可以被修改的,所以为了避免调试警告,一般都会用const来修饰
    return 0;
}

//例2:同一个常量字符串初始化不同数组与不同指针指向同一个常量字符串
int main()
{
    char str1[] = "hello world";
    char str2[] = "hello world";
    const char* str3 = "hello world";
    const char* str4 = "hello world";
    if (str1 == str2)    //数组名表示的数组首元素的地址,所以str1==str2是在比较他们是不是同一个地址
        printf("str1 and str2 are same\n");
    else
        printf("str1 and str2 are not same\n");
    //str1 and str2 are not same
        //str1[]和str2[]是两个不同的数组,只是被用相同的常量字符串去初始化而已,就像int a=0;int b=0 一样,a和b是两个不同的变量,只是都是用0初始化的而已
        //既然是不同的数组、不同的变量,那么无论是用什么初始化它都会在内存中开辟不同的内存空间,地址就不相同

 
    if (str3 == str4)
        printf("str3 and str4 are same\n");
    else
        printf("str3 and str4 are not same\n");
    //str3 and str4 are same
        //str3和str4是指向同一个常量字符串的指针,常量字符串在内存中被存储在一个单独的内存区域,当不同的指针指向同一个常量字符串的时候,实际上他们会指向同一快内存,所以str3和str4是同一个地址

    return 0;
}

二、指针数组
//字符指针数组
int main()
{
    char* arr[] = { "say","hello","to","world" };
        //数组arr的每个元素存放的都是字符指针(char*):
            //第一个char*:存放的是say\0中首元素s的地址
            //第二个char*:存放的是hello\0中首元素h的地址
            //第三个char*:存放的是to\0中首元素t的地址
            //第四个char*:存放的是world\0中首元素w的地址
    int i = 0;
    for (i = 0; i < 4; i++)
    {
        printf("%s\n", arr[i]);
            // say
            // hello
            // to
            // world
        //以arr[0]为例:表示arr数组中的第一个元素,即第一个字符指针,而第一个字符指针存放的是say\0中首元素s的地址,那么用arr[0]来打印就是以指针打印整个字符串say\0,\0作为字符串结束标志不计入字符串的内容,所以最终打印的是say。指针数组中剩下的几个字符指针同理。
    }
    return 0;
}

//指针数组模拟实现二维数组
int main()
{
    int arr1[] = { 1,2,3,4 };
    int arr2[] = { 2,4,6,8 };
    int arr3[] = { 9,8,7,6 };
    int* arr[] = { arr1,arr2,arr3 };
    int i = 0;
    for (i = 0; i < 3; i++)    //arr[]一共三个整型指针,分别是arr1,arr2,arr3(数组名表示的是数组首元素地址)
    {
        int j = 0;
        for (j = 0; j < 4; j++)
        {
            //printf("%d ", *(arr[i] + j));
            printf("%d ", arr[i][j]);
                // *(arr[i] + j)和arr[i][j]是等价的,如果觉得难理解可以用一维数组来帮助理解二维数组,即将这个二维数组中的arr[i]用arr来代替:
                    //我们知道一维数组中,数组名(暂定用arr表示)表示数组首元素的地址,也就是说arr本质上是一个指针,那么arr+1表示的是指向第二个元素的指针,解引用之后就是对应的第二个元素的实际值
                    //所以就有*(arr+1)=arr[1],但是本质上*(arr+1)是通过解引用指针找到数组的第二个元素,而arr[1]是通过数组下标找到数组第二个元素,途径不同,但是结果相同

                    //再回到我们的代码,*(arr[i]+j)和arr[i][j]就是等价的,现在就会很容易理解
            
            //注:为什么字符数组可以通过数组首元素的地址打印整个字符串,而整形数组只能一个一个元素的打印,其实是我们把问题复杂化了,打印字符串有专门的符号%s,整型数据(int型为例)只有%d,%d每次只能打印一个数,这是规定,没有为什么
        }
        printf("\n");
    }
    return 0;
}

评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值