指针深入解析(C语言基础)带你走进指针,了解指针

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: 指针深入解析(C语言基础)带你走进指针,了解指针

内存和地址


 CPU(中央处理器)在处理数据的时候,中央的数据在内存中读取,处理后的数据也会放回内存中。


 内存会被划分为一个个单元格,每个内存单元的大小取一个字节。每个字节可以放8个比特位,每个内存单元也有一个编号,有了这个编号,CPU可以迅速找到一个内存空间。C语言中把这个编号也叫地址

C语言中给地址起了一个名字叫指针

指针变量

1.和地址

在C语言中创建变量就是向内存申请空间我们已经知道啦,比如,创建整型变量就是向内存申请4个字节,每一个字节都有地址,

2.和解引用操作符

 我们通过取地址操作符拿到是一个地址的数值,这个数值有时候需要存储下来,方便后期使用,所以我们这个放在  指针变量  中。

#include<stdio.h>
int main()
{
  int a = 0;
  int* pa = &a;
  return 0;
}

这里出现的Int *,*就是代表这个是指针变量。

 我们拿到了指针就可以找到指针指向的对象,需要用到一个操作符叫解引用操作符----*

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

这里就改变了a的值。

指针变量的大小

 32位平台下地址就是32个bit,指针变量的大小的4个字节

 6位平4台下地址就是64个bit,指针变量的大小的8个字节

并且指针变量的大小与类型是无关的,管他什么整型,浮点型,在相同的平台下都是一样的。

指针变量类型的意义

 指针的类型决定了对指针解引用的时候有多大的权限,比如char类型只能1个字节,而int类型可以4个字节。

void*指针

 可以理解为无具体类型的指针,但是不可以进行指针的+-运算和解引用运算。

const修饰指针

 变量是可以被修改的,如果我们需要不可以被修改,那我们需要用到const,

对于 int*pa=&a;

    const 放在*左边,修饰的是指针指向的内容,保证指针指向的内容不能通过指针来改变,但是指针变量本身的内容可以改、

    const放在*右边,修饰是指针变量本身

const char *ptr="hello ", 本质就是把hello的首元素存到ptr中

指针运算

1.指针+-整数

2.指针-指针

3.指针的关系运算

  1.指针+-整数:数组在内存中是连续存放, 所以我们只要知道第一个元素的地址,就可以找到所有元素。

  2.指针-指针:

#include<stdio.h>
int strlen(char* s)
{
  char* p = s;
  while (*p != '\0')
  {
    p++;
  }
  return p - s;
}
int main()
{
  printf("%d\n", strlen("abc"));
  return 0;
}

野指针

 野指针就是指针指向的位置是不可知的。

原因:没有初始化,指针越界访问,指针指向的空间释放(就是可能创建的指针变量被销毁了)

数组名的理解

1.数组名就是数组首元素的地址,如下图

注意:

sizeof(数组名):计算的是整个数组的大小,单位是字节

&数组名:表示的是取出的是整个数组的地址

使用指针访问数组

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
  int arr[10];
  int sz = sizeof(arr) / sizeof(arr[0]);
  int* p = arr;//首元素
  int i = 0;
  for (i = 0; i < sz; i++)
  {
    scanf("%d", p+i);
  }
  for (i = 0; i < sz; i++)
  {
    printf("%d ", *(p + i));
  }
  return 0;
}

一维数组传参的本质

本质来说,一维数组传参的本质传的是数组的首元素的地址

并且一维数组传参形参部分可以写成数组,也可以写成指针

#include<stdio.h>
void test(int arr[])
{
  printf("%d\n", sizeof(arr));
}
void test(int* arr)
 
{
  printf("%d\n", sizeof(arr));
 
}
 
int main()
{
  int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
  test(arr);
  return 0;
}

二级指针

二级指针就是存放一级指针的地址

因为你的一级指针存放地址的时候,也需要向内存申请一块空间,它自己本身是需要地址

#include <stdio.h>
int main()
{
  int a = 0;
  int* p = &a;
  int** pa = &p;
  return 0;
 
}

指针数组

整型数组:存放整型的数组

字符数组:存放字符的数组

指针数组:存放指针的数组,也就是说,这个数组里面的每一个元素都是指针

指针数组模拟二维数组

int main()
{
  int arr1[] = { 1,2,3,4,5 };
  int arr2 [] = {2,3,4,5,6};
  int arr3[] = { 3,4,5,6,7 };
  //数组名是元素首元素的地址
  int* p[3] = { arr1,arr2,arr3 };
  int i = 0;
  int j = 0;
  for (i = 0; i < 3; i++)
  {
    for (j = 0; j < 5; j++)
    {
      printf("%d ", p[i][j]);
    }
    printf("\n");
  }
  return 0;
}

数组指针变量

定义

整型指针变量: int*pint,存放的是整型变量的地址,指向的是整型数据的指针

浮点指针变量:float*pint,存放的是浮点型变量的地址,指向的是浮点型数据的指针

数组指针变量:int(*p)[ ] 存放的是数组的地址,能够指向数组的指针变量

数组指针变量初始化

#include<stdio.h>
int main()
{
  int arr[10] = { 0 };
  int(*p)[10] = &arr;
  return 0;
}

&arr与*p的类型是完全一致的

二维数组传参的本质

  二维数组的首元素就是第一行,是一个一维数组

在本质上传的也是地址,传递的就是这个一维数组的地址

函数指针变量

 函数是有地址的,函数名就是函数的地址,也可以用   &函数名   来表示

int       (*p)      (int x, int y)........p指向函数的参数类型和个数的交代

.               .

.               .

.               .

.            函数指针变量名字

.

p指向函数返回的类型

函数指针变量的使用

#include<stdio.h>
int Add(int x, int y)
{
  return x + y;
}
int main()
{
  int (*p)(int, int) = Add;
  printf("%d\n", (*p)(2, 3));
  printf("%d\n", p(2, 3));
 
  return 0;
}

typeof关键字

可以将复杂的类型简单化

比如,你觉得unsigned int 写起来不方便

可以改成 typeof unsigned int uint;

之后你使用就可以直接使用 unit

指针类型也可以改名字

typeof int * ptr-t;

回调函数

 回调函数就是通过函数指针调用的函数

 如果你把函数的指针作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数,被调用的函数就是回调函数

回调前

#include<stdio.h>
int add(int a, int b)
{
  return a + b;
}
int sub(int a, int b)
{
  return a - b;
}
int mul(int a, int b)
{
  return a * b;
}
int div(int a, int b)
{
  return a / b;
}
int main()
{
  int x, y;
  int input = 1;
  int ret = 0;
  do
  {
    printf("******************************\n");
    printf("****  1. add     2. sub   ****\n");
    printf("****  3. mul     4. div   ****\n");
    printf("****  0. exit             ****\n");
    printf("******************************\n");
    scanf("%d", &input);
    switch (input)
    {
    case 1:
      printf("输入操作数:");
      scanf("%d%d", &x, &y);
      ret = add(x, y);
      printf("ret=%d\n", ret);
      break;
    case 2:
      printf("输入操作数:");
      scanf("%d%d", &x, &y);
      ret = sub(x, y);
      printf("ret=%d\n", ret);
      break;
    case 3:
      printf("输入操作数:");
      scanf("%d%d", &x, &y);
      ret = mul(x, y);
      printf("ret=%d\n", ret);
      break;
    case 4:
      printf("输入操作数:");
      scanf("%d%d", &x, &y);
      ret = div(x, y);
      printf("ret=%d\n", ret);
      break;
    case 0:
      break;
    }
 
  } while (input);
  return 0;
}

回调后

#include<stdio.h>
int add(int a, int b)
{
  return a + b;
}
int sub(int a, int b)
{
  return a - b;
}
int mul(int a, int b)
{
  return a * b;
}
int div(int a, int b)
{
  return a / b;
}
void calc(int(*pf)(int, int))
{
  int ret = 0;
  int x, y;
  pintf("输入操作数:");
  scanf("%d%d", &x, &y);
  ret = pf(x, y);
  printf("ret=%d\n", ret);
 
}
int main()
{
  int x, y;
  int input = 1;
  int ret = 0;
  do
  {
    printf("******************************\n");
    printf("****  1. add     2. sub   ****\n");
    printf("****  3. mul     4. div   ****\n");
    printf("****  0. exit             ****\n");
    printf("******************************\n");
    scanf("%d", &input);
    switch (input)
    {
    case 1:
      calc(add);
      break;
    case 2:
      calc(sub);
      break;
    case 3:
      calc(mul);
      break;
    case 4:
      calc(div);
      break;
    case 0:
      break;
    }
 
  } while (input);
  return 0;
}

qsort函数使用举例

 函数实现排序

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
int int_cmp(const void* p1, const void* p2)
{
  return (*(int*)p1 - *(int*)p2);
}
 
int main()
{
  int arr[] = { 1,3,5,6,8,2,4 };
  int i = 0;
  qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof(int), int_cmp);
  for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
  {
    printf("%d ", arr[i]);
  }
  printf("\n");
 
  return 0;
}

非常感谢您的阅读,多多关注呀,后面我也会尽心尽力为大家带来优质好文的


相关文章
|
27天前
|
C语言
【c语言】指针就该这么学(1)
本文详细介绍了C语言中的指针概念及其基本操作。首先通过生活中的例子解释了指针的概念,即内存地址。接着,文章逐步讲解了指针变量的定义、取地址操作符`&`、解引用操作符`*`、指针变量的大小以及不同类型的指针变量的意义。此外,还介绍了`const`修饰符在指针中的应用,指针的运算(包括指针加减整数、指针相减和指针的大小比较),以及野指针的概念和如何规避野指针。最后,通过具体的代码示例帮助读者更好地理解和掌握指针的使用方法。
45 0
|
25天前
|
C语言
【c语言】指针就该这么学(3)
本文介绍了C语言中的函数指针、typedef关键字及函数指针数组的概念与应用。首先讲解了函数指针的创建与使用,接着通过typedef简化复杂类型定义,最后探讨了函数指针数组及其在转移表中的应用,通过实例展示了如何利用这些特性实现更简洁高效的代码。
15 2
|
26天前
|
C语言
如何避免 C 语言中的野指针问题?
在C语言中,野指针是指向未知内存地址的指针,可能引发程序崩溃或数据损坏。避免野指针的方法包括:初始化指针为NULL、使用完毕后将指针置为NULL、检查指针是否为空以及合理管理动态分配的内存。
|
26天前
|
C语言
C语言:哪些情况下会出现野指针
C语言中,野指针是指指向未知地址的指针,通常由以下情况产生:1) 指针被声明但未初始化;2) 指针指向的内存已被释放或重新分配;3) 指针指向局部变量,而该变量已超出作用域。使用野指针可能导致程序崩溃或不可预测的行为。
|
1月前
|
存储 C语言
C语言32位或64位平台下指针的大小
在32位平台上,C语言中指针的大小通常为4字节;而在64位平台上,指针的大小通常为8字节。这反映了不同平台对内存地址空间的不同处理方式。
|
1月前
|
存储 算法 C语言
C语言:什么是指针数组,它有什么用
指针数组是C语言中一种特殊的数据结构,每个元素都是一个指针。它用于存储多个内存地址,方便对多个变量或数组进行操作,常用于字符串处理、动态内存分配等场景。
|
1月前
|
存储 C语言
C语言指针与指针变量的区别指针
指针是C语言中的重要概念,用于存储内存地址。指针变量是一种特殊的变量,用于存放其他变量的内存地址,通过指针可以间接访问和修改该变量的值。指针与指针变量的主要区别在于:指针是一个泛指的概念,而指针变量是具体的实现形式。
|
1月前
|
C语言
C语言指针(3)
C语言指针(3)
11 1
|
1月前
|
C语言
C语言指针(2)
C语言指针(2)
13 1
|
1月前
|
存储 搜索推荐 C语言
深入C语言指针,使代码更加灵活(二)
深入C语言指针,使代码更加灵活(二)

推荐镜像

更多