C语言 — 指针进阶篇(上)

简介: C语言 — 指针进阶篇(上)

前言


指针进阶篇分为上下两篇,上篇介绍1 — 4,下篇介绍5 — 6

  1. 字符指针
  2. 数组指针
  3. 指针数组
  4. 数组传参和指针传参
  5. 函数指针
  6. 函数指针数组
  7. 指向函数指针数组的指针
  8. 回调函数


一、字符指针

在基础篇中简单介绍过字符指针

1. 字符指针用法

一般使用

int main()
{
  char ch = 'a';
  char* p = &ch;
  *p = 'c';
  return 0;
}

另一种用法

#include<stdio.h>
int main()
{
  const char* psr = "hello word";
  printf("%s\n", psr);
  return 0;
}

输出结果

输出的结果是hello word,字符串的首字符的地址存放在字符指针psr

即意思是把一个常量字符串的首字符h的地址存放在指针变量 psr

2. 字符指针面试题

演示代码

#include <stdio.h>
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;
}

输出结果

结论

这里str3和str4指向的是一个同一个常量字符串。C/C++会把常量字符串存储到单独的一个内存区域,当几个指针指向同一个字符串的时候,他们实际会指向同一块内存

但是用相同的常量字符串去初始化不同的数组的时候就会开辟出不同的内存块。

所以str1和str2不同,str3和str4相同。

二、指针数组

在指针基础篇中提到过,指针数组就是存放指针的数组

1. 不同类型的指针数组

int * arr1[10];     //整形指针数组 ,里面存放整形指针
char * arr2[10];    //一级字符指针数组,里面存放字符指针
char ** arr3[10];   //二级字符指针数组,里面存放二级字符指针

三、数组指针

1. 数组指针定义

数组指针区别于上面的指针数组,数组指针是指针指针数组是数组。


数组指针和指针数组是两个不同的概念。

数组指针是指一个指向数组的指针变量。它可以用于访问数组元素,也可以作为函数参数传递,可以定义如下:

int (*arr_ptr)[N]; // 定义一个指向长度为 N 的整型数组的指针

这个指针变量可以指向长度为 N 的整型数组,可以通过以下方式初始化:

int arr[N] = {1, 2, 3, 4, 5};
int (*arr_ptr)[N] = &arr; // 指向数组arr的指针

指针数组是指一个包含指针的数组。它可以用来存储一组指针,也可以通过指针访问数组元素,可以定义如下:

int *ptr_arr[N]; // 定义一个包含N个指向整型的指针的数组

这个数组包含 N 个指针变量,每个指针变量可以指向一个整型变量,可以通过以下方式初始化:

int a = 10, b = 20, c = 30;
int *ptr_a = &a, *ptr_b = &b, *ptr_c = &c;
int *ptr_arr[] = { ptr_a, ptr_b, ptr_c };

以上都是基本的定义和初始化方式,具体使用还需要根据具体场景和需求进行操作。

2. &数组名与数组名的区别

演示代码

#include <stdio.h>
int main()
{
 int arr[10] = {0};
 printf("%p\n", arr);
 printf("%p\n", &arr);
 return 0;
}

输出结果

结论

总所周知,arr是数组名,数组名是首元素的地址

由输出结果得arr和&arr的输出结果相同,其实这两者是存在区别的


在上面的基础上我们对arr和&arr进行+1操作

演示代码

#include <stdio.h>
int main()
{
  int arr[10] = { 0 };
  printf("arr = %p\n", arr);
  printf("arr+1 = %p\n", arr + 1);
  printf("&arr= %p\n", &arr);
  printf("&arr+1= %p\n", &arr + 1);
  return 0;
}

输出结果

结论

由代码得,arr和&arr输出的值是一样的,但意义不同

&arr表示的是数组的地址,而不是数组首元素的地址

arr表示首元素地址,首元素地址+1,就是跳过一个元素的指针,( int是4个字节 )就是+4

&arr表示数组地址,数组地址+1,就是跳过整个数组的大小,所以&arr+1对于&arr的差值是40

3. 数组指针的使用

数组指针指向的是数组,那数组指针中存放的应该是数组的地址。

代码演示

#include <stdio.h>
int main()
{
  int arr[10] = { 1,2,3,4,5,6,7,8,9,0 };
  int(*p)[10] = &arr;//(*p)表示p是一个指针变量,[10]表示有10个元素
  return 0;
}

(*p)表示p是一个指针变量,[10]表示有10个元素


数组指针的使用举例

#include <stdio.h>
void print_arr1(int arr[3][5], int row, int col)
{
 int i = 0;
 for(i=0; i<row; i++)
 {
 for(j=0; j<col; j++)
 {
 printf("%d ", arr[i][j]);
 }
 printf("\n");
 }
}
void print_arr2(int (*arr)[5], int row, int col)
{
 int i = 0;
 for(i=0; i<row; i++)
 {
 for(j=0; j<col; j++)
 {
 printf("%d ", arr[i][j]);
 }
 printf("\n");
 }
}
int main()
{
 int arr[3][5] = {1,2,3,4,5,6,7,8,9,10};
 print_arr1(arr, 3, 5);
 //数组名arr,表示首元素的地址
 //但是二维数组的首元素是二维数组的第一行
 //所以这里传递的arr,其实相当于第一行的地址,是一维数组的地址
 //可以数组指针来接收
 print_arr2(arr, 3, 5);
 return 0;
}

四、数组传参和指针传参

写代码时(以往写冒泡排序时)需要把数组或指针传给函数,下面介绍函数的参数应该如何设计


1. 一维数组传参

#include <stdio.h>
void test(int arr[])//ok
{}
void test(int arr[10])//ok
{}
void test(int *arr)//ok
{}
void test2(int *arr[20])//ok
{}
void test2(int **arr)//ok
{}
int main()
{
 int arr[10] = {0};
 int *arr2[20] = {0};
 test(arr);
 test2(arr2);
}

总结:以上传参都是正确的


2. 二维数组传参

void test(int arr[3][5])//ok
{}
void test(int arr[][])  //NO  形参部分,行可以省略,列不能省略
{}
void test(int arr[][5]) //ok
{}
void test(int *arr)     //NO
{}
void test(int* arr[5])  //NO  形参是指针数组
{}
void test(int (*arr)[5])//ok   形参是数组指针
{}
void test(int **arr)  //NO  二级指针
{}
int main()
{
 int arr[3][5] = {0};
 test(arr);
}

总结:二维数组传参,函数形参的设计只能省略第一个[ ]的数字。因为对一个二维数组,可以不知道有多少行,但是必须知道一行多少元素。这样才方便运算。


3. 一级指针传参

#include <stdio.h>
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;
}

总结:传过去的参数和形参是匹配的上即可


4. 二级指针传参

#include <stdio.h>
void test(int** ptr)
{
  printf("num = %d\n", **ptr); 
}
int main()
{
   int n = 10;
   int*p = &n;
   int **pp = &p;
   test(pp);
   test(&p);
   return 0;
}

总结:传pp和&p都可以,相互对应即可

当函数的参数为二级指针的时候,可以接收什么参数?

void test(char **p)
{
 
}
int main()
{
 char c = 'b';
 char*pc = &c;
 char**ppc = &pc;
 char* arr[10];  
 test(&pc);  //OK
 test(ppc);  //OK
 test(arr);   //OK
 return 0;
}

五、总结

本文介绍了字符指针、数组指针、指针数组、数组传参和指针传参。

数组指针是指针,指针数组是数组

arr表示首元素地址,首元素地址+1,就是跳过一个元素的指针,( int是4个字节 )就是+4

&arr表示数组地址,数组地址+1,就是跳过整个数组的大小,所以&arr+1对于&arr的差值是40

二维数组传参,函数形参的设计只能省略第一个[ ]的数字。因为对一个二维数组,可以不知道有多少行,但是必须知道一行多少元素。这样才方便运算。


如这篇博客对大家有帮助的话,希望 三连 支持一下 !!! 如果有错误感谢大佬的斧正 如有 其他见解发到评论区,一起学习 一起进步。

目录
相关文章
|
16天前
|
存储 NoSQL 编译器
【C语言】指针的神秘探险:从入门到精通的奇幻之旅 !
指针是一个变量,它存储另一个变量的内存地址。换句话说,指针“指向”存储在内存中的某个数据。
70 3
【C语言】指针的神秘探险:从入门到精通的奇幻之旅 !
|
16天前
|
存储 编译器 C语言
【C语言】指针大小知多少 ?一场探寻C语言深处的冒险 !
在C语言中,指针的大小(即指针变量占用的内存大小)是由计算机的体系结构(例如32位还是64位)和编译器决定的。
44 9
|
16天前
|
安全 程序员 C语言
【C语言】指针的爱恨纠葛:常量指针vs指向常量的指针
在C语言中,“常量指针”和“指向常量的指针”是两个重要的指针概念。它们在控制指针的行为和数据的可修改性方面发挥着关键作用。理解这两个概念有助于编写更安全、有效的代码。本文将深入探讨这两个概念,包括定义、语法、实际应用、复杂示例、最佳实践以及常见问题。
40 7
|
26天前
|
存储 C语言
C语言如何使用结构体和指针来操作动态分配的内存
在C语言中,通过定义结构体并使用指向该结构体的指针,可以对动态分配的内存进行操作。首先利用 `malloc` 或 `calloc` 分配内存,然后通过指针访问和修改结构体成员,最后用 `free` 释放内存,实现资源的有效管理。
94 13
|
19天前
|
存储 程序员 编译器
C 语言数组与指针的深度剖析与应用
在C语言中,数组与指针是核心概念,二者既独立又紧密相连。数组是在连续内存中存储相同类型数据的结构,而指针则存储内存地址,二者结合可在数据处理、函数传参等方面发挥巨大作用。掌握它们的特性和关系,对于优化程序性能、灵活处理数据结构至关重要。
|
20天前
|
算法 C语言
C语言中的文件操作技巧,涵盖文件的打开与关闭、读取与写入、文件指针移动及注意事项
本文深入讲解了C语言中的文件操作技巧,涵盖文件的打开与关闭、读取与写入、文件指针移动及注意事项,通过实例演示了文件操作的基本流程,帮助读者掌握这一重要技能,提升程序开发能力。
62 3
|
20天前
|
存储 算法 程序员
C 语言指针详解 —— 内存操控的魔法棒
《C 语言指针详解》深入浅出地讲解了指针的概念、使用方法及其在内存操作中的重要作用,被誉为程序员手中的“内存操控魔法棒”。本书适合C语言初学者及希望深化理解指针机制的开发者阅读。
|
20天前
|
程序员 C语言
C语言中的指针既强大又具挑战性,它像一把钥匙,开启程序世界的隐秘之门
C语言中的指针既强大又具挑战性,它像一把钥匙,开启程序世界的隐秘之门。本文深入探讨了指针的基本概念、声明方式、动态内存分配、函数参数传递、指针运算及与数组和函数的关系,强调了正确使用指针的重要性,并鼓励读者通过实践掌握这一关键技能。
33 1
|
24天前
|
存储 C语言 计算机视觉
在C语言中指针数组和数组指针在动态内存分配中的应用
在C语言中,指针数组和数组指针均可用于动态内存分配。指针数组是数组的每个元素都是指针,可用于指向多个动态分配的内存块;数组指针则指向一个数组,可动态分配和管理大型数据结构。两者结合使用,灵活高效地管理内存。
|
24天前
|
存储 NoSQL 编译器
C 语言中指针数组与数组指针的辨析与应用
在C语言中,指针数组和数组指针是两个容易混淆但用途不同的概念。指针数组是一个数组,其元素是指针类型;而数组指针是指向数组的指针。两者在声明、使用及内存布局上各有特点,正确理解它们有助于更高效地编程。