C语言——指针

一.指针基础
在说指针之前,我们先来说说地址。平时生活化的地址比如邮箱地址,ip地址,家庭住址,这些都是地址。
在计算机中,所有的数据都是存放在存储器中的。一般把存储器中的一个字节称为一个内存单元。 为了正确地访问这些内存单元,必须为每个内存单元编上号。内存单元的编号也叫做地址。
既然根据内存单元的编号或地址就可以找到所需的内存单元,所以通常也把这个地址称为指针。也就是说指针就是地址。
内存单元的指针和内存单元的内容是两个不同的概念。比如:教室中有学生,教室是指针,教师的内容是学生;0x100 是指针,这个地址所指向的空间的内容’A’。指针是常量。地址是个常量。
在这里插入图片描述

#include <stdio.h>

int main(int argc, const char * argv[]) {
    
    int a = 10;
    int *p = &a;
    printf("a的地址 = %p, a的内容 = %d\n", &a, a); //a的地址 = 0x7ffeefbff4bc, a的内容 = 10
    printf("p = %p, *p = %d\n", p, *p);         // p = 0x7ffeefbff4bc, *p = 10
    
    return 0;
}

二.指针变量
1、指针变量的概念:
变量的指针就是变量的地址,存放变量地址的变量是指针变量。

2、定义一个指针变量:
一般形式:数据类型说明符 *指针变量名;(int *p;)

int main(void)
{
	//数据类型说明符 * 变量名;

	int *p;
	//p ----> int 声明了一个指针变量p,p用来指向Int类型的变量。
	float *p1;
	//p1--------->float 声明了一个指针变量p1, p1用来指向float 类型的变量。
	double *p2;
	//p2--------->double 声明了一个指针变量p2, p2用来指向double 类型的变量。
	char *p3;
	//p3--------->char 声明了一个指针变量p3, p3用来指向char 类型的变量。
	long *p4;
	//p4--------->long 声明了一个指针变量p4, p4用来指向long 类型的变量。

	return 0;
}
[注]: 
1、"*"是一个说明符,用来说明这个变量是个指针变量,是不能省略的,但它不属于变量名的一部分
2、前面的类型标识符表示指针变量所指向的变量的类型,而且只能指向这种类型的变量
3、指针变量同普通变量一样,使用之前不仅要定义说明,而且必须赋予具体的值。未经赋值的指针变量不能使用,否则将造成系统混乱,甚至死机。指针变量的赋值只能赋予地址,决不能赋予任何其它数据,否则将引起错误。

3、指针变量的初始化
1.先定义后初始化

// 先定义int类型的变量a
2 int a = 10;
3
4 // 定义一个指针变量p
5 int *p;
6 
7 // 将变量a的地址赋值给指针变量p,所以指针变量p指向变量a
8 p = &a;

2.在定义的同时初始化

// 先定义int类型的变量a
int a = 10;

// 定义一个指针变量p
// 并将变量a的地址赋值给指针变量p,所以指针变量p指向变量a
int *p = &a;

复制代码
[注意]: 指针变量使用前,一定要先赋值,未被赋值的指针,是野指针。野指针可能指向随机的位置。

4、如何避免野指针的出现?

    int *p = NULL;
    int a;
    p = &a;
    if (p != NULL)
    {
        *p = 100;
        printf("*p = %d\n", *p);//*p = 100
    }
/**NULL指针】:空指针,大多数编译器NULL == 0NULL指针所指向的区域,既不能写也不能读。
 NULL指针的使用场合:
	1)可以赋值给任意指针,比如指针初始化,赋值给释放内存后的指针。
					
	2)可以和任意类型的指针进行比较,判断是否是有效的指针。
	 if (指针 != NULL), if (指针 == NULL)
					
   3)可以作为返回指针函数的返回值。
**/

三、指针运算符
一般形式:* 运算符 一般形式(*p)
作用:访问指针变量所指向的存储区域。另外,指针变量和一般变量一样,存放在它们之中的值是可以改变的,也就是说可以改变它们的指向。简单来说就是取值和修改值。

int main(int argc, const char * argv[]) {
    
    char a = 10;
   
    // 指针变量p指向变量a
    char *p = &a;
    //访问指针变量所指向的存储区域
    printf("*p = %d\n", *p);//*p = 10
    
    // 通过指针变量p间接修改变量a的值
    *p = 9;
    printf("修改后,a的值:%d\n", a);//修改后,a的值:9
    
    return 0;
}

四.指针变量作为函数参数
先来看一段代码

void swap(int x, int y);
void swap1(int *x, int *y);

#include <stdio.h>

int main(int argc, const char * argv[]) {
    
    int a = 10;
    int b = 18;
    
    swap(a, b);
    printf("a = %d, b = %d\n", a, b);//a = 10, b = 18
    
    swap1(&a, &b);//&a--->x, &b--->y
    printf("a = %d, b = %d\n", a, b);//a = 18, b = 10
    return 0;
}
void swap(int x, int y)
{
    printf("1,x = %d, y = %d\n", x, y);//x = 10, y = 18

    int temp = x;
    x  = y;
    y = temp;

    printf("2.x = %d, y = %d\n", x, y);//x = 18, y = 10
}

void swap1(int *x, int *y)
{
    printf("1.*x = %d, *y = %d\n", *x, *y);//*x = 10, *y = 18

    int temp = *x;
    *x = *y;
    *y = temp;
    printf("2.*x = %d, *y = %d\n", *x, *y);//*x = 18, *y = 10
}

从输出结果可以看到,虽然x和y的值被交换了,但是变量a和b的值根本就没有换过来。因为基本数据类型作为函数实参时,只是纯粹地将值传递给形参,形参的改变并不影响实参。如果需要形参改变实参,那么需要进行指针传递。

五、关于指针的疑问
刚学完指针,都可能有一大堆的疑惑,这里我列出几个常见的疑惑吧。
1.一个指针变量占用多少个字节的内存空间?占用的空间是否会跟随所指向变量的类型而改变?

在同一环境下,一个指针变量所占用的内存空间是固定的。比如,在16位环境下,任何一个指针变量都只占用2个字节,并不会随所指向变量的类型而改变。

2.既然每个指针变量所占用的内存空间是一样的,而且存储的都是地址,为何指针变量还要分类型?而且只能指向一种类型的变量?比如指向int类型的指针、指向char类型的指针。

其实,我觉得这个问题跟"数组为什么要分类型"是一样的。

  • 看下面的代码,利用指针p读取变量c的值
1 int i = 2;
2 char c = 1;
3 
4 // 定义一个指向char类型的指针
5 char *p = &c;
6 
7 // 取出
8 printf("%d", *p);

这个输出结果应该难不倒大家:,是可以成功读取的。

  • 如果我改一下第5行的代码,用一个本应该指向int类型变量的指针p,指向char类型的变量c

int *p = &c;

我们再来看一下输出:,c的原值是1,现在取出来却是513,怎么回事呢?这个要根据内存来分析

根据变量的定义顺序,这些变量在内存中大致如下图排布:

其中,指针变量p和int类型变量i各占2个字节,char类型的c占一个字节,p指向c,因此p值就是c的地址

1> 最初的时候,我们用char p指向变量c。当利用p来获取变量c的值时,由于指针p知道变量c是char类型的,所以会从ffc3这个地址开始读取1个字节的数据:0000 0001,转为10进制就是1

2> 后来,我们用int p指向变量c。当利用p获取变量c的值时,由于指针p认为变量c是int类型的,所以会从ffc3这个地址开始读取2个字节的数据:0000 0010 0000 0001,转为10进制就是513

可见,给指针分类是多么重要的一件事,而且一种指针最好只指向一种类型的变量,那是最安全的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值