C语言----深入理解指针(3)(一)

简介: C语言----深入理解指针(3)

1.字符指针变量

//int main()
//{
//    char ch = 'w';
//    char*pc=&ch;
//    printf("%c", *pc);
//    return 0;
//}
 
/*int main()
{
    //char* p = "abcdef";
    //char arr[] = "abcdef";//常量字符串 a b c d e f \0
    //char* pc = arr;//将数组首元素的地址存在p中
    const char* p = "abcdef";//这里的赋值是讲字符串中首字符的地址存在p中
    printf("%c\n", *p);//打印a
 
    //如何打印一整个字符串呢?
    printf("%s\n", p);//使用%s打印字符串的时候,只需要提供首字符的地址就行了
 
    //*p='q'------不允许修改,因为p指向的是常量字符串,常量字符串不能被修改
    //在5303行添加const可以防止*p被修改
 
    return 0;
}*/
 
 
int main()
{
    char str1[] = "hello bit.";
    char str2[] = "hello bit.";
    const char* str3 = "hello bit.";
    const char* str4 = "hello bit.";
    if (str1 == str2)
        printf("str1 and str2 are same\n");
    else
        printf("str1 and str2 are not same\n");
 
    if (str3 == str4)
        printf("str3 and str4 are same\n");
    else
        printf("str3 and str4 are not same\n");
 
    return 0;
}
 
//输出结果
/*str1 and str2 are not same
str3 and str4 are same
为什么会出现这种情况呢?
 
str1是一个数组
str2是一个数组,只是内容相同而已
 
"hello bit."是一组常量字符串,是不能被修改的
内容相同的常量字符串只需要保存一份就可以
str3和str4存的都是h的地址,两个指针变量各自指向同一个地址
 
 
 
在这个条件语句中if (str1 == str2)
str1是数组名,首元素的地址,str2也是数组名,也是首元素的地址
str1和str2各占两份不同的空间,只是内容一样
完全不同的两个空间
 
 
在这个条件语句中if (str3 == str4)
str3和str4存放的都是h的地址,存放的是同一个地址
所以二者相同
 
 
这个代码里面的比较,不是比较字符串,比较的是地址
*/

使用%s打印字符串的时候,只需要提供首字符的地址就行了

char* p = "abcdef";//这里的赋值是讲字符串中首字符的地址存在p中

2.数组指针变量

指针数组--是数组--存放的是指针(地址)

数组指针是什么呢?

类比:字符指针--char*---指向字符的指针--字符指针变量中存放字符的地址

char ch='w';

char *pc=&ch;

整型指针---int*--指向整型的指针--整型指针变量中存放的整型变量的地址

int a=10

int *p=&a

那么数组指针就是指向数组的指针

数组指针变量存放的是数组的地址

数组的地址--&数组名

指针数组

1.是数组

2.是存放指针的数组

char* arr[6]-----char*是数组的元素类型---存放字符串指针的数组

int *arr2[5]---存放整型指针的数组

数组指针

是指针,指向数组的指针

*p--表示这是一个指针变量

这个指针指向的是数组,得有大小[10]

(*p)[10]

数组指向的元素类型是什么呢?在前面加上类型

int (*p)[10]--这里的p就是数组指针,P指向的数组有10个元素,每个元素的类型是int

p的类型是int (*)[10]

将数组的地址取出来,存放在指针变量里面,

charptr)=&arr---arr里面都是char类型的

//指针数组
//int main()
//{
//    int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
//    int(*p)[10] = &arr;//取出的是数组的地址,那么数组的地址就应该放到数组指针里面
//
//    //想使用p这个数组指针访问arr数组的内容
//    //p里面放的是数组的地址,那么*p就相当于拿到了一个数组
//    for (int i = 0; i < 10; i++)
//    {//*p就是数组,那么咱们加上[i]就说明直接访问arr[i],随着i的变化,逐步打印数组内的内容
//        printf("%d", (*p)[i]);
//    }
//    return  0;
//}
//上面这种就显得有点麻烦
 
//int main()
//{
//    //int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
//    //int(*p)[10] = &arr;//取出的是数组的地址,那么数组的地址就应该放到数组指针里面
//
//    想使用p这个数组指针访问arr数组的内容
//    p里面放的是数组的地址,那么*p就相当于拿到了一个数组
//    //for (int i = 0; i < 10; i++)
//    //{//*p就是数组,那么咱们加上[i]就说明直接访问arr[i],随着i的变化,逐步打印数组内的内容
//    //  printf("%d", (*p)[i]);
//    //}
//    int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
//    int* p = arr;
//    for (int i = 0; i < 10; i++)
//    {
//        printf("%d",p[i]);//p就是首元素的地址   p[i]---*(p+i)
//    }
//
//
//    return  0;
//}

3.二维数组传参的本质

不管是一位数组还是二维数组传参,形参可以写成数组,也可以写成指针

这里要对数组名做一个深入的理解

咱们要考虑到arr是数组首元素的地址

数组名+i就是跳过i个数组

arr[i]-----(arr+i)---第i行 arr[i][j]-----((arr+i)+j)---(arr+i)是第i行首元素的地址,+j就表示下标为j的数字的地址,再解引用就能得到下标为j的数字

对于一个二维数组的话,arr是数组名,同时也是这个二维数组第一行的元素地址

arr+i就是这个二维数组第i行的地址

对于(*(arr + i))[j]的理解

*(arr + i)就是这个二维数组的第i行的地址解引用得到第i行

[j]这个就是第i行下标为j的元素

对于((arr + i)+j)的理解

*(arr + i)是第i行首元素的地址,这个首元素的地址+j就是第i行下标为j的数字的地址,

*(arr + i)+j再将其解引用得到的就是第i行下标为j的元素

//二维数组传参的本质
 
/*void print(int arr[3][5], int r, int c)
{
    //两层循环,第一层循环打印行,第二层循环打印列
 
    for (int i = 0; i < r; i++)
    {
        for (int j = 0; j < 5; j++)
        {
            printf("%d ", arr[i][j]);//打印一行的内容
        }
        printf("\n");//换行
    }
 
 
}
 
 
int main()
{
    int arr[3][5] = { {1,2,3,4,5}, {2,3,4,5,6}, {3,4,5,6,7} };
    print(arr, 3, 5);//将arr数组的内容打印出来,数组名、行和列都要传上去
 
    return 0;
}*/
//一维数组传参
/*数组名是首元素的地址
* 一维数组在传参的时候,其实传递的是首元素的地址
* 
* 函数的参数可以写成数组,也可以写成指针
* 
* 那么二维数组呢?
* 二维数组的数组名该如何理解呢?
* 其实二维数组的数组名也是数组首元素的地址,但是是那个数字呢?
 
二维数组可以理解为一维数组的数组
将二维数组里面的三个一维数组当成一个元素
二维数组有三个元素,每个元素有三个数组
二维数组的每一行可以看成是一个一维数组‘二维数组的首元素就是这个二维数组的第一行
 
二维数组的数组名就是第一行的地址
不是第一行首元素的地址,而是第一行整个一维数组的地址
 
*/
 
 
void print(int(*arr)[5], int r, int c)//因为传过来的是一位数组的地址,我们要用数组指针接收
//使用数组指针存放第一行的地址,传过来的是一个一维数组,那么我们就需要一个数组指针来接收
{//这个数组指针并不是指向的二维数组,而是指向的是这个二维数组的第一行
    //两层循环,第一层循环打印行,第二层循环打印列
 
    for (int i = 0; i < r; i++)
    {
        for (int j = 0; j < 5; j++)
        {
            //第一行是arr
            //第二行是arr+1
 
 
            printf("%d ", (*(arr + i))[j]);//arr+i就是第几行,*(arr + i)就是解引用相当于直接访问数组后面的[j]就是那一行一维数组里面的第几个元素
        }   //printf("%d ", *(*(arr + i)+j))
        //arr+i是某一行的地址,将其括起来解引用就是这一行,相当得到第i行的数组名
        // *(arr+i)==arr[i],arr[i]是第i行的数组名,数组名是数组首元素的地址
        // *(arr + i)数组首元素的地址+j就是这一行首元素后面第j个元素的地址,再解引用
        // 再将这个地址解引用得到的就是数组首元素
        // *(arr + i)一行首元素的地址再+j就是下标为j的元素了
        // 对于这个二维数组,arr[i]表示的是arr[i][0],第i行第1个元素的地址
        // 
        // 
        //*(arr + i)这个是某一行,相当于拿到这一行的数组名字
        //对于二维数组arr的话
        //arr[0]是第一行的数组名
        //arr[1]是第二行的数组名
 
        printf("\n");//换行
    }
}
 
 
int main()
{
    int arr[3][5] = { {1,2,3,4,5}, {2,3,4,5,6}, {3,4,5,6,7} };
    print(arr, 3, 5);//将arr数组的内容打印出来,数组名、行和列都要传上去
    //arr是在这个二维数组首元素的地址,是第一行的地址,第一行是一位数组
    //这里传过去的是第一行的地址
    return 0;
}
/*不管怎么写对于二维数组arr+i就是这个二维数组的第i行一维数组,
* 传参时的arr是二维数组第一行,
* 
* 数组名+i就是跳过一整个数组,对于二维数组,里面是存在好几个一维数组的
对于(*(arr + i))[j]的理解
*(arr + i)就是这个二维数组的第i行的地址解引用得到第i行
[j]这个就是第i行下标为j的元素
 
对于*(*(arr + i)+j)的理解
*(arr + i)是第i行首元素的地址,这个首元素的地址+j就是第i行下标为j的数字的地址,
*(arr + i)+j再将其解引用得到的就是第i行下标为j的元素
 
 
arr[i]-----*(arr+i)---第i行
arr[i][j]-----*(*(arr+i)+j)---*(arr+i)是第i行首元素的地址,+j就表示下标为j的数字的地址,再解引用就能得到下标为j的数字
 
*/

*(*(arr+i)+j) 是访问二维数组中第i行,第j列元素的方法。

在C语言中,二维数组可以看作是由多个一维数组组成的连续存储空间。定义一个 int 类型的二维数组 arr,用 arr[i][j] 表示其第 i 行、第 j 列的元素,也可以写成 *(*(arr+i)+j)

解释 *(*(arr+i)+j) 的过程如下:

  1. arr 是一个指向二维数组首地址的指针,*(arr+i) 表示访问第 i 个一维数组的首地址。
  2. *(arr+i)+j 表示在第 i 个一维数组的基础上向后移动 j 个位置,即访问第 i 行、第 j 列元素的地址。
  3. *(*(arr+i)+j) 表示访问上述地址所存储的值,即获取第 i 行、第 j 列的元素值。

(*(arr + i))[j] 也可以用来访问二维数组中第 i 行,第 j 列的元素。

在C语言中,二维数组可以看作是由多个一维数组组成的连续存储空间。定义一个 int 类型的二维数组 arr,用 arr[i][j] 表示其第 i 行、第 j 列的元素,也可以写成 *(*(arr+i)+j)(*(arr + i))[j]

解释 (*(arr + i))[j] 的过程如下:

  1. arr 是一个指向二维数组首地址的指针,*(arr + i) 表示访问第 i 个一维数组的首地址。
  2. (*(arr + i))[j] 表示使用 [] 运算符访问该一维数组中下标为 j 的元素,即获取第 i 行、第 j 列的元素值。

C语言----深入理解指针(3)(二)https://developer.aliyun.com/article/1544349

相关文章
|
2月前
|
C语言
【c语言】指针就该这么学(1)
本文详细介绍了C语言中的指针概念及其基本操作。首先通过生活中的例子解释了指针的概念,即内存地址。接着,文章逐步讲解了指针变量的定义、取地址操作符`&`、解引用操作符`*`、指针变量的大小以及不同类型的指针变量的意义。此外,还介绍了`const`修饰符在指针中的应用,指针的运算(包括指针加减整数、指针相减和指针的大小比较),以及野指针的概念和如何规避野指针。最后,通过具体的代码示例帮助读者更好地理解和掌握指针的使用方法。
52 0
|
10天前
|
存储 NoSQL 编译器
【C语言】指针的神秘探险:从入门到精通的奇幻之旅 !
指针是一个变量,它存储另一个变量的内存地址。换句话说,指针“指向”存储在内存中的某个数据。
58 3
【C语言】指针的神秘探险:从入门到精通的奇幻之旅 !
|
10天前
|
存储 编译器 C语言
【C语言】指针大小知多少 ?一场探寻C语言深处的冒险 !
在C语言中,指针的大小(即指针变量占用的内存大小)是由计算机的体系结构(例如32位还是64位)和编译器决定的。
35 9
|
10天前
|
安全 程序员 C语言
【C语言】指针的爱恨纠葛:常量指针vs指向常量的指针
在C语言中,“常量指针”和“指向常量的指针”是两个重要的指针概念。它们在控制指针的行为和数据的可修改性方面发挥着关键作用。理解这两个概念有助于编写更安全、有效的代码。本文将深入探讨这两个概念,包括定义、语法、实际应用、复杂示例、最佳实践以及常见问题。
32 7
|
20天前
|
存储 C语言
C语言如何使用结构体和指针来操作动态分配的内存
在C语言中,通过定义结构体并使用指向该结构体的指针,可以对动态分配的内存进行操作。首先利用 `malloc` 或 `calloc` 分配内存,然后通过指针访问和修改结构体成员,最后用 `free` 释放内存,实现资源的有效管理。
81 12
|
13天前
|
存储 程序员 编译器
C 语言数组与指针的深度剖析与应用
在C语言中,数组与指针是核心概念,二者既独立又紧密相连。数组是在连续内存中存储相同类型数据的结构,而指针则存储内存地址,二者结合可在数据处理、函数传参等方面发挥巨大作用。掌握它们的特性和关系,对于优化程序性能、灵活处理数据结构至关重要。
|
14天前
|
算法 C语言
C语言中的文件操作技巧,涵盖文件的打开与关闭、读取与写入、文件指针移动及注意事项
本文深入讲解了C语言中的文件操作技巧,涵盖文件的打开与关闭、读取与写入、文件指针移动及注意事项,通过实例演示了文件操作的基本流程,帮助读者掌握这一重要技能,提升程序开发能力。
45 3
|
14天前
|
存储 算法 程序员
C 语言指针详解 —— 内存操控的魔法棒
《C 语言指针详解》深入浅出地讲解了指针的概念、使用方法及其在内存操作中的重要作用,被誉为程序员手中的“内存操控魔法棒”。本书适合C语言初学者及希望深化理解指针机制的开发者阅读。
|
20天前
|
存储 C语言 开发者
C 语言指针与内存管理
C语言中的指针与内存管理是编程的核心概念。指针用于存储变量的内存地址,实现数据的间接访问和操作;内存管理涉及动态分配(如malloc、free函数)和释放内存,确保程序高效运行并避免内存泄漏。掌握这两者对于编写高质量的C语言程序至关重要。
42 10
|
14天前
|
程序员 C语言
C语言中的指针既强大又具挑战性,它像一把钥匙,开启程序世界的隐秘之门
C语言中的指针既强大又具挑战性,它像一把钥匙,开启程序世界的隐秘之门。本文深入探讨了指针的基本概念、声明方式、动态内存分配、函数参数传递、指针运算及与数组和函数的关系,强调了正确使用指针的重要性,并鼓励读者通过实践掌握这一关键技能。
29 1