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

简介: 指针深入解析(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;
}

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


相关文章
|
5天前
|
安全 C语言
【C语言】如何规避野指针
【C语言】如何规避野指针
22 0
|
5天前
|
C语言
c语言指针总结
c语言指针总结
15 1
|
3天前
|
存储 安全 编译器
C语言详解指针(指针海洋的探索,将传值与传址刻在心里)
C语言详解指针(指针海洋的探索,将传值与传址刻在心里)
8 0
|
5天前
|
C语言
C语言(指针详解)重点笔记:指针易错点,都是精华
C语言(指针详解)重点笔记:指针易错点,都是精华
12 0
|
5天前
|
存储 C语言
C语言指针讲解(适用于初学者)
C语言指针讲解(适用于初学者)
6 0
|
5天前
|
存储 程序员 C语言
【C 言专栏】C 语言指针的深度解析
【4月更文挑战第30天】C 语言中的指针是程序设计的关键,它如同一把钥匙,提供直接内存操作的途径。指针是存储其他变量地址的变量,通过声明如`int *ptr`来使用。它们在动态内存分配、函数参数传递及数组操作中发挥重要作用。然而,误用指针可能导致错误,如空指针引用和内存泄漏。理解指针的运算、与数组和函数的关系,以及在结构体中的应用,是成为熟练 C 语言程序员的必经之路。虽然挑战重重,但掌握指针将增强编程效率和灵活性。不断实践和学习,我们将驾驭指针,探索更广阔的编程世界。
|
5天前
|
算法 搜索推荐 程序员
C语言中的函数指针和回调函数
C语言中的函数指针和回调函数
12 2
|
5天前
|
存储 编译器 C语言
【C语言】初步解决指针疑惑
【C语言】初步解决指针疑惑
8 0
|
3天前
|
C语言
C语言—内存函数的实现和模拟实现(内存函数的丝绸之路)
C语言—内存函数的实现和模拟实现(内存函数的丝绸之路)
17 0
|
3天前
|
C语言
C语言—字符函数与字符串函数(字符问题变简单的关键之技)
C语言—字符函数与字符串函数(字符问题变简单的关键之技)
5 0

推荐镜像

更多
http://www.vxiaotou.com