C语言指针基础知识

指针概念

  1. 变量的访问方式:直接访问,直接使用变量名进行访问;间接访问,通过指针来实现。
  2. 指针:如果一个变量专门用来存放内存地址,则称它为指针变量,简称地址。
  3. 指针格式:数据类型 *指针变量名 [=初始化地址值]; 
  4. 取址运算符:&,取出变量的内存地址,格式占位符:%p。
  5. 取值运算符:* ,取出指针指向的内存地址的数据值。也叫解引用。
  // 声明一个int 变量
  int num = 100;
  // 声明一个指针变量
  int *ptr = #
  int  * ptr = #
  int* ptr = #
  // 打印指针的值
  printf("ptr 的值:%p\n", ptr);
  // 打印指针的地址
  printf("ptr 的地址:%p\n", &ptr);
  // 打印指针指向的值
  printf("ptr指向的值:%d\n", *ptr);
  // 打印num 所占空间字节的大小
  printf("num占空间大小:%zu\n", sizeof(num));
  // 打印指针所占内存的大小
  printf("ptr占空间大小:%zu\n", sizeof(ptr));

指针运算

指针加减整数

  1. 指针与整数的加减运算,表示指针所指向的内存地址的移动,加——向后移动,减——向前移动。指针移动多少,与指针指向的数据类型有关,int——4字节,double——8字节,float——1字节。
  // 声明一个数组 数据连续存储
  int arr[5] = {10, 20, 30, 40, 50};
  int *ptr = &arr[0];
  ptr += 3;
  printf("ptr=%d\n", *ptr);
  ptr -= 2;
  printf("ptr=%d\n", *ptr);

指针自增自减

  1. 指针自增自减,本质上就是指针加减整数,自增地址后移,自减地址前移。
  int arr[5] = {10, 20, 30, 40, 50};
  int *ptr = &arr[0];
  // 自增
  ptr++;
  printf("ptr=%d\n", *ptr);
  // 自减
  ptr--;
  printf("ptr=%d\n", *ptr);

同类型指针相减

  1. 相同类型的指针可以进行减法运算,返回它们之间的距离,即间隔多少个数据单位,高位地址减去地位地址,返回真值,低位地址减去高位地址返回的是负值。结果是一个ptrdiff_t类型数据,是一个带符号的整数。格式占位符%td。
  // 相同类型的指针相减 // 返回两个数据存储位置的相差个数
  double a = 2.434;
  double b = 32.55;
  double *ptr1 = &a;
  double *ptr2 = &b;
  int result = ptr1 -ptr2;
  printf("%td\n", result);

指针的比较运算

  1. 指针之间进行比较: < 、>、<=、>=、==等,比较的是各自指向的内存地址的大小,返回值是int类型整数1或0。
  // 指针比较  返回值 1 —— true  0 —— false
  // 比较的是各自指向的内存地址的大小,比较地址大小
  double a = 3.24;
  int num = 10;
  double *ptr = &a;
  int *ptr1 = &num;
  int result = ptr > ptr1;
  printf("%d\n", result);

指针和数组

数组名

  1. 数组名:一般会被隐式的转换位指向数组第一个元素的指针,有一点指针的特性
    1. 使用sizeof运算符,数组名得到的是整个数组的大小,指针得到的是本身的大小;
    2. 数组名不能进行自增、自减运算;
    3. 数组名的指向不可更改。

指针数组

  1. 指针数组:是一个数组,其中每个元素都是指针。
  2. 语法:数据类型   *指针数组名[长度];
// 指针数组  int *ptr[5];
  int a = 10;
  int b = 12;
  int c = 13;
  // 定义一个长度为三的指针数组
  int *ptr[3];
  ptr[0] = &a;
  ptr[1] = &b;
  ptr[2] = &c;
  // 遍历数组
  for (int i = 0; i < 3; i++) {
    printf("指针数组的元素为:%p, 元素指向的值为:%d\n", ptr[i], *ptr[i]);
  }

数组指针

  1. 数组指针:是一个指针,指向一个数组。数组指针指向的是整个数组的地址而不是第一个元素的地址。
  2. 语法:数据类型 (*数组指针名) [长度];
  // 数组指针  是一个指针 int (*ptr)[4];
  int arr[4] = {10, 20, 30, 40};
  // 定义一个数组指针
  int (*ptr)[4] = &arr; // &arr 指向整个数组的地址
  // 二者数值相同
  printf("arr指向的地址:%p\n", arr);
  printf("ptr的地址:%p\n", ptr);
  //  数组的值是第一个元素的地址
  // 数组指针的值是整个数组的地址
  printf("arr + 1指向的地址:%p\n", arr + 1);
  printf("ptr + 1 的地址:%p\n", ptr + 1);
  // 数组指针遍历数组
  for (int i = 0; i < 4; i++) {
    printf("数组指针ptr 的每个元素指向的值为:%d\n", (*ptr)[i]);
  }

数组指针和数组名的区别

  • 指向不同:数组名指向元素的首地址,数组指针指向数组的地址。
  • 类型不同:数组的是arr[4],ptr的类型是int(*)[4];
  • 能否再次赋值:数组名是个常量,是不可改变的,数组指针是可变的,可以指向不同的数组。
  • 初始化:数组名不需要显示初始化,自动指向数组元素的首元素,数组指针需要显示初始化,指定它将指向的数组。
  • 访问元素:数组名访问数组元素不需要解引用,数组指针通常需要解引用才能访问数组元素。

字符指针

  1. 字符指针:指向字符或字符串(字符数组),通常用于处理字符串。
  2. 字符数组名和字符指针表示字符串的区别
    1. 对字符数组只能对各个元素赋值,不能对字符数组名重新赋值。
    2. 字符指针式可变的,允许重新赋值,指向新的字符串。
  char arr[] = "Hello";
  printf("%s\n", arr); // Hello
  // 字符指针
  char *ptr = "World"; 
  printf("%s\n", ptr); // OK
  ptr = "OK";
  arr[1] = 'a';
  printf("%s\n", arr); // Hello
  printf("%s\n", ptr);// OK

指针和函数

传递指针给函数

  1. 传地址或指针给函数;
  2. 传数组给函数——数组名本身代表数组首地址,本质就是传地址。
#include <stdio.h>

void fn(int *);
int main() {
  // 给函数传递指针
  int a = 100;
  printf("a 的地址:%p, a 地址中存储的数据:%d\n", &a, a);
  int *ptr = &a;
  fn(ptr);
  printf("函数运行后a 的地址:%p, a 地址中存储的数据:%d\n", &a, a);
  fn(&a);
  printf("函数运行后a 的地址:%p, a 地址中存储的数据:%d\n", &a, a);
  return 0;
}
void fn(int *p) {
  printf("p地址:%p,p = %d\n", p, *p);
  *p += 1;
  printf("p地址:%p,p = %d\n", p, *p);
}

// 传递数组
#include <stdio.h>
// 返回这个数组的平均数
double avg(double  *arr, int length) {
  double sum = 0;
  for (int i = 0; i < length; i++) {
    sum += arr[i];
  }
  return sum / length;
}
int main() {
  // 给函数传递数组
  double arr[3] = {10, 20, 30};
  int length = sizeof(arr) / sizeof(double);
  double result = avg(arr, length);
  printf("result = %lf\n", result);
  return 0;
}

指针函数——返回指针的函数

  1. 指针函数:函数的返回值是一个指针,本质上是一个函数。
  2. 语法:返回类型 *指针函数名(参数列表);
  3. 返回值:返回值不能指向局部变量,局部变量会在当前代码块结束后释放。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

// 定义一个指针函数返回10哥随机数
int *fn () {
  // 定义一个数组接收
  static int arr[10];
  // 设置随机数种子
  srand(time(NULL));
  for (int i = 0; i  < 10; i++) {
    arr[i] = rand();
  }
  return arr;
}

int main() {
  int *array = fn();
  for (int i = 0; i < 10; i++) {
    printf("arr[%d]= %d\n", i + 1, array[i]);
  }

  return 0;
}

函数指针——指向函数的指针

  1. 函数指针:把函数的这个首地址赋予一个指针变量,通过指针变量就可以找到并调用该函数,这种指针就是函数指针。
  2. 语法:返回类型  (* 函数指针名)(参数列表);
  3. ()的优先级高于 *, 第一个括号不能省略。
#include <stdio.h>
// 函数 返回两整数中的最大值
int max(int a, int b) {
  return a > b ? a : b;
}
int main() {
  // 函数指针  就是一个指针 (指针类型)
  int (*ptr)(int a, int b) = max;

  printf("%d\n",(*ptr)(10, 20));

  // 通过函数指针调用函数
  int maxVal;
  maxVal = (*ptr) (12, 32);
  printf("%d\n", maxVal);

  return 0;
}

回调函数

  1. 回调函数:一个通过函数指针调用的函数。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
// 使用回调函数,实现返回一个随机数
int *fn(int *array, int length, int (*arr)()) { // int (*arr)()  调用了 rand() 函数
  for (int i = 0; i < length; i++) {
    array[i] = (*arr)();
  }
  return array;
}
int main() {

  int arr[10];
  int length = sizeof(arr) / sizeof(int);
  // 设置随机种子
  srand(time(NULL));
  fn(arr, length, rand);
  for (int i = 0; i < 10; i++ ) {
    printf("%d\n", arr[i]);
  }

  return 0;
}

多级指针

  1. 指向指针的指针是一种多级间接寻址的形式。
  2. 声明多级指针时,使用多个 * 老表示指针的级别。
  3. 初始化指针时,需逐级给指针赋值,确保每个指针指向正确的目标。
  4. 解引用多级指针时,需要根据指针的级别使用适当数量的 * 解引用。
  // 多级指针
  int a = 100;
  // 一级指针
  int *ptr = &a;
  // 二级指针
  int **ptr2 = &ptr;
  // 三级指针
  int ***ptr3 = &ptr2;
  printf("一级指针 = %d,二级指针 = %d, 三级指针 = %d\n", *ptr, **ptr2, ***ptr3);

空指针

  1. 赋为NULL值的指针称为空指针,NULL一个值为0的宏常量。
  // 空指针
  int *p = NULL;
  int num = 34;
  p = &num;

  printf("p = %p \n", p);
  printf("p = %d \n", *p);

野指针

  1. 野指针:指针指向的位置是不可知的,随机性、不正确、没有明确限制。
  2. 野指针的成因:
    1. 指针使用前未初始化,值是随机的。
    2. 指针越界访问。
    3. 指针指向已释放的空间。
  3. 避免野指针
    1. 初始化时没有明确的地址赋值,为指针变量赋一个NULL。
    2. 小心指针越界。
    3. 避免返回指向局部变量的指针。

指针总结:

变量定义

类型表示

含义

int i

int

i是一个整型变量。

int *p

int *

p 是一个指向整型数据的指针

int a[5]

int[5]

a 是一个5个元素的整型数组。

int *p[4]

int *[4]

p 是一个指针数组,每个元素都是指向整型数据的指针。

int (*p)[4]

Int (*)[4]

p 是一个数组指针,指向一个4个元素的整型数组。

int f()

Int ()

f是一个返回整型数据的函数

int *f()

int *()

f是一个指针函数,返回指向整数数据的指针。

int (*p)()

int (*)()

p 是一个函数指针,指向一个返回整型数据的函数。

int **p

int **

p是一个指向指针的指针。

                

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值