内存,计算机中的内存,通常说的是虚拟内存, 它是所有硬件内存条在操作系统,并且是运行起来的OS中的一个地址映射 比如,电脑中插入4个16G的内存条,那么电脑的内存为64G 这个64G就是从0开始,然后1,2,3,...,直到64G-1 可以将之看作一个刻度尺,0代表第1格,1代表第2格,64G-1代表最后一格 所有的进程使用的都这一个虚拟内存,毕竟整个电脑 也就这64G内存 0,1,2,3,...虚拟内存对应的数字标记,就是内存地址,也叫指针 地址3,就是虚拟内存的第4个格, 每个格是一个字节,一个Byte,代表了8位,就是8bit, 一个bit可以是0或1, 8bit表示一个字节是这样的:00000010,这个数表示2,是2进制 指针就是地址,就是一个数字,这个数字对应着虚拟内存上的一个字节位置
数字变量
int a =1; 这是一个整数变量,也是一个变量,也就是说它不是常量,即a的值可以变化,比如 a =2; a这个字符标记,对应着虚拟内存上的一个地址,就是一个数字, &a可以取变量a的地址
C语言中进制前缀
二进制 前缀 0b 示例 0b100 十进制 4 八进制 前缀 0 示例 0100 十进制 64 十进制 无前缀 示例 100 十进制 100 十六进制 前缀 0x 示例 0x100 十进制 256
#include <stdio.h> int main(){ int a=1; printf("%p\n",&a);//0x7ffcf4fb0a7c a=2; printf("%p\n",&a);//0x7ffcf4fb0a7c return 0; }
变量a从1到2的过程中,其地址是不变的, 就是将虚拟内存中地址为0x7ffcf4fb0a7c为开头及之后的三个格子,一个共四个格子,存储的数字从1变更为2 一个地址只能表示一个格子,但整数int在计算机中占用4个字节,变量a的数据类型为int,就表示它要用四个格式 但&变量返回的地址,只有一个数字,是一个地址, 将前后连续的四个格子看作一个数据单元这个操作由C语言自动完成
变量a 操作一个变量,比如输出,是则是输出 变量a的值 &a 每个变量在栈上,也只能是在栈上,分配有一个地址,&a指取变量a在栈上的地址 *(&a) 即*号可以从一个地址中取出该地址对应的值
指针与指针变量
指针就是地址 指针变量就是存放指针的,即存放地址的 任何一个变量都对应着一个地址/指针,比如int a=1; 符号a就对应着一个地址,&a表示其符号a的地址, a=1;表示将1这个数字赋值到符号a对应的地址上 指针变量也对应着一个地址,该地址中存放的是地址/指针
#include <stdio.h> int main(){ int a=1; int* b=&a; printf("%p\n",b); //0x7ffcb9d9cc8c printf("%p\n",&b);//0x7ffcb9d9cc80 return 0; }
符号b是一个指针变量,它的值是一个地址/指针, 符号b本身也有一个地址0x7ffcb9d9cc80,并且是整数
数据类型**:双星,指向指针的指针
终于来到了高能时刻... int a=1; int* b=&a; b是一个指针变量,其值是指针,通常提到一个变量其实意在指这个变量的值, 比如这里,b 指 变量a的地址 b本身也是有地址的,&b是取变量b的地址,这是一个值,也可以用一个变量来存储,这就是指向指针的指针 #include <stdio.h> int main(){ int a=1; int* b=&a; int** c = &b; printf("%p\n",b); //0x7ffec0cc0504 printf("%p\n",&b);//0x7ffec0cc04f8 printf("%p\n",c); //0x7ffec0cc04f8 *(*c) =2; printf("a=%d\n",a); //a=2 return 0; } 对于整数来说,很少这么操作,请看下面的字符串:
C语言经典字符串传参
#include <stdio.h> void change(char** tmp){ *tmp = "abc"; } int main(){ char* a; change(&a); printf("-%s-\n",a);//-abc- return 0; }
change函数传递的是指针变量a的地址,即&a 进入函数再使用*,即*(&a),相当于直接修改了变量a *(&a) = "abc"; 相当于 a = "abc"; a = "abc";对应的操作是,向符号a对应的地址存入"abc"的首地址 ("abc"返回的是字符串的首地址,因为变量a是指针变量,其值是要放指针的), 函数中的一系列操作,建立在对地址的操作上,而一个计算机的虚拟内存只有一个 所以从函数中出来后,变量a的值也随之改变
这里change函数传参这个过程本身是值的复制, &a是一个数,将这个数复制给另外一个变量,再取这个变量的值进程操作 只是先向上追溯一个向量的地址,将地址传进去后,再取其值,就回到该变量本身了 这样就做到了,在函数中,直接操作外部向量 这里说的参数值复制,意思是说*tmp与a的值是一样的, 即指向的地址相同,但它们不是一个符号,只是彼此等价, 说到底,函数并没有将变量a真的传递进函数,传递的只有地址... 符号什么的,只是一个表示,人看着方便就行... 你要是乐意,你可以将无数个符号指向同一个地址
这个过程并不复杂,只是字符变量本身多了一个指针,在形式上看着复杂了,其实这个过程就两步: 1. 向函数上传入一个变量的地址,&变量 2. 在函数中取出这个变量,*变量 这样就做到在函数中直接操作外部变量了
#include <stdio.h> void ch(int* i){ *i = 2; } int main(){ int i=1; ch(&i); printf("i=%d\n",i);//i=2 return 0; }
字符指针指向一个字符串的首地址 "abc"的特殊在于,它本身多占一个字符'\0' 输出字符串时,从其首地址开始,遇'\0'字符结束,这个过程是自动的 为什么会这样,为什么要这样? 因为整数有固定长度,比如int占四个字节, int*指针指向第一个字节的地址,自动向后移动三次,凑够四个字节,就凑齐了所需要的字节了 而字符串中的字符数字是不固定的,一个字符串与另外一个字符串的长度是否相等不确定, 它可以很短,也可以很长... 所以,就使用'\0'这个字符来统一表示字符串的结尾,遇到这个就表示结束了