计算机中,存储单元的相互转换:
1G = 1024M; 1M = 1024K; 1K = 1024B; (1B = 8个位)
char 1个字节 1个内存单元
short 2个字节 2个内存单元
int 4个字节 4个内存单元
long 4/8个字节 4/8个内存单元
float 4个字节 4个内存单元
double 8个字节 8个内存单元
字节和位:
字节:是最小的存储单元,一个字节被称为一个存储单元(也叫做内存单元);不同的数据类型占的存储单元也不相同;
位:一个字节右称作8位,为了正确访问内存单元,每个内存单元都有一个编号,内存单元的编号被称作地址;
内存地址 == 地址 == 内存单元编号;内存单元中的数据才是我们要关注的内容;
指针:即内存地址,简称为地址;
& 和 *
&,“and",取址符,可以查看一个变量的内存地址(首地址),用 %p 格式化输出内存地址;
int a = 998;
printf("&a = %p\n",&a);
注意:&取出来的内存地址,并不是变量只占用一个内存地址,变量的数据类型决定变量占用几个内存地址;
* 取值符,顾名思义,通过‘*‘来访问内存单元中存储的数据;
指针变量:存放内存地址的变量
基本数据类型 *变量名 = 内存地址;
*p = 100;
printf("%d\n",a);
如果出现*号的地方有类型修饰符(int,char,float),此时*只起到标示作用,告诉编译器就是一个指针变量;
*j = 337;
如果出现*的地方没有任何类型修饰符,此时*代表取值操作符,他会把指针指向的区域内的值取出来;
如果前面没有*和内存修饰符,那么这个变量就是指针变量,他里面存储着一个内存地址;
指针赋值:C语言允许使用赋值运算符对指针进行赋值,前提是两个指针具有相同的数据类型;
int i,*p,*q;
p = &i;
q = &j;
i = 1;
*p = *q;
printf("%d\n%d\n%d\n",i,*p,*q);
指针变量所占的字节数,只与 操作系统 位数有关;64位操作系统指针变量占8位,32位占4位;
以上是指针初级,下面是深入了解:
数组的内存地址:在C语言中数组是构造类型,数组会分配一段连续的内存空间来存储数组的全部数据;数组名代表数组首个元素的地址;
指针与数组的区别:
所占空间不同:
指针:只与操作系统位数有关;
数组:与元素个数和数据类型有关;
数组名是常量地址,不能被赋值,不能重定向
指针可以重定向;
指针变量p和array相同,都指向数组第一个元素的内存地址;
printf("%d\n",*(p+1));
(p+1)的内部实现是:p是数组元素的首地址,p+(1*int(当前数据类型所占的字节数));操作的是内存地址;
(p+1)= (p+1*当前数组的类型所占的字节数)
printf("%p\n",p+1);
printf("%d\n",*p+1);
综上所述,*(p+1),是指数组的下标加1;*p+1,是指数组的第一个值加1;*p是数组的第一个元素的地址;
下面四个结果都有一样,都是数组的第二个元素;
p[1] == array[1] == *(p+1) ==*(array +1);
数组名是常量,不能被赋值,不能重定向;
指针可以被重定向;
数组是不能被直接赋值的,数组名代表元素首地址,数组是常量地址,不能被改值,只能使用赋值字符串函数strcpy把值复制进去,或者把数组里面的元素都取出来赋值;
结构体指针变量指向的是结构体变量的首地址,也就是第一个成员的地址;
结构体数组与指针的关系:结构体数组的数组名是一个结构体指针的常量;
结构体指针比较复杂,我们看一个例子吧:
使用 指针 查找学员数组中 性别为男 的学员,成绩增加10分,超过100分的记为100分
typedef struct st{
char name[20];
int age;
char sex;
int score;
}Stu;
Stu stude[4] = {
{"jhbj",18,'m',56},
{"bhkl",21,'w',96},
{"dsff",23,'m',98},
{"ghbi",21,'m',87}
};
Stu *p4 = stude;
// p1 ->age
for (int i = 0; i < 4; i++) {
if ((p4+i)->sex == 'm') {
(p4+i)->score+=10;
}
if ((p4+i)->score > 100) {
(p4+i)->score = 100;
}
}
for (int i = 0; i < 4; i++) {
printf("%d\n",(p4+i)->score);
};