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

简介: 指针进阶篇分为上下两篇,上篇介绍1 — 4,下篇介绍5 — 6字符指针数组指针指针数组数组传参和指针传参函数指针函数指针数组指向函数指针数组的指针回调函数

前言

指针基础篇回顾可以详见:指针基础篇(1)指针基础篇(2)

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

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

文章目录

前言

一、字符指针

1. 字符指针用法

2. 字符指针面试题

二、指针数组

1. 不同类型的指针数组

三、数组指针

1. 数组指针定义

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

3. 数组指针的使用

四、数组传参和指针传参

1. 一维数组传参

2. 二维数组传参

3. 一级指针传参

4. 二级指针传参

五、总结



一、字符指针

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


1. 字符指针用法

一般使用

intmain()
{
charch='a';
char*p=&ch;
*p='c';
return0;
}

另一种用法

#include<stdio.h>intmain()
{
constchar*psr="hello word";
printf("%s\n", psr);
return0;
}

输出结果

image.png

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

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


2. 字符指针面试题

演示代码

#include <stdio.h>intmain()
{
charstr1[] ="hello bit.";
charstr2[] ="hello bit.";
constchar*str3="hello bit.";
constchar*str4="hello bit.";
if(str1==str2)
printf("str1 and str2 are same\n");
elseprintf("str1 and str2 are not same\n");
if(str3==str4)
printf("str3 and str4 are same\n");
elseprintf("str3 and str4 are not same\n");
return0;
}

输出结果

image.png

结论

这里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 的整型数组,可以通过以下方式初始化:

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

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

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

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

inta=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>intmain()
{
intarr[10] = {0};
printf("%p\n", arr);
printf("%p\n", &arr);
return0;
}

输出结果

image.png

结论

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

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


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

演示代码

#include <stdio.h>intmain()
{
intarr[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);
return0;
}

输出结果

image.png

结论

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

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

image.png

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

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


3. 数组指针的使用

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

代码演示

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

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


数组指针的使用举例

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


四、数组传参和指针传参

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


1. 一维数组传参

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

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


2. 二维数组传参

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

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


3. 一级指针传参

#include <stdio.h>voidprint(int*p, intsz)
{
inti=0;
for(i=0; i<sz; i++)
 {
printf("%d\n", *(p+i));
 }
}
intmain()
{
intarr[10] = {1,2,3,4,5,6,7,8,9};
int*p=arr;
intsz=sizeof(arr)/sizeof(arr[0]);
//一级指针p,传给函数print(p, sz);
return0;
}

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


4. 二级指针传参

#include <stdio.h>voidtest(int**ptr)
{
printf("num = %d\n", **ptr); 
}
intmain()
{
intn=10;
int*p=&n;
int**pp=&p;
test(pp);
test(&p);
return0;
}

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


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

voidtest(char**p)
{
}
intmain()
{
charc='b';
char*pc=&c;
char**ppc=&pc;
char*arr[10];  
test(&pc);  //OKtest(ppc);  //OKtest(arr);   //OKreturn0;
}

五、总结

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


  • 数组指针是指针,指针数组是数组
  • arr表示首元素地址,首元素地址+1,就是跳过一个元素的指针,( int是4个字节 )就是+4
  • &arr表示数组地址,数组地址+1,就是跳过整个数组的大小,所以&arr+1对于&arr的差值是40
  • 二维数组传参,函数形参的设计只能省略第一个[ ]的数字。因为对一个二维数组,可以不知道有多少行,但是必须知道一行多少元素。这样才方便运算。



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

目录
相关文章
|
8天前
|
存储 C语言
【C语言基础】一篇文章搞懂指针的基本使用
本文介绍了指针的概念及其在编程中的应用。指针本质上是内存地址,通过指针变量存储并间接访问内存中的值。定义指针变量的基本格式为 `基类型 *指针变量名`。取地址操作符`&`用于获取变量地址,取值操作符`*`用于获取地址对应的数据。指针的应用场景包括传递变量地址以实现在函数间修改值,以及通过对指针进行偏移来访问数组元素等。此外,还介绍了如何使用`malloc`动态申请堆内存,并需手动释放。
|
11天前
|
存储 人工智能 C语言
C语言程序设计核心详解 第八章 指针超详细讲解_指针变量_二维数组指针_指向字符串指针
本文详细讲解了C语言中的指针,包括指针变量的定义与引用、指向数组及字符串的指针变量等。首先介绍了指针变量的基本概念和定义格式,随后通过多个示例展示了如何使用指针变量来操作普通变量、数组和字符串。文章还深入探讨了指向函数的指针变量以及指针数组的概念,并解释了空指针的意义和使用场景。通过丰富的代码示例和图形化展示,帮助读者更好地理解和掌握C语言中的指针知识。
|
17天前
|
存储 安全 C语言
C语言 二级指针应用场景
本文介绍了二级指针在 C 语言中的应用,
|
1月前
|
存储 编译器 C语言
【C语言篇】深入理解指针2
代码 const char* pstr = "hello world."; 特别容易让初学者以为是把字符串 hello world.放 到字符指针 pstr ⾥了,但是本质是把字符串 hello world. 首字符的地址放到了pstr中。
|
1月前
|
存储 程序员 编译器
【C语言篇】深入理解指针1
assert.h 头⽂件定义了宏 assert() ,⽤于在运⾏时确保程序符合指定条件,如果不符合,就报错终⽌运⾏。这个宏常常被称为“断⾔”。
|
1月前
|
存储 搜索推荐 C语言
C语言中的指针函数:深入探索与应用
C语言中的指针函数:深入探索与应用
|
1月前
|
C语言
【C语言】指针速览
【C语言】指针速览
16 0
|
1月前
|
C语言
【C初阶——指针5】鹏哥C语言系列文章,基本语法知识全面讲解——指针(5)
【C初阶——指针5】鹏哥C语言系列文章,基本语法知识全面讲解——指针(5)
|
1月前
|
C语言
【C初阶——指针4】鹏哥C语言系列文章,基本语法知识全面讲解——指针(4)
【C初阶——指针4】鹏哥C语言系列文章,基本语法知识全面讲解——指针(4)
|
3月前
|
C语言
指针进阶(C语言终)
指针进阶(C语言终)