文章目录
前言
本篇主要记录C语言指针相关知识
学习笔记,如有错误,还请指正。
新人小白,码字不易,希望各位能多多点赞收藏关注,感谢各位。
一、内存
存储器:存储数据器件
外存
外存又叫做外部存储器,长期存放数据,掉电不丢失数据
常见的外存设备::硬盘、flash、rom、u盘、光盘、磁带
内存
内存又叫做内部存储器,暂时存放数据,掉电丢失数据
常见的内存设备:RAM,DDR
物理内存:实实在在存在的存储设备。
虚拟内存:操作系统虚拟出来的内存,当一个进程被创建的时候,或者程序运行的时候都会分配内存,虚拟内存和物理内存之间存在映射关系。
操作系统会在物理内存和虚拟内存之间做映射。
在32位系统下,每个进程(运行中的程序)的寻址范围是4G,0x00 00 00 00 ~ 0x ff ff ff ff在写程序的时候,都是虚拟内存。
在运行程序的时候,操作系统会将虚拟内存分区。
栈
静态全局区
代码区
文字常量区
内存以字节为单位来存储数据的,可以将程序中的虚拟寻址空间,看成一个很大的一维的字符数组
二、指针的相关概念
操作系统给每个存储单元分配了一个编号,0x00 00 00 00 ~ 0xff ff ff ff
这个编号称为地址
指针就是地址
指针变量:是个变量,是一个指针变量,这个变量用来存放一个地址编号
在32位平台下,地址总线是32位的,所以指针变量是32位的,即4个字节。
注意:
1)无论什么类型的指针,都是存储单元的编号。在32位平台下都是4个字节,任何类型的指针变量都是4个字节大小
2)对应的指针变量,只能存放对应类型的变量的地址
扩展:
字符变量char ch; ch占一个字节,他又一个地址编号,这个地址编号就是地址。整形变量 int a; a占四个字节,它占用四个字节的存储单元,有四个地址编号。
int a = 0x00 00 23 4f
三、指针的定义方法
3.1简单的指针
数据类型 *指针变量名;
int *p; //定义了一个指针变量
在定义指针变量的时候 * 是用来修饰变量的说明变量p是一个指针变量。
变量名是p
3.2关于指针的运算符
& 取地址:获取一个变量的地址
* 取值: 在定义一个指针变量时,起到标识符的作用,标识定义的是一个指针变量
除此之外其他地方表示获取一个指针变量保存的地址里面的内容。
#include <stdio.h>
int main(int argc, char *argv[])
{
//定义一个普通变量
int a = 100;
//定义一个指针变量
int *p;
//给指针变量赋值
//将a的地址保存在p中
p = &a;
printf("a = %d %d\n", a, *p);
printf("&a = %p %p\n", &a, p);
return 0;
}
执行结果:
扩展:如果在一行中定义多个指针变量,
需要在每个指针变量前面加上*修饰
int *p,*q //定义了两个整形的指针变量p q
int *p,q //定义了一直整形指针变量p,和一个整形变量q
3.2指针大小
在32位编译器下,所有类型的指针都是4个字节
在64位编译器下,所有类型的指针都是8个字节
#include <stdio.h>
int main(int argc, char *argv[])
{
char *a;
short *b;
int *c;
long *d;
float *e;
double *f;
printf("sizeof(a) = %d\n", sizeof(a));
printf("sizeof(b) = %d\n", sizeof(b));
printf("sizeof(c) = %d\n", sizeof(c));
printf("sizeof(d) = %d\n", sizeof(d));
printf("sizeof(e) = %d\n", sizeof(e));
printf("sizeof(f) = %d\n", sizeof(f));
return 0;
}
执行结果(这里我使用的是32位编译器):
四、指针分类
按照指针指向的类型分类
4.1字符指针
字符型数据的地址
char *p;//定义了一个字符指针变量,只能存放字符型数据的地址编号
char ch;
p= &ch;
4.2短整型指针
short int *p;//定义了一个短整型的指针变量p,只能存放短整型变量的地址
short int a;
p =&a;
4.3整型指针
int *p;//定义了一个整型的指针变量p,只能存放整型变量的地址
int a;
p =&a;
注:多字节变量,占多个存储单元,每个存储单元都有地址编号,
c语言规定,存储单元编号最小的那个编号,是多字节变量的地址编号。
4.4长整型指针
long int *p;//定义了一个长整型的指针变量p,只能存放长整型变量的地址
long int a;
p =&a;
4.5float 型的指针
float *p;//定义了一个float型的指针变量p,只能存放float型变量的地址
float a;
p =&a;
4.6double型的指针
double *p;//定义了一个double型的指针变量p,只能存放double型变量的地址
double a;
p =&a;
4.7函数指针
4.8结构体指针
4.9指针的指针
4.10数组指针
总结:无论什么类型的指针变量,在32位系统下,都是4个字节,只能存放对应类型的变量的地址编号。
五、指针和变量的关系
指针可以存放变量的地址编号
在程序中,引用变量的方法
- 直接通过变量的名称
int a;
a = 100;
2)通过指针变量来引用变量
int *p; //在定义的时候,*是修饰的意思,修饰p是一个指针变量
p = &a; //取a的地址赋给p,p保存了a的地址,p指向a
*p = 100;//在调用的时候*是取值的意思,*指针变量 等价于 指针指向的变量
注意:
指针变量在定义的时候可以初始化
int a;
int *p = &a; //用a的地址,给p赋值
指针变量只能保存开辟好空间的地址,不能随意保存地址
#include <stdio.h>
int main(int argc, char *argv[])
{
int *p1,*p2,temp,a,b;
p1=&a;
p2=&b;
printf("请输入:a b的值:\n");
scanf("%d %d", p1, p2);//给p1和p2指向的变量赋值
temp = *p1; //用p1指向的变量(a)给temp赋值
*p1 = *p2; //用p2指向的变量(b)给p1指向的变量(a)赋值
*p2 = temp;//temp给p2指向的变量(b)赋值
printf("a=%d b=%d\n",a,b);
printf("*p1=%d *p2=%d\n",*p1,*p2);
return 0;
}
执行结果:
扩展:
对应类型的指针,只能保存对应类型的地址
如果想要让不同类型的指针相互赋值打的时候,需要强制类型转换
#include <stdio.h>
int main(int argc, char *argv[])
{
int a=0x1234,b=0x5678;
char *p1,*p2;
printf("%#x %#x\n",a,b);
p1=(char *)&a;
p2=(char *)&b;
printf("%#x %#x\n",*p1,*p2);
p1++;
p2++;
printf("%#x %#x\n",*p1,*p2);
return 0;
}
执行结果:
注意:
1:*+指针 取值,取几个字节,由指针类型决定的指针为字符指针则取一个字节, 指针为整型指针则取4个字节,指针为double型指针则取8个字节。 2:指针++ 指向下个对应类型的数据 字符指针++ ,指向下个字符数据,指针存放的地址编号加1 整型指针++,指向下个整型数据,指针存放的地址编号加4
六、指针和数组元素之间的关系
6.1数组元素与指针的基本关系
变量存放在内存中,有地址编号,咱们定义的数组,是多个相同类型的变量的集合,
每个变量都占内存空间,都有地址编号指针变量当然可以存放数组元素的地址。
int a[10];
int *p;
p = &a[0] //指针变量p保存了数组a中第0个元素的地址,即a[0]的地址
6.2数组元素的引用方法
1)数组名[下标]
int a[5];
a[2] = 1;
2)指针名加下标
int a[5];
int *p;
p = a;
p[2] = 1; //p和a等价
C语言规定:数组名字就是数组的首地址,即第0个元素,是一个常量
注意:p和a不同,p是指针变量,而a是常量。所以可以用等号给p赋值,而不能给a赋值
3)通过指针运算加取值的方法来引用数组的元素
int a[10];
int *p;
p = a;
*(p+2) = 100; //相当于a[2] = 100;
解释:p是第0个元素的地址,p+2是对第二个元素的地址,a[2]
#include <stdio.h>
int main(int argc, char *argv[])
{
int a[5]={0,1,2,3,4};
int *p;
p=a;
//只要将数组名赋值给同类型的指针变量,则此时的指针变量与数组名可
//以用相同的方法操作数组
printf("a[2]=%d\n",a[2]);
printf("p[2]=%d\n",p[2]);
//*(a + n) <==> *(p + n) <==> a[n] <==> p[n]
printf("*(p+2) = %d\n",*(p+2));
printf("*(a+2) = %d\n",*(a+2));
printf("p=%p\n",p);
printf("p+2=%p\n",p+2);
printf("&a[0] = %p\n", &a[0]);
printf("&a[2] = %p\n", &a[2]);
return 0;
}
执行结果:
七、指针的运算
7.1指针可以加一个整数
往下指几个它指向的变量,结果还是个地址
前提:指针指向数组的时候,加一个整数才有意义
test1()
7.2两个相同类型指针可以比较大小
前提:只有两个相同类型的指针指向同一个数组的元素的时候,比较大小才有意义
指向前面元素的指针 小于 指向后面 元素的指针
test2()
7.3两个相同类型的指针可以做减法
前提:必须是两个相同类型的指针指向同一个数组的元素的时候,做减法才有意义
做减法的结果是,两个指针指向的中间有多少个元素
test3()
7.4两个相同类型的指针可以相互赋值
注意:只有相同类型的指针才可以相互赋值(void *类型的除外)
test4()
#include <stdio.h>
//指针的运算
//指针可以加一个整数,往下指几个它指向的变量,结果还是个地址
void test1()
{
int a[10];
int *p, *q;
//p和q间隔8个字节,意味着加一个整数最终移动的字节数与指针变量的类型也有关系
p = a;
q = p + 2;
printf("p = %p\n", p);
printf("q = %p\n", q);
return ;
}
//两个相同类型指针可以比较大小
void test2()
{
int a[10];
int *p,*q;
p=&a[1];
q=&a[6];
if(p<q)
{
printf("p < q\n");
}
else if(p>q)
{
printf("p > q\n");
}
else
{
printf("p = q\n");
}
}
//两个相同类型的指针可以做减法
void test3()
{
int a[10];
int *p,*q;
p=&a[0];
q=&a[3];
printf("%d\n",q-p);
}
//两个相同类型的指针可以相互赋值
void test4()
{
int a = 100;
int *p, *q;
p = &a;
printf("a = %d %d\n", a, *p);
q = p;
printf("*q = %d\n", *q);
*q = 999;
printf("a = %d\n", a);
}
int main(int argc, char *argv[])
{
test4();
return 0;
}
执行结果:
八、数组指针
8.1指针和数组的关系
1)指针可以保存数组元素的地址
2)可以定义一个数组,数组中有若干个相同类型指针变量,这个数组被称为指针数组
指针数组:
指针数组本身是个数组,是个指针数组,是若干个相同类型的指针变量构成的集合
8.2指针数组的定义方法
类型说明符 *数组名[数组个数]
int *p[10];///定义了一个整型的指针数组p,有10个元素p[0]~p[9],每个元素都是int*类型
int a;
p[1] = &a;
8.3指针数组的分类
字符指针数组char *p[10]、短整型指针数组、整型的指针数组、长整型的指针数组
float型的指针数组、double型的指针数组
结构体指针数组、函数指针数组
#include <stdio.h>
int main(int argc, char *argv[])
{
//大多数情况下,指针数组都用来保存多个字符串
char *name[5] = {"Follw me","BASIC","Greatwall","FORTRAN","Computer"};
int i;
for(i=0;i<5;i++)
{
printf("%s\n",name[i]);
}
return 0;
}
执行结果:
总结
本节主要讲解了部分指针的基础知识,还会有一节更新指针。
新人小白,如有错误,还请指正
码字不易,希望各位能够点赞收藏关注,谢谢各位