数组
- 数组是什么
数组算是定义了一块连续的空间,数组名就是这块连续空间首地址的名字
这块空间多大?—数组的长度乘以元素的类型得到 或者使用sizeof也行
如何访问?—数组的起始地址 + 对应的偏移量
数组的起始地址可以用数组名得到 - 一维数组和二维数组
- 2.1 一维数组
int a[2] = {1,2,3,4};//不会报错但是会warning 越界了
从汇编也能看出来 确实只分配了8个字节 所以数组越界行为的后果都是未定义的
.global a
.data
.align 2
.type a, %object
.size a, 8 - 2.2二维数组
int a[4][2] = {1,2,3}; //明确了大小 就是 4 * 2 * 4个字节,虽然部分没填满
int b[][2] = {1,2}; // 告诉编译器自己推导大小是多大 根据给定的数据
int c[][] = {5,6}; // 错误的初始化
.global a.data.align 2.type a, %object.size a, 32.global b` .align 2.type b, %object.size b, 8
- []运算符 与 *运算符
a[x]运算符本质上就是(a + x)运算符
不过这里注意 指针的++可不是单纯的递增1 而是和数据类型有关
- 3.1 []里面的数可以是负数吗?
当然可以 只要这个[]里面的表达式最后能算出来数 是啥都行 - 3.2二维数组的运算
数组名可以看做是这块连续内存的起始地址的别名
int main(){int array[4] = {1,2,3};int count = 2;printf("%d %d %d\r\n",array[count],*(array + count),(array - count)[count]); printf("%d\r\n",a[3][0]);return 0;}
- 二维数组呢?
int a[4][2] = {1,2,3};
a++相当于移动了多少个字节呢
printf("%p %p\r\n",a,a + 1); // 0x55eae2a01020 0x55eae2a01028
相当于移动了8个字节 此时a可以看做是这样类型 int (* a)[2];
- 数组指针与指针数组
- 数组指针
本质上是个指针 指向了一个数组
int (*a)[2]; // 这是一个指针 指向一个数组 数组的大小是2 元素类型是int - 指针数组
本质是个数组 只不过里面元素类型是指针
int a[2]; // 这是一个长度为2的数组 数组里元素的类型是 int *
因为指针的操作 每次++都是按照指针的类型自增地址的
int p[8] = {1,2,3,4,5,6,7};
int a[2];
a = p;
printf("%d %d %d",(a),(++a),a[2]); // []等于*
所以我们可以通过指针数组实现跳着访问一维数组
void test1(){int p[8] = {1,2,3,4,5,6,7};int (*a)[2] = (int (*) [2])p;int (*b)[2] = (int (*) [2])p;printf("%d %d %d\r\n",*(a)[0],*(++b)[0],a[2][0]); }
- 字符、字符串与字符数组
- 字符串与字符数组
实际上我们是用字符数组存储字符串 如果字符串是用""定义的 会自动往后面补上’\0’
但是如果是 char a[]= {‘a’, ‘b’, ‘c’} 不手动添加’\0’的话是不会有的
但是,字符数组会自动补0,so有时候就会发蒙就是因为这个
#include <stdio.h>void test1(){char a[] = {'a','b','c'}; char b[6] = {'a','b','c'}; char * c = "abc";printf("%d %d %d\r\n",strlen(a), strlen(b), strlen(c)); printf("%d %d %d\r\n",sizeof(a), sizeof(b), sizeof(c)); }int main(){test1();}movb $97, -33(%rbp)movb $98, -32(%rbp)movb $99, -31(%rbp)movl $0, -30(%rbp) movw $0, -26(%rbp)movb $97, -30(%rbp)movb $98, -29(%rbp)movb $99, -28(%rbp)
- 转义字符
我们最常用的就是 \r\n 和 \ - \x转义字符–表示16进制
char a = ‘\x15’; // 表示值为 0x15 = 21
所以’\x’有范围 为’\x00 ---- \xff’
'\xffff’就是不对的
char sub1 = ‘\x15’;
char sub2 = ‘\x1555’;
printf("%d %d\r\n",sub1, sub2); // suib2 = 85 还是得看编译器怎么做 - 八进制 \105 反斜杠后面的就默认是8进制的
printf("\150\n"); //答案就是105
- 数组与指针的区别
- 数组是连续的区间 指针指向的区间大小可不一定,也不一定连续(链表)
- 同种类型指针之间可以直接赋值,数组只能一个个元素赋值
- 概念不同
数组:是同种类型的集合
指针:里面保存的地址的值 - 所占用的字节不同
- 修改内容的方式不同
char * c = "abc";char d[] = "abc";void test2(){c[0] = '5';d[0] = '5';printf("修改已完成");}.globl c.section .rodata..................globl d.data.type d, @object.size d, 4
- 数组作为参数传递----直接当做指针处理
void test1(int array[]) {int n = sizeof(array) / sizeof(array[0]); }int array[10] = {1,2};
- 实现排序
什么冒泡啊 快排啊之类的
指针
- 指针是什么,指针的类型
指针其实也是个变量,只不过这个变量里面存储的是内存地址
这个内存地址指向了一片内存 通过指针 + */[] 就可以操作这块内存 - 指针的类型
int * char; // 指针类型为 int *
函数指针 指针类型就是它
- 指针的运算
一定注意只有同类型的指针才可以运算
比如一个指针指向float 一个指针指向int 是不可以进行运算的
- 2.1 指针的自增/减
int *p;
p ++;
此时不是单纯的数值 + 1 而是 + siezeof(type),这里是int 所以打印++p的结果%p会发现地址增加了4 - 2.2 两个指针相减–表示它们在内存中的距离
相减的结果以数据类型的长度sizeof(type)为单位,而
int main (void){int a[10];int *p1,*p2;p1 = &a[1];p2 = &a[2];printf("%d\n", p2 - p1);return 0; }#define mysizeof2(name) ((size_t)(&(name)+ 1) - (size_t)(&name))
- 2.3 比较运算符
p < q:指针p所指的数在q所指数据的前面。
- &运算符和运算符,[]运算符
只要了解[]运算符和运算符的本质木有区别就行 - 强制类型转换
int num = 0x12345679;char * p = (char*)#printf("%02x %02x %02x %02x\r\n",p[0],p[1],p[2],p[3]);
- 大端与小端
大端:是高字节序的存放在低地址
小端:是高字节序的存放在高地址
什么是高字节序 int a = 0x1234;// 34是低字节序 12是高字节序
注意:栈是从高地址向低地址生长的
// 打印 p[0] = 0x79 说明低地址存放低字节序 所以是小端 - 空指针与野指针与void*
野指针:是指指针指向的地址是不确定的;
原因:释放内存之后,指针没有及时置空
避免: - 初始化置 NULL
- 申请内存后判空
- 指针释放后置 NULL
空指针就是指向了地址为0的地方 - void*表示一种通用的指针 但注意不能直接解引用
void *my_memcpy(void *dest, const void *src, size_t n) {void * res = dest;while (n--) {*dest++ = *src++; }return res;}
- 二级指针
- 7.1二级指针与指针数组–传入参数
char *a[4] = {“123”,“456”,“789”,“101”};
void test(char *a[],int len);
void test2(char **a,int len); //使用起来没有区别 - 7.2二级指针与二维数组
void test3() {int array[5][10] = {1,2,3,4,5,6,7,8,9,10,11,123}; int * p = array; printf("%d \r\n",p[6]); int ** p2 = array;printf("%d %d %d\r\n",p2[0],p2[1], p2[2]);int (*p3)[10] = array; printf("%p %p %d %d %d\r\n",p3, p3 + 1, *(p3)[0], *(p3 + 1)[0],p3[1][1]);int (*p4)[2] = array; printf("%p %p %d %d %d\r\n",p4, p4 + 1, *(p4)[0], *(p4 + 1)[0],p4[1][1]);}
- 指针和引用的区别
- 指针是实体,而引用是别名。
- 指针和引用的自增(++)运算符意义不同,指针是对内存地址自增,引用是对值的自增。
- 引用使用时无需解引用(*),指针需要解引用;
- 引用只能在定义时被初始化一次,之后不可变;指针可变。
- 引用不能为空,指针可以为空。
- sizeof的结果不同