零基础C语言入门024——指针

指针是一种数据类型,指针定义的变量是用来装地址的
内存是如何存放变量的?
通过变量名对变量进行访问和存储是为了方便程序员而设计的,其实在内存中完全没有存储变量名的必要。因为编译器知道具体每一个变量名对应的存放地址,所以当你读取某个变量的时候,编译器就会找到变量名所在的地址,并根据变量的类型读取相应范围的数据。
在这里插入图片描述 指针和指针变量
通常我们所说的指针,就是地址的意思。C 语言中有专门的指针变量用于存放指针,跟普通变量不同,指针变量存储的是一个地址。
指针变量也有类型,它的类型就是存放的地址指向的数据类型。
在这里插入图片描述看图,上边我们又定义了两个指针变量:pa 和 pb,因为它们是指针变量,所以它们在内存中存放的是地址。这里我们分别存放了变量 a 和 f 的地址。在我们的编译系统中,指针变量是占 4 个字节的空间,也就是说一个地址是占 4 个字节的空间。

定义指针变量
定义指针变量跟普通变量十分相似,只是中间多了一个星号(*)。

char *pa;
int *pb;

左侧的数据类型表示指针变量中存放的地址指向的内存单元的数据类型。
比如刚才的图中,指针变量 pa 中存放字符变量 a 的地址,所以 pa 应该定义为字符型指针;而指针变量 pb 中存放的是整型变量 f 的地址,所以 pb 就定义为整型指针。这点一定要注意,因为不同数据类型所占的内存空间不同,如果指定错误了,那么在访问指针变量指向的数据时就会出错。
取地址运算符和取值运算符
如果需要获取某个变量的地址,可以使用取地址运算符(&):

char *pa = &a;
int *pb = &f;

如果需要访问指针变量指向的数据,可以使用取值运算符(*):

printf("%c, %d\n", *pa, *pb);

这里要注意的是取值运算符跟定义指针用的都是星号(*),这属于符号的重用,在不同的地方有不同的意义:在定义时表示定义一个指针变量;在其他位置表示获取指针变量指向的变量的值。
直接通过变量名来访问变量的值,我们称之为直接访问;通过指针变量这样的形式来访问变量的值,我们称之为间接访问,所以取值运算符有时候也叫间接运算符。
避免访问未初始化的指针

//访问获得变量的值可用变量名,也可用指针间接访问 
#include<stdio.h.>
int main(void)
{
	int a;
	int *b=&a;//这里的*表示定义,这是一个指针变量,前面的int表示指针指向int类型
	printf("请输入一个整数:\n");
	scanf("%d", &a);
    printf("%d\n",a);/*通过变量名访访问变量的值*/
	printf("%d\n",*b);/*通过指针间接访问变量的值*/
	system("pause");
	return 0;
}
//scanf函数要获取地址信息,可以不用&a,直接用b代替 
#include<stdio.h.>
int main(void)
{
	int a;
	int *b=&a;
	printf("请输入一个整数:\n");
	scanf("%d", b);/*这里p就不用&取址操作符,如果加了就是获取指针p的地址*/
	system("pause");
	return 0;
}
//错误演示
#include <stdio.h>
int main(void)
{
    int *a;
    *a = 123;
    system("pause");
    return 0;
}

类似于上边这样的代码是很危险的,因为指针变量 a 到底指向哪里,我们没办法知道。这个道理就跟访问未初始化的变量一样,它的值是随机的。
这在指针变量里会很危险,因为后边代码对一个未知地址进行赋值,那么你可能会覆盖到系统的一些关键代码。不过你也别高兴得太早,因为系统通常都不会允许你这么干,程序这时候会被终止并报错。
更危险的是,偶尔这个指针变量里随机存放的是一个合法的地址,那么接下来的赋值就会导致那个位置的值莫名其妙地被修改。这种类型的 Bug 是非常难以排查的。
所以,在对指针进行间接访问时,必须确保它们已经被正确地初始化。

//通过指针来访问和修改变量的值 
#include<stdio.h>
int main(void)
{
	char m='f';
	int n=5;
	char *a=&m;
	int *b=&n;
	printf("%c--%d\n",*a,*b);/*访问指针来间接访问变量的值*/
	*a='u';/*对指针进行操作来修改变量的值*/
	*b+=1;
	printf("%c--%d\n",m,n);/*里面参数可以用变量名m, n也可以用指针取值*a,*b*/
	printf("占用字节:%d--%d\n",sizeof(a),sizeof(b));/*指针变量只占用四个字节*/
	printf("地址:%p--%p\n",a,b);	/*指针(变量的地址)以十六进制形式存放
	后面参数指针名就不用加*,加*是为了取这个指针所指向的变量值,*/
	system("pause");
	return 0;
}
//可以对指针进行操作,来改变所指向变量的值。
#include <stdio.h>
int main(void)
{
        int a = 110;
        int *b = &a;
        *b = *b - 10;
        /**b减10相当于变量a减10,指针取值可以当变量直接放入表达式*/
        printf("a = %d\n", a);
        system("pause");
        return 0;
}

对指针操作只有三种:读,写,取地址

//对指针操作只有三种:读,写,取地址
#include<stdio.h>
int main(void)
{
    int a=5;
    int *p=&a;
    //这里的*表示定义,这是一个指针变量,前面的int表示指针指向int类型
    //读——*为内存操作符,读取内存
    printf("%d,%d\n",*p,a);
    //写
    *p=7;
    printf("%d,%d,\n",*p,a);
    //取地址
    printf("%p,%p\n",&*p,&a);//这里的*p等同于a
    system("pause");
    return 0;
}

C 语言的术语 lvalue 指用于识别或定位一个存储位置的标识符。(注意:左值同时还必须是可改变的)
第一个问题:定义指针变量 b 的时候,存放的是变量 a 的地址。在此之后,*b 即对变量 a 的间接访问(通过地址访问 a 变量)。所以 *b = *b - 10; 相当于 a = a - 10; 也就是说,通过指针对一个变量间接访问,你可以理解为把它作为那个变量本身使唤(即 *b == a)。
第二个问题:指针变量 b 既是左值,也是右值。看 *b = *b - 10; 这个语句,赋值号右边,*b 间接访问变量 a 的值,因为用的是它的值,所以是右值;赋值号左边,*b 用于定位变量 a 的存储位置,然后将右边表达式的值存放进去,所以此时为左值。

指针变量*pa可以直接当变量来用,放入表达式运算。因为指针变量存的地址就是指向整形变量。
指针通过访问地址来间接访问变量要更效率

//用指针法把三个整数按从小到大排列
#include<stdio.h.>
int main(void)
{
	int a, b, c, t;
	int* pa, * pb, * pc;
	printf("请输入三个不相等的数:\n");
	scanf("%d%d%d", &a, &b, &c);
	pa = &a, pb = &b, pc = &c;
	if (a > b)/*三个if判断有规律,顺序不能乱*/
	{
		t = *pa;
		*pa = *pb;
		*pb = t;
	}
	if (a > c)
	{
		t = *pa;
		*pa = *pc;
		*pc = t;
	}
	if (b > c)
	{
		t = *pb;
		*pb = *pc;
		*pc = t;
	}
	printf("%d<%d<%d\n", *pa, *pb, *pc);
	printf("%d<%d<%d\n", a, b, c);
	system("pause");
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值