【指针的进阶(1)】指针的类型、数组传参和指针传参

简介: 【指针的进阶(1)】指针的类型、数组传参和指针传参

一、指针是什么?

  • 含义:内存被划分为一个个小的内存单元,每个内存单元都有一个编号,编号也称为地址,地址在C语言中被称为指针。
    指针(地址)需要存储起来,存储在变量中,这个变量就被称为指针变量。
int a=10;
int* pa=&a;

比如要存储变量a到pa里,&a就是a的地址,pa就是指针变量,还要说明pa的类型是int*。

  • 指针的大小:在32位平台上是4个字节,在64位平台上是8个字节

二、字符指针

顾名思义是用来存放字符的地址

2.1 字符指针的两种使用方法

在初阶指针,学习了字符指针的一般使用方式:

#include<stdio.h>
//字符指针
int main()
{
  char ch= "w";
  char* pc =&ch;
  pc = "a";
  return 0;
}

方法思路:改变ch的字符,可以直接用ch来改,但是字符指针pc的好处就是可以代替ch去改,把ch的地址存到pc,pc就可以通过地址找到ch,改变ch的字符,有种借刀杀人的意思。

本章继续学习另一种使用方法

int main()
{
  //创建arr字符数组,用abcdef给arr初始化
  //相当于在内存中创建数组,里面放了[a b c d e f \0] 
  char arr[] = "abcdef";
  //在x86环境下,p指针是4个字节,abcdef是放不完的
  //不是把abcdef放进p指针
  //思路:给p一个地址,向后打印字符串
  //就是是把首元素a的地址赋给p,让p找到字符串的起始位置
  //注意:字符串是常量字符串,不能被改,在*左边加上const,限制p不能改字符串
  const char* p ="abcdef";
  //打印字符串,要指定格式%s,还要给p一个起始地址,从这个地址向后打印字符串
  printf("%s\n", p);
  //给p解引用,打印字符串的首字符a
  printf("%c", *p);
  return 0;
}

三、指针数组

是数组,是存放指针的数组

类比:

  • 整型数组:存放整型的数组
  • 字符数组:存放字符的数组
int main()
{
  int arr[10];//存放整型数组
  int* arr[10];//存放整型指针数组
  char* arr[5];//一级字符指针数组
  char* arr[6];//二级字符指针的数组
  return 0;
}

四、数组指针

4.1数组指针的定义

是指针,是指向数组变量的指针,存放数组变量的地址的指针变量

类比:

  • 整型指针:指向整型变量的指针,存放整形变量的地址的指针变量
  • 字符指针:指向字符变量的指针,存放字符变量的地址的指针变量

指针数组和数组指针的区别

int* p1[10];

p1是数组,元素有10个,每个元素的类型是int*

int(* p2)[10];

p2和*结合,p2是指针,p2外边是数组int[10],说明p2指向的是数组,所以p2是数组指针变量

4.2 &数组名 VS 数组名

数组名的理解

int main()
{
  //arr和&arr[0]的地址一样
  //说明数组名是数组首元素的地址
  int arr[10] = { 0 };
  printf("%p\n", arr);
  printf("%p\n", &arr[0]);
  printf("%d\n", sizeof(arr));
  printf("%p\n", &arr);
  return 0;
}

两个例外

1.sizeof(数组名),这里的数组名不是数组首元素的地址, 而是代表整个数组,sizeof(数组名)计算整个数组的大小, 单位是字节

2.&数组名,这里的数组名表示整个数组,&数组名取出的是整个数组的地址 单纯打印出来和首元素地址一样,没有区别,但调试起来发现它们的类型不一样

验证第二点:

int main() 
{
  int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
  printf("%p\n", arr);
  printf("%p\n", arr + 1);//跳过一个元素,4个字节
  printf("%p\n", &arr[0]);
  printf("%p\n", &arr[0] + 1);//跳过一个元素,4个字节
  printf("%p\n", &arr);
  printf("%p\n", &arr + 1);//跳过整个数组,40个字节
  return 0;
}

4.3 数组指针的使用方法

  1. 普通的二维数组传参
void print(int arr[4][5], int r, int c)//数组,行,列接收
{
  int i = 0;
  for (i = 0; i < r;i++)//第i行
  {
    int j = 0;
    for (j = 0; j < c; j++)//循环打印第i行的每个元素
    {
      printf("%d ", arr[i][j]);
    }
    printf("\n");//换行
  }
}
int main()
{
  int arr[4][5] = { 1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7, 4,5,6,7,8 };
  print(arr, 4, 5);
    return 0;
}
  1. 用数组指针传参

思路:

void print(int(*p)[5], int r, int c)//用数组指针,行,列接收
{
  int i = 0;
  for (i = 0; i < r; i++)//第i行
  {
    int j = 0;
    for (j = 0; j < c; j++)//循环打印第i行中的每个元素
    {
      //p是数组第一行的地址,相当于首元素的地址,p+i是找到数组第i行的地址
      //*(p+i) 是找到第i行中的每一个元素的地址
      //*(p+i)+j 是找到第i行第j列的地址
      //*(*(p + i) + j) 是给地址解引用,找到第i行第j列的那个元素
      printf("%d ", *(*(p + i) + j));
    }
    printf("\n");//换行
  }
}
int main()
{
  int arr[3][5] = { 1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7 };
  print(arr,3,5);//把数组,行,列传过去
  return 0;
}

五、数组参数,指针参数

5.1 一维数组传参

  • 一维数组传参可以是数组,也可以是指针
  • 形式上两种都可以,但本质上数组传参就是指针传参,只不过写成数组更直观
void test1(int arr[5], int sz)
{
}
void test2(int* p, int sz)
{
}
int main()
{
  int arr[5] = { 0 };
  test1(arr,5);
  test2(arr, 5);
  return 0;
}

5.2二维数组传参

二维数组传参可以是数组,也可以是指针

void test3(char arr[3][5], int r, int c)//行可以省略,[3][5]可以写成[][5],但不能像数组指针那样写成[5]
{
}
void test4(char(*p)[5], int r, int c)//行可以省略,[3][5]可以写成[5]
{
}
int main()
{
  char arr[3][5] = { 0 };//char或int初始化都是0
  test3(arr, 3, 5);
  test4(arr, 3, 5);
  return 0;
}

需要注意的是:

可以用数组指针传参,也可以用数组传参,但是不能用指针数组传参

错误写法:用指针数组传参:void test (int* arr[5])

5.3一级指针传参

void print(int* p, int sz)
{
  int i = 0;
  for (i = 0; i < sz; i++)
  {
    printf("%d ", *(p+i));
  }
}
int main()
{
  int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
  int* p = arr;//把首元素的地址赋给指针p
  int sz = sizeof(arr) / sizeof(arr[0]);//计算数组大小
  print(p, sz);//传一级指针p和数组的大小给函数
  return 0;
}

思考:

当一个函数的的参数部分是一级指针时,函数可以接收什么参数?

void test(char* p)
{
}
int main()
{
  return 0;
}

思路: 传的实参类型要跟形参类型完全匹配上。

  1. char ch = '2'; //单引号里面只能放一个任何类型的字符
    test(&ch); //传字符变量的地址
  2. char* ptr = &ch;//把ch的地址取出来放进ptr里
    test(ptr);//ptr是char类型的,参数也用char类型的指针接收它
  3. char arr[] = "abcdef";//字符数组
    test(arr);//传字符数组的首元素地址,参数用char*类型接收

5.4二级指针传参

void test(int **ptr)//用二级指针接收
{
}
int main()
{
  int n = 10;
  int* p = &n;
  //把n的地址放进指针变量p里,p是一级指针
  int** p1 = &p;
  //对一级指针p取地址赋给p1,p1是二级指针
  test(p1);
  //第一种传参
  //传二级指针p1,因为p的地址赋给了p1
  test(&p);
  //第二种传参
  //传p的地址,因为p接收了n的地址,再传p的地址,&p就是二级指针
  return 0;
}

思考:

当一个函数的的参数部分是二级指针时,函数可以接收什么参数?

void test(char** ptr)
{
}
int main()
{
  char n = 'a';
  return 0;
}
  1. char* p = &n;
    test(&p); //把n的地址放进指针变量p里,p是一级指针,再传p的地址,&p就是二级指针
  2. char** p1 = &p;//对一级指针p取地址,p1是二级指针
    test(p1);//可以传二级指针p1, 因为p的地址赋给了p1
  3. char* arr[5];//arr本身是首元素地址,它的元素类型又是char*类型
    test(arr);//所以arr是二级指针,可以用arr传参
    总结
    指针的进阶第一章内容就写到这,如果对你有帮助的话,不妨来一个关注吧!
相关文章
|
1月前
使用指针访问数组元素
【10月更文挑战第30天】使用指针访问数组元素。
37 3
|
24天前
|
存储 程序员 编译器
C 语言数组与指针的深度剖析与应用
在C语言中,数组与指针是核心概念,二者既独立又紧密相连。数组是在连续内存中存储相同类型数据的结构,而指针则存储内存地址,二者结合可在数据处理、函数传参等方面发挥巨大作用。掌握它们的特性和关系,对于优化程序性能、灵活处理数据结构至关重要。
|
28天前
|
存储 C语言 计算机视觉
在C语言中指针数组和数组指针在动态内存分配中的应用
在C语言中,指针数组和数组指针均可用于动态内存分配。指针数组是数组的每个元素都是指针,可用于指向多个动态分配的内存块;数组指针则指向一个数组,可动态分配和管理大型数据结构。两者结合使用,灵活高效地管理内存。
|
28天前
|
容器
在使用指针数组进行动态内存分配时,如何避免内存泄漏
在使用指针数组进行动态内存分配时,避免内存泄漏的关键在于确保每个分配的内存块都能被正确释放。具体做法包括:1. 分配后立即检查是否成功;2. 使用完成后及时释放内存;3. 避免重复释放同一内存地址;4. 尽量使用智能指针或容器类管理内存。
|
28天前
|
存储 NoSQL 编译器
C 语言中指针数组与数组指针的辨析与应用
在C语言中,指针数组和数组指针是两个容易混淆但用途不同的概念。指针数组是一个数组,其元素是指针类型;而数组指针是指向数组的指针。两者在声明、使用及内存布局上各有特点,正确理解它们有助于更高效地编程。
|
1月前
|
存储 人工智能 算法
数据结构实验之C 语言的函数数组指针结构体知识
本实验旨在复习C语言中的函数、数组、指针、结构体与共用体等核心概念,并通过具体编程任务加深理解。任务包括输出100以内所有素数、逆序排列一维数组、查找二维数组中的鞍点、利用指针输出二维数组元素,以及使用结构体和共用体处理教师与学生信息。每个任务不仅强化了基本语法的应用,还涉及到了算法逻辑的设计与优化。实验结果显示,学生能够有效掌握并运用这些知识完成指定任务。
53 4
|
1月前
使用指针访问数组元素
【10月更文挑战第31天】使用指针访问数组元素。
48 2
|
1月前
|
存储 C语言
C语言如何使用结构体和指针来操作动态分配的内存
在C语言中,通过定义结构体并使用指向该结构体的指针,可以对动态分配的内存进行操作。首先利用 `malloc` 或 `calloc` 分配内存,然后通过指针访问和修改结构体成员,最后用 `free` 释放内存,实现资源的有效管理。
105 13
|
2月前
|
C语言
无头链表二级指针方式实现(C语言描述)
本文介绍了如何在C语言中使用二级指针实现无头链表,并提供了创建节点、插入、删除、查找、销毁链表等操作的函数实现,以及一个示例程序来演示这些操作。
36 0
|
3月前
|
存储 人工智能 C语言
C语言程序设计核心详解 第八章 指针超详细讲解_指针变量_二维数组指针_指向字符串指针
本文详细讲解了C语言中的指针,包括指针变量的定义与引用、指向数组及字符串的指针变量等。首先介绍了指针变量的基本概念和定义格式,随后通过多个示例展示了如何使用指针变量来操作普通变量、数组和字符串。文章还深入探讨了指向函数的指针变量以及指针数组的概念,并解释了空指针的意义和使用场景。通过丰富的代码示例和图形化展示,帮助读者更好地理解和掌握C语言中的指针知识。
137 4