https://m.toutiao.com/is/SbU6MJ8/ 一维数组中的指针数组(Array)是一系列具有相同类型的数据的集合,每一份数据叫做一个数组元素(Element)。数组中的所有元素在内存中是连续排列的,整个数组占用的是一块内存。以int arr[] = { 99, 15, 100, 888, 252 };为例,该数组在内存中的分布如下图所示: 一维数组名:可以隐式转换为指向数组首地址的指针 定义数组时,要给出数组名和数组长度,数组名可以认为是一个指针,它指向数组的第 0 个元素。在C语言中,我们将第 0 个元素的地址称为数组的首地址。以上面的数组为例,下图是 arr 的指向: 数组下标为啥从0开始? 数组下标实际上是每个元素的地址相对于第一个元素地址的偏移量。如下图所示: 一维数组名可以隐式转换为指向数组首地址的指针,但是不可对数组名直接自增自减操作,数组名的位置不可改变。所以一般会用指针指向数组去操作,如下测试代码: #include <stdio.h>int main() { int arr[5] = { 99, 15, 100, 888, 252 }; int* p = arr; //等效 p=&arr[0] //错误,数组名不可改变位置 //arr++; for (int i = 0; i < 5; i++) { //*(arr + i)等效arr[i] 等效p[i]等效(arr+i)[0]等效(p+i)[0] printf('%d\t', *(arr + i)); } printf('\n'); return 0;} &一维数组名:可以隐式转换为指向整个数组的数组指针 数组指针是指向整个数组的指针,在做偏移的时候就是整个数组占用的字节数。如下测试代码:
运行结果如下: 0000001512BEFB5C- 0000001512BEFB48=0000000000000014 ,十六进制0000000000000014 就是十进制20,刚好是sizeof(int)*5 个字节,自己电脑上运行的地址肯定会改变,但是偏移量肯定是一样的。 数组名和普通指针的区别 虽然说数组名可以当做指针使用,但实际上数组名并不等价于指针。
如下测试代码: #include <stdio.h>int main() { int arr[5] = { 99, 15, 100, 888, 252 }; //隐式转换 int* p = arr; //指针变量64位中占用8个字节 printf('sizeof(p):%zd\n', sizeof(p)); //整个数组占用内存 printf('sizeof(arr):%zd\n', sizeof(arr)); //数组名取地址并不是二级指针,而是数组指针 int(*parr)[5] = &arr; for (int i = 0; i < 5; i++) { printf('%d\t', parr[0][i]); } printf('\n'); return 0;} 运行结果如下: 指针操作一维数组示例程序| 各种方式遍历一维数组 在一维数组中以下访问元素的方式都是等效的,不过在用指针操作的时候强烈建议新手采用下标法。
当指针指向一维数组的首地址的时候,也存在上述一样的用法,并且还有其他的使用方式,如下测试代码:
运行结果如下: 示例程序| 指针操作一维数组负下标理解 在一维数组中如果用指针指向数组首地址后,在操作过程中对指针对了一些偏移后,或者指针不是指向首地址,下标法的含义是完全不同的,如下测试代码: #include <stdio.h>int main() { int arr[5] = { 99, 15, 100, 888, 252 }; int* p = &arr[2]; //p[0]等效 *(p+0) printf('%d\n', p[0]); //p[-2]等效*(p-2); printf('%d\n', p[-2]); return 0;} 运行结果与图解如下: 示例程序| 指针操作字符串(字符数组) 指针操作字符类数组,要注意的是边界问题,尤其是在字符串中的字符调整,例如反转字符串操作,统计字符串长度等操作。指针操作字符串,注意常量字符串,建议养成const修饰指针的写法,C++对于const要求更为严格,如下测试代码:
运行结果如下: 二维数组中的指针二维数组可以理解为每一个元素都是一个一维数组的数组,这样就可以很好的理解二维数组与指针了。下面定义了一个2行3列的二维数组,内存模型如下: 二维数组名:可以隐式转换指向数组的指针 数组指针在做偏移的时候,每次都是偏移一行,如下测试代码: #include<stdio.h>int main(){ int arr[2][3] = { 1,2,3,4,5,6 }; int(*p)[3] = arr; printf('%p\t%p\n', p + 1, &arr[1][0]); for (int i = 0; i < 2; i++) { for (int j = 0; j < 3; j++) { printf('%d\t', p[i][j]); } printf('\n'); } return 0;} 运行结果如下: 二维数组名[下标]:可以隐式转换一级指针 二维数组名[i]:代表第i行的首地址,可以隐式转换为一级指针。 &二维数组名[i] :代表的是第i行的首地址,并且可以隐式转换为数组指针。 &二维数组名[i][j]:当前行列元素的地址, 如下测试代码:
运行结果如下: 行列指针行指针:是指向一整行,并不是指某个具体元素
列指针:是指向某个具体元素
指针操作二维数组示例程序| 一级指针遍历二维数组 在显存指针操作的时候就需要使用一级指针操作二维数组,由于二维数组的内存是连续的,所以一级指针依然可以操作,只需要把行列转换为序号即可,如下测试代码: #include<stdio.h>int main(){ int arr[2][3] = { 1,2,3,4,5,6 }; int* p = &arr[0][0]; for (int i = 0; i < 2; i++) { for (int j = 0; j < 3; j++) { printf('%d\t', p[i*3+j]); } printf('\n'); } return 0;} 运行结果如下: 示例程序| 数组指针遍历二维数组 二维数组访问元素的方式比较多,以下方式都可以:
当数组指针指向一维数组的首地址的时候,也存在上述一样的用法,并且还有其他的使用方式,如下测试代码:
示例程序| 数组指针操作多个字符串 多个字符串可以采用二维数组存储,每一行存储一个字符串,操作每一行即可操作每个字符串,例如多个字符串的排序问题,如下测试代码: #include<stdio.h>#include<string.h>int main(){ char str[][10] = { 'coolmoying','moying','ying' }; char (*p)[10] = str; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3 - i - 1; j++) { if (strcmp(p[j], p[j+1])>0) { char temp[10] = ''; strcpy(temp, p[j]); strcpy(p[j], p[j + 1]); strcpy(p[j + 1], temp); } } } for (int i = 0; i < 3; i++) { puts(p[i]); } return 0;} 动态内存申请C语言内存四区 C语言在程序执行的时候,内存划分为4个区域
C语言内存申请和释放函数 C语言使用内存申请和释放函数一定要记得包含stdlib.h头文件。不包含可能会导致申请内存失败
动态申请内存基本操作示例程序| 一级指针申请单个变量内存 动态申请内存过程其实是分为两个过程
如下测试代码:
示例程序| 一维数组动态申请内存 一维数组动态内存申请其实就是申请一段内存,然后把一段内存的首地址赋值给指针,通过指针偏移操作多个内存。不过一般操作方便,推荐使用数组下标方式访问,一维数组动态主要有一下三种方式:
测试代码如下: #include<stdio.h>#include<assert.h>#include<stdlib.h>int main(){ int* pInt = (int*)malloc(sizeof(int)); //申请内存失败判定 assert(pInt); *pInt = 123; char* pChar = (char*)malloc(sizeof(char)); //申请内存失败判定 if (pChar == NULL) return 0; putchar(*pChar = 'A'); free(pInt); pInt = NULL; free(pChar); pChar = NULL; return 0;} 运行结果如下: 示例程序| 一维数组动态申请之内存自动扩增 realloc函数可以实现内存的自动扩增,当用户数据超过限定的时候,可以做到自动增长,如下测试代码:
运行结果如下: 示例程序| 二维组动动态申请内存 二维数组的动态内存申请主要有一下两种方式
测试代码如下: #include<stdio.h>#include<assert.h>#include<stdlib.h>int main(){ int row = 3; int cols = 4; //No.1 数组指针申请 int(*p)[4] = NULL; p = (int(*)[4])calloc(row, sizeof(int[4])); assert(p); for (int i = 0; i < row; i++) { for (int j = 0; j < cols; j++) { printf('%d ', p[i][j]); } printf('\n'); } //No.2 二级指针申请 int** parr = (int**)calloc(row, sizeof(int*)); assert(parr); for (int i = 0; i < row; i++) { parr[i] = (int*)calloc(cols, sizeof(int)); assert(parr[i]); } for (int i = 0; i < row; i++) { for (int j = 0; j < cols; j++) { printf('%d ', parr[i][j]); } printf('\n'); } for (int i = 0; i < row; i++) { free(parr[i]); parr[i] = NULL; } free(parr); parr = NULL; free(p); p= NULL; return 0;} 示例程序| 字符指针申请内存并且赋值字符串 字符指针操作字符串的时候,主要是要注意字符串长度问题,一级字符串操作必须采用字符串处理函数去完成,如下测试代码:
|
|
来自: 山峰云绕 > 《C语言数据结构描述Windows程序设计》