1. 指针 指针与地址: 指针在内存中占用8(64位),并且,指针里面能存地址,指针有自己的地址。
指针里面的存的地址可以改变,但是地址本身不能变化。 指针有类型概念,地址只是一个16进制的常量。 指针本身可以移动指向新的数据空间,并且指针移动一位字节数不一样(由类型决定)。 指针有两两层含义:1. 表示一个能存地址变量(等效于指针变量)2. 指还含有数据类型的概念。
指针的内存布局 先看一个例子: 这里定义了一个指针p,一个“int *”类型的模子在内存上咔出了8个字节(根据编译器环境不同而不同,64位是8个字节,32位是4个字节)的空间,然后这个空间命令为p,同时限定这4个字节的空间里面只能存储某个内存地址,即使你存入别的任何数据,都被当做地址来处理,而且这个内存地址开始的连续4个字符上只能存储某个int类型的数据。
file:///var/folders/mk/_b94wp2j747_xv_dyxzvmm8w0000gn/T/WizNote/9631532b-4a0c-43e6-a4b6-3ca0c8d1832e/index_files/c0fe214c-9fd5-4fee-8326-9beb84b31c3a.png 如上图所示,我们把p称为指针变量,p里存储的内存地址处的内存称为p所指向的内存。指针变量p里存储的任何数据都将被当作地址来处理。 我们可以这么理解:一个基本的数据类型(包括结构体等自定义类型)加上“*”号就构成了一个指针类型的模子。这个模子的大小是一定的,与“*”号前面的数据类型无关。“*”号前面的数据类型只是说明指针所指向的内存里存储的数据类型。所以,在64位系统下,不管什么样的指针类型,其大小都是8byte,sizeof(void *)也是8个字节。
注意int *p = NULL 和 *p = NULL的区别 p的值为 0x00000000。解释为:定义一个指针变量p,其指向的内存里面保存的是int类型的数据,在定义变量p的同时把p的值设置为0x00000000,而不是把*p的值设置为0x00000000。这个过程叫做初始化,是在编译的时候进行的。 然后再看下面的代码:
因此,我们可以改写上面的代码,使p指向一块合法的内存 int i = 10; int *p = &i; *p = NULL;
调试的时候可以发现:p所指向的内存地址存储的数据从10变成了0,但是p本身的值,也就是内存地址并没有变。 备注:NULL是一个宏定义 如何将数值存储到指定的内存地址 假设现在需要往内存0x12ff7c地址上存入一个整型数0x100。我们怎么才能做到呢?我们知道可以通过一个指针向其指向的内存地址写入数据,那么这里的内存地址0x12ff7c其本质就是一个指针。所以我们可以用下面的方法: 也可以这么写:
2. 数组 数组的内存布局
先看一个例子 上面定义了一个数组,其包含了5个int型的数据,我们可以用a[0], a[1]等来访问数组里面的每一个元素,那么这些元素的名字就是a[0], a[1]...吗?我们看一个图:
file:///var/folders/mk/_b94wp2j747_xv_dyxzvmm8w0000gn/T/WizNote/9631532b-4a0c-43e6-a4b6-3ca0c8d1832e/index_files/deeb2ef4-07ea-4aa9-84b5-a8a6757bbc32.png 如上图所示,当我们定义一个数组a时,编译器根据指定的元素个数和元素的类型分配确定大小(元素类型大小*元素个数)的一块内存,并把这块内存的名字命名为a,名字a一旦与这块内存匹配就不能改变。a[0], a[1]等为a的元素,但并非元素的名字。数组的每一个元素都是没有名字的。那现在再看一下sizeof和数组的几个问题: 在64位系统环境下:(sizeof关键字求值是在编译时) #include <stdio.h> int main(int argc, char const *argv[]) { int a[5]; printf("%lu\n", sizeof(a)); // 20 printf("%lu\n", sizeof(&a)); // 8 printf("%lu\n", sizeof(a[0])); // 4 printf("%lu\n", sizeof(&a[0])); // 8 return 0; }
&a[0]与&a的区别
a[0]是一个元素, a是整个数组,虽然&a[0]和&a的值一样,但其意义不一样。前者是数组首元素的首地址,而后者是数组的首地址。比如:湖南的省政府在长沙,而长沙的市政府也在长沙,两个政府都在长沙,但其代表的意义完全不同。这里也是同一个意思。
字符数组
字符串 是一个以'\0'结尾的字符数组,是一串字符。 定义及初始化:char arr[] = "abc"; 或 char arr[4] = {'a', 'b', 'c', 'd', '\0'};
输出:printf("%s\n", s); 或 printf("%s\n", &arr[0]);
赋值:strcpy(字符变量名,"字符串");
特点 后面必须有'\0'结尾,否则只是普通的字符数组,但是'\0'不会输出,只表示字符串结束。 字符串输出占位用%s,必须遇到'\0'才会结束,否则会继续输出更高位地址值的字符。 srelen函数用于计算一个字符串的长度(字符常量),使用必须引入<string.h>。 strlen不会计算'\0',且碰到'\0'结束,但是sizeof不受'\0'映像,且长度会包含'\0'. 字符串一定是字符数组,但字符数组不一定是字符串。
#include <stdio.h> int main(int argc, char const *argv[]) { char s[] = "abcd"; char s1[] = {'a', 'b', 'c'}; printf("%s\n", s1); // adcabcd 在内存访问到'\0'为止,所以连s一起输出 return 0; }
|