二级指针


多级指针、数组(C语言) ............................................................................................................ 1
1 多级指针 ................................................................................................................................... 5
2 数组........................................................................................................................................... 8
2.1 数组的定义 ................................................................................................................... 8
2.1.1 定义 ................................................................................................................... 8
2.1.2 2个属性 ............................................................................................................. 8
2.2 数组空间的初始化(数组空间的赋值问题) ........................................................... 9
2.2.1 字符空间(软件的最小空间:char) .......................................................... 10
2.2.2 字符拷贝函数(strcpy、strncpy) ............................................................... 12
2.2.3 非字符空间 ..................................................................................................... 13
2.2.4 memcpy ........................................................................................................... 14
2.3 用指针表示数组 ......................................................................................................... 15
2.3.1 一维数组与一级指针 ..................................................................................... 15
2.3.2 指针数组与多级指针(二级指针) ............................................................. 15
2.3.3 多维数组(二维数组) ................................................................................. 16
1 多级指针 指针的本质:存放地址的盒子。 指针 多级指针:也是一个盒子。只是这个盒子里面存放的还是盒子。它是存放地址的地址空间,也可以理解成一个地址表。 多级指针 多级指针(二维指针):把一些毫不相关的东西,组成线性关系(连续的空间,每个里面存放的都是地址)。它更多描述的是内存与内存的线性关系,而不是要描述内存的内容是什么。
把p[0]、p[1]、p[2]等组成线性关系。NULL是二维指针结束的标志。 例1: // 001.c #include <stdio.h> int main(int argc, char **argv) // argc:传递参数的个数 { int i; for(i = 0; i < argc; i++) { printf("argv[%d] is %s\n", i, argv[i]); } return 0; }
使用二维指针建立地址的线性关系,让各个地址依次指向字符串,这样,二维数组的内容就是按该字符串顺序输出的 例2: // 002.c #include <stdio.h> int main(int argc, char **argv) { int i = 0; while(argv[i] != NULL) // 二维指针常用的模板和框架。 NULL为结束的标志 { printf("argv is %s\n", argv[i]); // 里面具体的实现 i++;
} return 0; }
2 数组
2.1 数组的定义
2.1.1 定义 数组:指针的特殊化。 它也是内存分配(空间申请)的一种形式,而不是一种全新的数据结构。 其目的就是为了定义一个连续的空间。
2.1.2 2个属性 ? 大小 ? 读取方式 ? 数据类型 数组名[m]: ? ? []:把数组名升级为一个连续空间 ? m:连续空间的个数。
? 数据类型:表示内存以何方式切割。 ? ? int a[100]; // 100个int这么大的连续空间 ? a[10] // 使用方式与指针是一样的 (1)m 就是一个建议符,只是在申请的时候用一下。后面使用的时候,编译器无法知道[]里面的数是否越界。 int a[100]; // 理论上,a的空间只有100个,但是只是建议;还是可以越界的。 (2)经典错误1:数组名是一个常量符号,只是一个标签常量,是无法改变的,一定不要放到=的左边 char buf[100]; buf = "hello world"; // 错误! buf++; // 错误! 数组名是一个常量,指针是一个变量。
2.2 数组空间的初始化(数组空间的赋值问题) 原理:按照标签逐一赋值。(空间的赋值没有投机取巧的办法,只能这样做) int a[10]; a[0] = x; a[1] = y; ...
问题: 但如果这样赋值,程序员的工作量很大。 偷懒办法:让编译器进行一些自动处理,帮助程序员写如上的逐一赋值的程序。 方法:空间在定义时,就告知编译器初始化情况,这叫空间的第一次赋值。 int a[10] = 空间; C语言本身/CPU内部本身,一般不支持空间和空间的拷贝,只支持int、int(4B)等之间小的拷贝。 int a[10] = {10, 20, 30}; -- > 学习arm汇编后,可以进行反汇编。 其内部相当于执行一个拷贝的过程。只是不同编译器调用不同的函数来做拷贝。 这句定义,其实CPU还是做了: a[0] = 10; a[1] = 20; a[2] = 30; a[3] = 0 / 随机值; (不同编译器可能有所不同) ... 所以,一定不要这样认为:数组初始化一步就可以完成了! 数组空间的初始化和变量的初始化,本质上是不同的。 尤其在嵌入式的裸机开发中,数组空间的初始化往往需要一些库函数的辅助,或者程序员的人为设计。
2.2.1 字符空间(软件的最小空间:char) char buf[10] = {'a','b','c'};
// 1. buf如果当成普通内存来看,这样写没有问题 // 2. buf如果当成一个字符串来看,最后一定加上一个'\0' 字符串的重要属性:结尾一定有个'\0' (1)buf当成字符串的写法: char buf[10] = {'a','b','c', '\0'}; char buf[10] = {"abc"}; // buf当成字符串最合理的写法 // C语言编译器看到双引号,就会自动在末尾加上'\0' char buf[10] = "abc"; char buf[] = "abc"; (2)经典错误2: char buf[10] = "abc"; // buf有空间,再把abc逐一地拷贝到buf中 // 通过初始化方法完成了常量区向变量区的拷贝。 // 因此,对buf变量区的值进行修改是可以的;但无法对“abc”常量区进行改动。 buf[2] = 'e'; //对变量区进行修改,没有问题 char *p = "abc"; // p直接指向abc的地址
p[2] = 'e'; // 错误!不能对常量区进行修改 (3)经典错误1:数组名是一个常量符号,只是一个标签常量,是无法改变的,一定不要放到=的左边。 char buf[100] = "abc"; // 数组空间的初始化,是空间的第一次赋值,可以直接这样写 buf = "hello world"; // 错误! // 想把空间的值变为其它,这是进行空间的第二次赋值,就不能直接这样写了,只能逐一处理: buf[0] = 'h'; buf[1] = 'e'; ... buf[n] = 'd'; buf[n+1] = 0; C语言编译器只支持第一次空间赋值(初始化)时,直接=来一次赋值;第二次开始,必须进行逐一赋值。 问题: 第二次赋值,是很多人都有的需求,而逐一赋值工作量太大啦! 鉴于此,C语言提供了一套字符拷贝函数。
2.2.2 字符拷贝函数(strcpy、strncpy) 字符拷贝函数:内存空间和内存空间的逐一赋值功能的一个封装体。 注意:一旦空间中出现了0这个特殊值,字符拷贝函数就将结束。 也就是说,只有遇到\0,strcpy和strncpy才会结束拷贝;否则会一直拷贝。 (1)strcpy char *strcpy(char *dest, const char *src);
使用strcpy实现第二次空间赋值: char buf[10] = "abc"; // buf = "hello world"; strcpy(buf, "hello world"); // 使用strcpy实现了第二次空间赋值! 该函数存在严重的内存泄漏问题,在工程中绝对不能使用! char buf[10] = "abc"; strcpy(buf, "hello world, i am lixingzhi. How are you ? ..."); // buf只有10个连续空间,但是strcpy时字符串的字符多于10个,导致内存泄漏 (2)strncpy char *strncpy(char *dest, const char *src, size_t n);
2.2.3 非字符空间 字符空间:可以使用ASCII码来解码的空间,其目的是让人看的(%s看字符空间的内容,人可以看懂) 字符空间有字符串和结束标志(\0)。 非字符空间: 数据采集,是8bit或其倍数为单位来进行采集的。 所以需要开辟一个存储这些数据的空间。 char buf[10]; // 看到char,第一反映就是:一定是个string(字符串) unsigned char buf[10]; // 看到unsigned char,一定是个data(普通数据,非字符串) 注意:非字符空间的第二次赋值,不能用strcpy和strncpy:
unsigned char *p = sensor_base; // sensor的数据 strcpy(buf, p); // strcpy遇到\0才会结束。sensor_base里很可能没有\0,或者刚开始就是低电平(0) 问题: 字符空间的拷贝,结束标志为\0;那么非字符空间拷贝的结束标志是什么? 非字符空间没有结束标志,只能定义拷贝的个数。 因此其拷贝的三要素: ? src ? dest ? 拷贝的个数
2.2.4 memcpy // man memcpy: #include <string.h> void *memcpy(void *dest, const void *src, size_t n); // void *:非字符空间标识符 // n:非字符空间的大小 例1: int buf[10]; int sensor_buf[100]; // memcpy(buf, sensor_buf, 10); 错误!! 10是10个字节(char)
memcpy(buf, sensor_buf, 10 * sizeof(int)); // 拷贝的是10个int大小 例2: unsigned char buf[10]; unsigned char sensor_buf[100]; memcpy(buf, sensor_buf, 10 * sizeof(unsigned char));
2.3 用指针表示数组
2.3.1 一维数组与一级指针 int b[100]; int *p1 = b; // 数组名就是数组首地址,可以赋给一个指针
2.3.2 指针数组与多级指针(二级指针) int b[100]; // 100个空间都存的是int整型值 // 指针数组 char *a[100]; // 100个空间都存的是*(指针),指针对取的方式是char(一个字节一个字节地操作) sizeof(a) = 100 * 4; // 1个地址4个字节 // 二级指针 char **a ; // 指针数组和二级指针,都通过a[0]、a[1]这样的方式访问
char a[100]首地址被指针指向,就成了char *a
2.3.3 多维数组(二维数组) (1)Q:二维数组与二级指针有关吗? // 定义一个指针,指向int b[5][6]的首地址 // 错误!: int **p2 = b; 例1: // 001.c #include <stdio.h> int main() { int a[5][6]; // 二维数组
int **p2 = a; // 二级指针 return 0; } 无效的指针类型:p2读内存的方式,和a读内存的方式是不一样的 二维数组与二级指针没有一点关系,完全不一样 二维数组与二级指针没有一点关系,完全不一样。 二级指针:只是描述地址的线性关系,是地址的一个存储器。 二维数组:一块一块地读内存。 (2)Q:二维数组该如何用指针表示? int a; // 一个int型变量a int *p; // 一个int型指针p
int a[5]; int *p[5]; int (*p)[5]; 例2: // 002.c #include <stdio.h> int main() { int a[5][6]; int (*p2)[6] = a; // 指针表示二维数组 return 0; }
这次编译没有警告了,说明a[5][6]读内存的方式,和(*p2)[6]读内存的方式是一样的 (3)多维数组 int b[2][3][4]; // 多维数组 int (*p)[3][4] = b; // 指针表示多维数组

转载于:https://www.cnblogs.com/wangpeiq/p/10882688.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值