【C语言初阶】带你轻松掌握指针基础知识完结篇——野指针,指针运算,指针和数组,二级指针

简介: 【C语言初阶】带你轻松掌握指针基础知识完结篇——野指针,指针运算,指针和数组,二级指针

一. 野指针

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

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. 指针指向的空间释放
  • 这里放在指针进阶篇中动态内存开辟的时候讲解

2. 如何规避野指针

1. 指针初始化
2. 小心指针越界
3. 指针指向空间释放,及时置NULL
4. 避免返回局部变量的地址
5. 指针使用之前检查有效性

第三种情况的使用例子

#include <stdio.h>
int main()
{
  int *p = NULL;//在使用前先把指针置空防止为释放指针之前指向的空间
  //....
  int a = 10;
  p = &a;
  if(p != NULL)
 {
    *p = 20;
 }
  return 0;
  }

二. 指针运算

1.指针± 整数

#define m 5
float values[m];
float* vp;
//指针+-整数;指针的关系运算
for (vp = &values[0]; vp < &values[m];)
{
    *vp++ = 0;//把values数组中每个元素都初始化为0,这里指针++表示地址后移
}

2.指针-指针

//计算字符串的长度
int my_strlen(char *s)
{
   char *p = s;
   while(*p != '\0' )
       p++;
   return p-s;//当p中读取到\0时说明该字符串总长度为此时的地址p-首元素地址s
   }

3.指针的关系运算

for(vp = &values[m]; vp > &values[0];)
{
  *--vp = 0;//由于是前置--,最后会与第一元素之前的元素比较
}
  • 上面这段代码有比较明显的缺点,我们来简化一下。
for(vp = &values[m-1]; vp >= &values[0];vp--)
{
  *vp = 0;
}




  • 实际在绝大部分的编译器上是可以顺利完成任务的,然而我们还是应该避免这样写,因为标准并不保证它可行。
  • 标准规定:
  • 允许指向数组元素的指针与指向数组最后一个元素后面的那个内存位置的指针比较,但是不允许与指向第一个元素之前的那个内存位置的指针进行比较。

三. 指针和数组


  • 我们先通过一个例子来建立一下数组与指针之间的联系
#include <stdio.h>
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,0};
  printf("%p\n", arr);//打印地址
  printf("%p\n", &arr[0]);
  return 0;

900cf98154ff4ae4813a1cc8e6e1696d.png

int arr[10] = {1,2,3,4,5,6,7,8,9,0};
int *p = arr;//p存放的是数组首元素的地址
  • 既然可以把数组名当成地址存放到一个指针中,我们就可以使用指针来访问一个数组。
  • 示例如下:
#include <stdio.h>
int main()
{
  int arr[] = {1,2,3,4,5,6,7,8,9,0};
  int *p = arr; //指针存放数组首元素的地址
  int sz = sizeof(arr)/sizeof(arr[0]);
  int i;
  for(i=0; i<sz; i++)
 {
    printf("&arr[%d] = %p  <====> p+%d = %p\n", i, &arr[i], i, p+i);
    }
    return 0;
 }

21f6158a159742f4917e24a70082c7e2.png

  • 所以 p+i 其实计算的是数组 arr 下标为i的地址。
    那我们就可以直接通过指针来访问数组。
  • 示例如下:


int main()
{
int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
int *p = arr; //指针存放数组首元素的地址
int sz = sizeof(arr) / sizeof(arr[0]);
int i = 0;
for (i = 0; i<sz; i++)
{
printf("%d ", *(p + i));
}
return 0;
}

四.二级指针

  • 指针变量也是变量,是变量就有地址,那指针变量的地址存放在哪里?
  • 答案不言而喻—— 二级指针 。
int main()
{
    int a = 10;
    int* p = &a;
    int** pa = &p;
    printf("%d\n", a);
    printf("%d\n", *p);
    printf("%d\n", **pa);
    return 0;
}

bd93e3bb8cbc4772b9fccfc536a3d5f2.png

  • 我们可以看出来三者的值是相同的!!
  • 对于二级指针的运算有:
//*pa通过对pa中的地址进行解引用,这样找到的是p ,*pa 其实访问的就是p .
int b = 20;
*pa = &b;//等价于 p = &b;
//**pa 先通过* pa 找到 p, 然后对 p 进行解引用操作:*p ,那找到的是 a .
**pa = 30;
//等价于*p = 30;
//等价于a = 30;

五. 指针数组

  • 指针数组是指针还是数组?
  • 是数组。是存放指针的数组。

数组我们已经知道整形数组,字符数组。

int arr1[5];
char arr2[6];
  • 那指针数组是怎样的?
int* arr3[5];//是什么?


82be226d2eec4a7c867061f3d5b1859c.png

  • 还有一种指针类型叫做数组指针,是指针,这两种情况我都会放在指针进阶篇中介绍。

总结


  • 今天的内容到这里就全部结束了,我们今天把指针基础部分全部介绍完了,其中主要包括野指针的定义以及如何避免,指针运算的几种形式以及指针与数组的关系和二级指针,希望大家把博客中的代码都弄懂哦!
  • 好了,如果你有任何疑问欢迎在评论区或者私信我提出,大家下次再见啦!

新人博主创作不易,如果感觉文章内容对你有所帮助的话不妨三连一下这个新人博主再走呗。你们的支持就是我更新的动力!!!

**(可莉请求你们三连支持一下博主!!!点击下方评论点赞收藏帮帮可莉吧)**



目录
相关文章
|
6天前
|
存储 C语言 C++
【C语言数组】
【C语言数组】
|
6天前
|
算法 C语言
C语言------数组
这篇文章是关于C语言数组的实训,包括一维数组、二维数组和字符数组的定义、赋值、输入、输出方法,并通过实例代码演示了数组的使用和一些基本算法,如冒泡排序。
C语言------数组
|
18天前
|
存储 编译器 程序员
七:《初学C语言》— 数组
【8月更文挑战第2天】本篇文章详细讲解了一维数组和二维数组的创建、使用和初始化及如何使用sizeof()计算数组中的元素个数。并附带了多个教学源码及代码练习
34 1
七:《初学C语言》— 数组
|
4天前
|
算法 Java
双指针在数组遍历中的应用
文章深入探讨了双指针技术在数组遍历中的应用,通过实战例子详细解释了快慢指针和首尾指针的不同用法,并提供了解决LeetCode相关问题的Java代码实现。
|
7天前
|
存储 编译器 C语言
C语言——数组
C语言——数组
|
12天前
|
存储 C语言
C语言(数组)
C语言(数组)
23 6
|
1天前
|
存储 编译器 程序员
【C语言篇】从零带你全面了解数组(超详细)
有时候,数组在创建的时候,我们需要给定⼀些初始值,这种就称为初始化。
|
27天前
|
运维
开发与运维数组问题之指针的加减法意义如何解决
开发与运维数组问题之指针的加减法意义如何解决
31 7
|
27天前
|
C++ 索引 运维
开发与运维数组问题之在C++中数组名和指针是等价如何解决
开发与运维数组问题之在C++中数组名和指针是等价如何解决
18 6
|
27天前
|
存储 C++ 运维
开发与运维数组问题之指针的定义语法如何解决
开发与运维数组问题之指针的定义语法如何解决
23 6