c_010 C语言 指针

1. 指针是什么?

指针是什么?
   指针理解的2个要点:
       1. 指针是内存中一个最小单元的编号,也就是地址
       2. 平时口语中说的指针,通常指的是指针变量,是用来存放内存地址的变量.

总结:指针就是地址,口语中说的指针通常指的是指针变量

  • 我们可以这样理解:
    在这里插入图片描述

指针变量
 我们可以通过&(取地址操作符)取出变量的内存真实地址,把地址可以存放到一个变量中(说白了还是个变量),这个变量就是指针变量。

#include <stdio.h>
int main()
{
 int a = 10;//在内存中开辟一块空间
 int *p = &a;//这里我们对变量a,取出它的地址,可以使用&操作符。(int *p和int* p的写法都可以)
    //a变量占用4个字节的空间,这里是将a的4个字节的第一个字节的地址存放在p变量
中,p就是一个之指针变量。
 return 0;
}

总结:指针是地址;指针变量,用来存放地址的变量。(存放在指针变量中的值都被当成地址处理)。

  • 那指针的大小是多少呢?

 经过计算机设计者仔细的计算和权衡发现,一个字节给一个对应的地址是比较合适的。
 对于32位的机器,假设有32根地址线,那么假设每根地址线在寻址的时候产生高电平(高电压)和低电平(低电压)就是(1或者0);
那么32根地址线产生的地址就会是:
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000001

11111111 11111111 11111111 11111111
这里就有2的32次方个地址。

每个地址标识一个字节,那我们就可以给 (2^32Byte == 2^32/1024KB ==
232/1024/1024MB==232/1024/1024/1024GB == 4GB) 4G的空间进行编址。

  • 这里我们就明白:
       在32位的机器上**,地址是32个0或者1组成二进制序列,那地址就得用4个字节的空间来存储**,所以一个指针变量的大小就应该是4个字节
      那如果在64位机器上,如果有64个地址线,那一个指针变量的大小是8个字节,才能存放一个地址。

2. 指针和指针类型

 我们都知道,变量有不同的类型,整形,浮点型等。那指针有没有类型呢?
准确的说:有的。

char  *pc = NULL;
int   *pi = NULL;
short *ps = NULL;
long  *pl = NULL;
float *pf = NULL;
double *pd = NULL;

这里可以看到,指针的定义方式是: type + *
其实:
char* 类型的指针是为了存放 char 类型变量的地址。
short* 类型的指针是为了存放 short 类型变量的地址。
int* 类型的指针是为了存放 int 类型变量的地址。

2.1 那指针类型的意义是什么?

  • 指针±整数
    在这里插入图片描述
    可以看到 :char* 类型指针加1 ,地址值变化为1(即1个字节);int* 类型指针加1 ,地址值变化为4(即4个字节);

总结:指针的类型决定了指针向前或者向后走一步有多大(距离)

  • 指针的解引用

//演示实例
#include <stdio.h>
int main()
{
	int n = 0x11223344; // 调试可以发现内存中的值为 44 33 22 11 
	
	int* pi = &n;  // 取地址放入int*  类型的指针变量
	char* pc = (char*)&n;  // 强制类型转换为char*类型的指针变量
	
	*pc = 0; //调试可以发现内存中的值改变为 00 33 22 11 
	*pi = 0; //调试可以发现内存中的值改变为 00 00 00 00  
	return 0;
}

总结:指针的类型决定了,对指针解引用的时候有多大的权限(能操作几个字节)。
比如: char* 的指针解引用就只能访问一个字节,而 int* 的指针的解引用就能访问四个字节。

3. 野指针

概念: 野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)

3.1 野指针成因

    1. 指针未初始化
    #include <stdio.h>
    int main()
    { 
     int *p;//局部变量指针未初始化,默认为随机值
        *p = 20;
     return 0;
    }
    
    1. 指针越界访问
    #include <stdio.h>
    int main()
    {
        int arr[10] = {0};
        int *p = arr;
        int i = 0;
        for(i=0; i<=11; i++)
       {
            //当指针指向的范围超出数组arr的范围时,p就是野指针
            *(p++) = i;
       }
        return 0;
    }
    
    1. 指针指向的空间释放
      Todo 后续博客阐述原因

3.2 如何规避野指针

    1. 指针初始化
    1. 小心指针越界
    1. 指针指向空间释放即使置NULL
    1. 避免返回局部变量的地址
    #include <stdio.h>
    
    int* test()
    {
    	int a = 10;
    	return &a; // 返回局部变量地址
    }
    
    int main() 
    {
    	// 返回局部变量地址,但是局部变量出了test方法的代码块({}范围内)即销毁。即该内存已经不属于我们的程序了
    	//所以p指针变量指向了不属于我们的内存,这是不允许的
    	int* p = test(); 
    
    	printf("%d\n", *p);
    	return 0;
    }
    
    1. 指针使用之前检查有效性
    #include <stdio.h>
    int main()
    {
        int *p = NULL;
        //....
        int a = 10;
        p = &a;
        if(p != NULL)
       {
            *p = 20;
       }
        return 0;
    }
    

4. 指针运算

4.1 指针±整数

指针±整数的表示含义,指针前后移动一次(指针j加减1),调整的大小为sizeof(指针去掉一个*)

int main(){
	float values[N_VALUES];
	float* vp;
	//指针+-整数;指针的关系运算
	for (vp = &values[0]; vp < &values[N_VALUES];)
	{
		*vp++ = 0;
	} 
	// 将values数组的元素全部置为0
	return 0;
}

4.2 指针±指针

  • 指针+指针

    由于指针加指针的值是一个相对于原数组地址相差较大的数值,该数值很有可能超越了我们所定义的数组的右边界,这样获得的地址值将是一个“盲值”,虽然它确实存在,但我们不能对这个地址做任何处理,因为我们无法得知这个位置原先存储的是什么变量,所以我们认为这是个非法的

-2、指针-指针

只有当两个指针都指向同一个数组中的元素时,才允许从一个指针减去连一个指针。两个指针相减的结果类型是ptrdiff_t,它是一种有符号整数类型。减法运算的值是两个指针在内存中的距离(该距离以间隔的单元格数为单位,而不是以字节为单位)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值