=========================================================================
相关代码gitee自取:C语言学习日记: 加油努力 (gitee.com)
=========================================================================
接上期:
学C的第二十四天【练习:1. 打印菱形;2. 打印自幂数;3. 求Sn=a+aa..n项之和;4. 喝汽水问题;5. 调整数组使奇数位于偶数前面;6. 打印X形图案;7……;8……;9……;10……】_高高的胖子的博客-CSDN博客
=========================================================================
指针回顾:
一些指针相关知识:
(1). 指针是个用来存放地址的变量,地址是唯一标识的一块内存空间。
内存会划分为一个个的内存单元,
每个内存单元都有一个独立的编号,编号也称为地址,
地址在C语言中也被称为指针,
指针(地址)需要存储起来,存储到变量中,这个变量就被称为指针变量。
(2). 指针(地址)的大小是固定的 4/8(32位操作系统/64位操作系统) 个字节。
地址是由物理的电线产生的,
在32位机器上,有32根地址线,每根会产生 1 或 0 的电信号,
32个 1/0 会组成一个二进制序列,将这个二进制序列当作地址,
需要32个bit位(4个字节)才能存储这个地址,使用指针变量的大小就是4个字节。
同理,在64位机器上,
地址是由64个 1/0 组成的二进制序列,需要64个bit位存储,即8个字节,
使用这时指针变量的大小是8个字节。
(3). 指针是有类型的,指针的类型 决定了指针加减多少个整数的步长,指针解引用操作时的权限。
(4). 指针的运算:指针加减整数、指针减指针、指针的关系运算
往期指针相关文章:
学C的第五天(初识指针,内存产生内存单元地址过程,指针函数介绍和其大小;结构体补充)_高高的胖子的博客-CSDN博客
学C的第十七天【指针初阶: 1. 指针是什么?;2. 指针和指针类型;3. 野指针;4. 指针运算】_高高的胖子的博客-CSDN博客
学C的第十八天【指针初阶:5. 指针和数组、6. 二级指针、7. 指针数组;初识结构体:1. 结构体的声明、2. 结构体成员的访问、3. 结构体传参;练习:3道和整数二进制数相关的练习】_高高的胖子的博客-CSDN博客
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1.字符指针:
(1). 含义:
字符指针是指向字符变量的指针,存放字符变量的地址的指针变量。
(2). 字符指针的一种写法:存放指针变量
使用 取地址符& 取出字符变量的地址,赋给 字符指针。
(3). 字符指针的另一种写法:存放字符串表达式
实际上就是把 字符串表达式 的首字符地址(字符串表达式起始地址) 赋给 字符指针。
这里说到了常量,补充一些关于常量的知识:
(4). 一道相关笔试题:
对应代码:
#include <stdio.h> int main() { // 创建两个字符数组,一个叫str1,一个叫str2, // 只不过两个数组存储的内容相同,两个空间是相互独立的 char str1[] = "hello world."; char str2[] = "hello world."; // str1数组 和 str2数组 是两个相互独立的空间 // 所以两者指向的 首元素地址 是不同的 if (str1 == str2) printf("str1 and str2 are same\n"); else printf("str1 and str2 are not same\n"); // 这两个是字符指针,“hello world”是一个常量字符串,不会改变 // 所以只会为常量字符串开辟一个空间,指针使用时直接指向该字符串地址进行使用 // 那么 str3 和 str4 应该是指向同一个空间(地址)的 const char* str3 = "hello world."; const char* str4 = "hello world."; // 只会为常量字符串开辟一个空间,指针使用时直接指向该字符串地址进行使用 // 那么 str3 和 str4 应该是指向同一个空间(地址)的 if (str3 == str4) printf("str3 and str4 are same\n"); else printf("str3 and str4 are not same\n"); return 0; }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2.指针数组:
(1). 含义:
指针数组是一个数组,用于存放指针的数组。
(2). 实例:
(3). 使用指针数组模拟二维数组:
对应代码:
//使用指针数组模拟二维数组: #include <stdio.h> int main() { int arr1[] = { 1,2,3,4,5 }; int arr2[] = { 2,3,4,5,6 }; int arr3[] = { 3,4,5,6,7 }; //使用指针数组存放3个数组名(数组首元素地址) int* arr[3] = { arr1,arr2,arr3 }; //通过指针数组里的指针找到指针内容 int i = 0; for (i = 0; i < 3; i++) //循环0-3,指针数组的下标0-3 { int j = 0; for ( j = 0; j < 5; j++) //循环0-5,指针数组里指针内容的下标0-5 { printf("%d ", arr[i][j]); } printf("\n"); //打印完一行后进行换行 } return 0; }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3.数组指针:
(1). 含义:
数组指针是指向数组的指针,存放的是数组的地址的指针变量。
例子:
int (*p)[10];
解释:
* 先和 p 结合,说明p是一个指针变量,
指向的是 int [10] ,即一个大小为10的整型数组。
所以 p 是一个指针,指向一个数组,叫做数组指针。
(2). 数组名 对比 &数组名(取数组名地址)
数组名表示数组首元素地址,但有两个例外:
1. sizeof(数组名),这里的数组名表示整个数组,
计算整个数组的大小,单位是字节。
2. &数组名,这里的数组名也表示整个数组,
取出整个数组的地址,整个数组的地址也是用数组首元素表示。&数组名 + 1 -- 会跳过整个数组,而不是 arr+1 跳过一个元素。
实例:
对应代码:
//数组名的理解: //数组名表示数组首元素地址,但有两个例外 #include <stdio.h> int main() { int arr[10] = { 0 }; //证明数组名是首元素地址: printf("%p\n", arr); //打印arr的地址 printf("%p\n", &arr[0]); //打印&arr[0]的地址 //换行: printf("\n"); //数组名不表示首元素的两种例外: //1. sizeof(数组名),这里的数组名表示整个数组 // 计算整个数组的大小,单位是字节 printf("%d\n", sizeof(arr)); //换行: printf("\n"); //2. &数组名,这里的数组名也表示整个数组 // 取出整个数组的地址 printf("%p\n", arr); //打印arr的地址 -- int* 类型 printf("%p\n", arr + 1); //换行: printf("\n"); printf("%p\n", &arr[0]); //打印&arr[0]的地址 -- int* 类型 printf("%p\n", &arr[0] + 1); //换行: printf("\n"); printf("%p\n", &arr); //打印&arr的地址 -- int(*)[10] printf("%p\n", &arr + 1); return 0; }
(3). 数组指针的初始化和使用:
1 . 数组指针的初始化:
数组指针指向的是数组,那数组指针中存放的应该是数组的地址。
实例:
2 . 数组指针的使用:一般在二维(或以上)数组使用
(2.1). 对二维数组的补充理解:
二维数组的每一行都可以理解为二维数组的一个元素,
每一行又是一个一维数组,
所以二维数组其实是一维数组的数组。
(2.2). 二维数组的数组名:
二维数组的数组名 也是 二维数组首元素的地址,
数组首元素的地址 也是 二维数组第一行的地址,
二维数组第一行的地址 是一个 一维数组的地址,
可以通过 一维数组的地址 访问 一维数组的内容。
实例:二维数组传参
对应代码:
//在二维数组中使用数组指针进行打印 #include <stdio.h> void Print(int (*p)[5], int r, int c) //因为 二维数组数组名 是一个一维数组地址, //所以可以用 数组指针 作为形参 { int i = 0; for (i = 0; i < r; i++) //遍历二维数组的元素 { int j = 0; for ( j = 0; j < c; j++) //遍历二维数组中每一行的元素 { printf("%d ", *(*(p + i) + j)); // *(p + 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); //参数:(二维数组名,行数,列数) return 0; }
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4.数组传参和指针传参:
(数组传参,形参可以用 数组接收,也可以用 指针接收。)
(1). 一维数组传参:
(2). 二维数组传参:
(指针传参,形参只能用 指针接收。)
(3). 一级指针传参:
(4). 二级指针传参:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5.函数指针:
(1). 含义:
函数指针是存放函数地址的指针。
(2). 函数也有地址:
(3). 函数指针的初始化和调用:
1 . 函数指针的 初始化:
2 . 函数指针的 调用: