C语言指针(详细理解指针、野指针、指针和数组)


前言

指针是C语言学习阶段的一个难点,本文将介绍C语言中的指针,什么是指针,指针类型以及指针运算等相关内容。


一、指针

1.什么是指针

对指针可以做出以下理解: 指针是个变量,用来存放内存单元的地址
即指针是一种保存变量地址的变量。

整个过程对应到C代码中如下:

#include <stdio.h>
int main()
{
    
    
	//定义int 类型变量 a,并初始化值为:10
 	int a = 10;
 	int *p = &a; //(1)对变量a,使用&符号取出它的地址
  	             //(2)在将a的地址存放在p变量中
 	return 0;
}

对应图解如下:
在这里插入图片描述

2.指针类型

指针类型:指针声明语句里除指针名之外的部分就是这个指针的类型。

有如下代码:

int *p;           //指针的类型是int*
char *p           //指针的类型是char*
int *arr[10]      //指针的类型是int* [10]
int (*arr)[10]    //指针的类型是int (* )[10]
int **p;          //指针的类型是int ** 

可以看到,指针的类型有很多种,那么不同指针类型有什么作用呢?

3.指针类型的作用

先看以下实例:

#include <stdio.h>
int main()
{
    
     
	
	int n = 10;
	char* p1 = (char*)&n; //n为整型数据,将其强制转换为(char*)
	int* p2 = &n;

	printf("%p\n", &n);
	printf("%p\n", p1);
	printf("%p\n", p1 + 1);
	printf("%p\n", p2);
	printf("%p\n", p2 + 1);
	return  0;
}

对应图解如下:
在这里插入图片描述
可以得出结论:指针的类型决定了指针向前或者向后走一步有多大(距离)

补充 前面已经提到内存其实就是一组有序字节组成的数组。其存储数据最小单位是字节

在这里插入图片描述

4.指针解引用

学习指针离不开 * 符号。

指针比普通变量的声明多了一个一元运算符 “ * ”

int a=10;
int * p=&n ;

“*” :间接引用(间接寻址)运算符。 当它作用于指针时,将访问指针所指向的对象。

例:

#include <stdio.h>
int main()
{
    
     
	
	int n = 10;
	int* p = &n;
	printf("%d", *p);
	return  0;
}

代码运行结果如下:
在这里插入图片描述

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


二、野指针

1.指针声明

声明一个指针变量:

//(1)直接声明
int * p; 

//(2)声明并初始化
int a=10;
int *p=&a;  

值得注意的是:第一种方式程序会直接报错。

指针在声明时并不会自动分配任何内存。在对指针进行间接访问之前,指针必须进行初始化。 否则指针随机指向。

2.什么是野指针?

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

3.产生野指针的原因

(1) 指针未初始化
例:

#include <stdio.h>
int main()
{
    
     
     int *p;//局部变量指针未初始化,默认为随机值
    printf("%d",*p);
    return 0;
 }

运行结果出错:
在这里插入图片描述
(2)指针越界访问
例:

#include <stdio.h>
int main()
{
    
    
    int a[10] = {
    
    0};
    int *p = a;//数组名即为该数组首元素的地址
    for(int i=0; i<=11; i++)
   {
    
    
        //当指针指向的范围超出数组a的范围时,p就是野指针
        *(p++) = i;
   }
    return 0;
}

程序运行出错!
在这里插入图片描述
因此在使用指针时要注意:a.指针初始化 b.注意指针越界 c. 指针使用之前检查有效性

例如:

#include <stdio.h>
int main()
{
    
    
    int a = 10;
    p = &a;
    if(p != NULL)  //检查有效性
   {
    
    
        *p = 20;
   }
    return 0;
}

三、指针和数组

1.数组名

我们先来看以下这个例子:

#include <stdio.h>
int main()
{
    
    
 	int a[10] = {
    
    1,2,3,4,5};
    printf("%p\n", a);
    printf("%p\n", &a[0]);
    return 0;
}

图解如下:
在这里插入图片描述
结论:数组名表示的是数组首元素的地址。

2.实例代码

因此:以下代码成立:

int a[5] = {
    
    1,2,3,4,5};
int* p=a;

实例如下:

#include <stdio.h>
int main()
{
    
    
    int arr[5] = {
    
     1,2,3,4,5 };
    int* p = arr; //指针存放数组首元素的地址
    for (int i = 0; i < 5; i++)
    {
    
    
        printf("对数组中的第 %d 元素取地址:&arr[%d] = %p    p+%d = %p\n",i, i, &arr[i], i, p + i);
    }
    return 0;
}

运行结果:
在这里插入图片描述
以上代码可以写成如下形式:

#include <stdio.h>
int main()
{
    
    
    int arr[5] = {
    
     1,2,3,4,5 };
    int* p = arr;
    for (int i = 0; i < 5; i++)
    {
    
    
        printf("%d ",arr[i]);
    }
    printf("\n");
    for (int i = 0; i < 5; i++)
    {
    
    
       printf("%d ", *(p + i));
    }
    return 0;
}

运行结果如下:
在这里插入图片描述


总结

提示:以上就是本文的全部内容。

猜你喜欢

转载自blog.csdn.net/m0_53689542/article/details/123302431