【学习笔记之我要C】指针进阶

简介: 【学习笔记之我要C】指针进阶

一、const修饰指针变量

  1. const如果放在*的左边,修饰的是指针指向的内容,保证指针指向的内容不能通过指针来改变。但是指针变量本身的内容可变;
  2. const如果放在*的右边,修饰的是指针变量本身,保证了指针变量的内容不能修改,但是指针指向的内容,可以通过指针改变。
void test1()
{
  int n = 10;
  int m = 20;
  int* p = &n;
  *p = 20;
  p = &m; 
}
void test2()
{
  //代码2
  int n = 10;
  int m = 20;
  const int* p = &n;
  *p = 20;//报错
  p = &m; 
}
void test3()
{
  int n = 10;
  int m = 20;
  int* const p = &n;
  *p = 20; 
  p = &m;  //报错
}
int main()
{
  //测试无cosnt的
  test1();
  //测试const放在*的左边
  test2();
  //测试const放在*的右边
  test3();
  return 0;
}

二、字符指针

int main() {
  //本质是把"hello"这个字符串的首字符的地址存储在了ps中
  char* ps = "hello";
  printf("%c\n", *ps);
  return 0;
}
int main()
{
  char str1[] = "hello bit.";
  char str2[] = "hello bit.";
  const char* str3 = "hello bit.";
  const char* str4 = "hello bit.";
  if (str1 == str2)
    printf("str1 and str2 are same\n");
  else
    printf("str1 and str2 are not same\n");
  if (str3 == str4)
    printf("str3 and str4 are same\n");
  else
    printf("str3 and str4 are not same\n");
  return 0;
}

三、 指针数组

 指针数组本质是数组,数组中存放的是指针。

int main() {
  //存放整型指针的数组
  //int* arr[3];
  int a[5] = { 1,2,3,4,5 };
  int b[] = { 2,3,4,5,6 };
  int c[] = { 3,4,5,6,7 };
  //模拟了一个二维数组,但并不是二维数组,二维数组是连续存放的。
  int* arr[3] = { a, b, c };
  int i = 0;
  for (int i = 0; i < 3; i++) {
    int j = 0;
    for(j = 0;j < 5; j++){
      //printf("%d ", *(arr[i] + j));
      printf("%d ", arr[i][j]);
    }
    printf("\n");
  }
  return 0;
}

四、数组指针

 指向数组的指针,注意区分和数组指针的区别。


 int (*p)[10];

 解释:p先和 * 结合,说明p是一个指针变量,然后指着指向的是一个大小为10个整型的数组。所以p是一个指针,指向一个数组,叫数组指针。

 注意:[]的优先级是高于 * 的,所以必须加上()来保证p先和 * 结合。

int main() {
  int arr[10] = { 1,2,3,4,5 };
  int (*parr)[10] = &arr;//取出的是数组的地址
  //parr 就是一个数组指针 - 其中存放的是数组的地址
  double* d[5];
  double* (*pd)[5] = &d;//pd就是一个数组指针
  return 0;
}

我们基本不会使用数组指针来存放一维数组的地址


五、数组传参、指针传参

  1. 一维数组传参
//数组传参,数组接受
void test(int arr[])
{}
//数组传参,数组接受,这里的10是没有意义的
void test(int arr[10])
{}
//数组传参实际传的是首元素地址,用用指针接收没有问题
void test(int* arr)
{}
//arr2本身就是一个指针数组,可以用指针数组接收
void test2(int* arr[20])
{}
//数组名表示首元素地址,也就是一个int*的地址
//int*是一个一级指针,
//这里arr2相当于取了一个一级指针地址
//那么arr2就相当于一个二级指针,可以用二级指针接收
void test2(int** arr)
{}
int main() {
  int arr[10] = { 0 };
  int* arr2[20] = { 0 };//整型指针数组
  test(arr);
  test2(arr2);
  return 0;
}
  1. 二维数组传参
void test(int arr[3][5])
{}
//二维数组传参,函数形参的设计只能省略第一个[]的数字
//因为对一个二维数组,可以不知道有多少行,但是必须知道一行多少元素
void test(int arr[][])//报错
{}
void test(int arr[][5])
{}
//二维数组的数组名也是表示的是地址
//但它表示的是第一行元素的地址,而不是第一个元素的地址
// 不能用一级指针来接收
void test(int* arr)
{}
//int* arr[5]是一个指针数组,不能接收二维数组
void test(int* arr[5])
{}
//数组指针能够指向一个含5个int类型元素的一维数组
//二维数组的数组名表示的是第一行元素的地址
//正好是一个含5个int类型元素的一维数组
void test(int (*arr)[5])
{}
//传的是一个一维数组的地址,也不能用二级指针来接收
void test(int** arr)
{}
int main()
{
  int arr[3][5] = { 0 };
  test(arr);
}
  1. 一级指针传参
void print(int* p, int sz) {
  int i = 0;
  for (i = 0; i < sz; i++)
  {
    printf("%d\n", *(p + i));
  }
}
int main()
{
  int arr[10] = { 1,2,3,4,5,6,7,8,9 };
  int* p = arr;
  int sz = sizeof(arr) / sizeof(arr[0]);
  //一级指针p,传给函数
  print(p, sz);
  return 0;
}
  1. 二级指针传参
void test(int** ptr) {
  printf("num = %d\n", **ptr);
}
int main()
{
  int n = 10;
  int* p = &n;
  int** pp = &p;
  test(pp);
  //可以一级指针的地址
  //二级指针本身就是用来存放以及指针地址的
  test(&p);
  int* arr[10] = { 0 };
  //可以传一个指针数组
  //指针数组内存放的是指针也就是地址
  //有点类似传过去了一个一级指针地址
  test(arr);
  return 0;
}

六、函数指针

 函数指针就是存放函数地址的指针。

int Add(int x, int y){
  return x + y;
}
int main() {
  //pf就是一个函数指针
  int (*pf)(int, int) = &Add;
  //&Add == Add
  //&Add、Add都表示函数的地址
  printf("%p\n", &Add);
  printf("%p\n", Add);
  printf("%p\n", pf);
  //实际上这里*是没有实意的
  //它的作用是让我们知道这是一个指针
  int ret1 = (*pf)(3, 5);
  printf("%d\n", ret1);
  //int (*pf)(int, int) = Add;
  //pf === Add
  //函数调用可以写成Add(3, 5)
  //所以可以写成pf(3, 5)
  int ret2 = pf(3, 5);
  printf("%d\n", ret2);
  return 0;
}

七、函数指针数组

 函数指针数组用来存放同类型的函数指针。

int Add(int x, int y) {
  return x + y;
}
int Sub(int x, int y) {
  return x - y;
}
int main() {
  int (*pf1)(int, int) = Add;
  int (*pf2)(int, int) = Sub;
  //pfArr函数指针数组,存放同类型的函数指针
  int (*pfArr[2])(int, int) = { Add, Sub };
  return 0;
}

八、指向函数指针数组的指针

 指向函数指针数组的指针是一个指针,指针指向一个数组,数组的元素都是函数指针。

void test(const char* str) {
  printf("%s\n", str);
}
int main()
{
  //函数指针pfun
  void (*pfun)(const char*) = test;
  //函数指针的数组pfunArr
  void (*pfunArr[5])(const char* str);
  pfunArr[0] = test;
  //指向函数指针数组pfunArr的指针ppfunArr
  void (*(*ppfunArr)[5])(const char*) = &pfunArr;
  return 0;
}

九、回调函数

 回调函数就是一个通过函数指针调用的函数。把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。


目录
相关文章
|
6月前
|
C语言
指针进阶(C语言终)
指针进阶(C语言终)
|
3月前
|
存储 Go
Go: struct 结构体类型和指针【学习笔记记录】
本文是Go语言中struct结构体类型和指针的学习笔记,包括结构体的定义、成员访问、使用匿名字段,以及指针变量的声明使用、指针数组定义使用和函数传参修改值的方法。
|
4月前
|
存储 C++
c++学习笔记06 指针
C++指针的详细学习笔记06,涵盖了指针的定义、使用、内存占用、空指针和野指针的概念,以及指针与数组、函数的关系和使用技巧。
36 0
|
6月前
|
C语言
指针进阶(回调函数)(C语言)
指针进阶(回调函数)(C语言)
|
6月前
|
存储 C语言 C++
指针进阶(函数指针)(C语言)
指针进阶(函数指针)(C语言)
|
6月前
|
编译器 C语言
指针进阶(数组指针 )(C语言)
指针进阶(数组指针 )(C语言)
|
6月前
|
搜索推荐
指针进阶(2)
指针进阶(2)
52 4
|
6月前
指针进阶(3)
指针进阶(3)
45 1
|
6月前
|
C++
指针进阶(1)
指针进阶(1)
47 1
|
6月前
|
Java 程序员 Linux
探索C语言宝库:从基础到进阶的干货知识(类型变量+条件循环+函数模块+指针+内存+文件)
探索C语言宝库:从基础到进阶的干货知识(类型变量+条件循环+函数模块+指针+内存+文件)
52 0