指针的进阶 上

简介: 指针的进阶

1.字符指针


一般的使用

1ba376cd7a2c51cc3b25d7a68e8c60ee_62018993658e4c979fca9eae9d8f847b.png

通过字符指针 char*p 将字符 ch 的内容由 m 改写为 y


另一种使用

e0b77daf3f7481a0097b6ea465835767_c283aeaa96f1498da3a8059f476942a1.png

其本质就是将字符串“abcdef",首字符的地址存放在字符指针 p 中


经典例题


#include<stdio.h>
int main()
{
  char ch1[] = "abcdef";
  char ch2[] = "abcdef";
  const char* ch3 = "abcdef";
  const char* ch4 = "abcdef";
  if (ch1 == ch2)
  {
  printf("ch1 and ch2 are same\n");
  }
  else
  printf("ch1 and ch2 are not same\n");
  if (ch3 == ch4)
  {
  printf("ch3 and ch4 are same\n");
  }
  else
  printf("ch3 and ch4 are not same\n");
  return 0;
}


运行结果如下

cc74bf3bbf2cf63c6f1c4f14a9248a1e_8982de6d588a416bb26be2e1befa840f.png

ch3,ch4指向同一字符串,指向同一块内存。所以相同

ch1,ch2 由于是相同的常量字符串初始化不同的数组,便会开辟不同的内存块,所有不同


2.指针数组


int*arr1[10];//整形指针的数组
char*arr2[10];//字符指针的数组
char**arr3[10];//二级字符指针的数组


3.数组指针


3.1数组指针的诠释


数组指针,顾名思义是指针,前面加上个数组,所i有数组指针就是指向数组的指针


int(*p)[10];
p 的类型是 int(*)[10]
p 指向一个整形数组,数组有10个元素  int [10]


3.2 &数组名vs数组名


数组名通常表示的都是数组首元素地址
只有两个例外
1.sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小
2.&数组名,这里的数组名表示的依然是整个数组,所以&数组名取出的是整个数组的地址

观察下列代码


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

运行结果如下

ede689f41a7c8cac6386d0107cf8f7d9_94feff5048484e36847673667f94a20f.png

由此可见数组名,&数组名打印的地址是一样的,但真是如此吗?????

再观察一段代码


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


33a2a3c2ab6d661d60b63ac38247f721_419cbb9f8cdb448b8af81e5622761ca7.png


由运行结果可以知道,&arr,arr,虽然再数值上是一样的,但本质上是不同的。

实际上:&arr表示的是整个数组的地址。

整个数组的地址+1,跳过整个数组。


3.3 数组指针的使用


既然数组指针指向的是数组,所以数组指针中存放的是数组的地址。


数组指针的使用-> 模拟二维数组


#include<stdio.h>
void Print(int(*p)[3], int row, int col)
{
  int i = 0;//先按行打印
  for (i = 0; i < row; i++)
  {
  int j = 0;//打印每行中的数据
  for (j = 0; j < col; j++)
  {
    printf("%d ", p[i][j]);
  }
  printf("\n");//打印完一行之后需要换行
  }
}
int main()
{
  int arr[3][3] = { 1,2,3,2,3,4,3,4,5 };
  Print(arr, 3, 3);
  //数组名表示首元素地址
  //二维数组的首元素是二位数组的第一行
  //这里的arr,相当于第一行的地址,一个一维数组的地址
  //数组的地址,当然需要用数组指针来接受
  return 0;
}


c0a54b917d8ba3ba9b30fdf4e52e7686_8a90785e0d014a1d8f343a4eefc74b68.png


4.数组传参,指针传参


4.1一维数组传参


//数组传参可以传数组本身,亦可以传指针
void test1(int arr1[])
{}
void test1(int arr1[10])
{}
void test1(int *arr)
{}
void test2(int *arr2[10])
{}
//指针数组,元素类型是int*, 数组名是首元素地址,需要指针来接收
//所以形参可以是二级指针
void test2(int **arr2)
{}
int main()
{
  int arr1[10] = { 0 };
  int* arr2[10] = { 0 };
  test1(arr1);
  test2(arr2);
  return 0;
}


4.2二维数组传参


#include<stdio.h>
//形参的二维数组行可省略,列不可省略
void test(int arr[3][4])
{}
void test(int arr[][4])
{}
//二维数组的数组名,表示首元素地址
//就是第一行的地址,第一行地址是一个一维数组的地址
//可以用数组指针来接收
void test(int(*arr)[4])
{}
int main()
{
  int arr[3][4] = { 0 };
  test(arr);
  return 0;
}


4.3一级指针传参


void Print(int* parr, int sz)
{
  int i = 0;
  for (i = 0; i < sz; i++)
  {
  printf("%d ", parr[i]);
  }
}
int main()
{
  int arr[] = { 1,2,3,4,5,6,7,8,9 };
  int* parr = arr;
  int sz = sizeof(arr) / sizeof(arr[0]);
  //一级指针传给函数
  Print(parr, sz);
  return 0;
}


如果函数的形参是指针,实参有哪些可能呢


void Print(int*p)
{}
int main()
{
  int a = 10;
  int* p = &a;
  int arr[10] = { 0 };
  Print(&a);//直接取出整形a的地址
  Print(p);//将整形a的地址存放在指针p中
  Print(arr);//数组名是首元素地址
  return 0;
}


4.4 二级指针传参


void test(int** ptr)
{}
int main()
{
  int a = 10;
  int* p = &a;
  int** pp = &p;
  test(pp);//直接将二级指针作为实参
  test(&p);//取出一级指针的地址作为实参
  return 0;
}


如果函数的形参是二级指针,实参有哪些可能呢


void test(int**p)
{}
int main()
{
  int a = 10;
  int* p = &a;
  int** pp = &p;
  int* arr[10] = { 0 };
  //指针数组,数组名是首元素地址,首元素类型是int*
  test(&p);
  test(pp);
  test(arr);
  return 0;
}


5.函数指针


函数指针,顾名思义是指针,指向函数的指针。


int(*pf)(int,int)
函数指针,指向的函数返回类型是int,参数是(int,int)


int Add(int x, int y)
{
  return x + y;
}
int main()
{
  int arr[10] = { 0 };
  //&数组名,取出数组的地址
  int(*p)[10] = &arr;//数组指针
  //&函数名,取出的就是函数的地址
  int(*p)(int, int) = &Add;//函数指针
  return 0;
}


对于函数来说,&函数名和函数名都是函数的地址。


函数指针实现计算器(不包含浮点数)


#include<stdio.h> 
void menu()
{
  printf("**********************\n");
  printf("*****1.Add  2.Sub ****\n");
  printf("*****3.Mul  4.Div ****\n");
  printf("********0.exit *******\n");
  printf("**********************\n");
}
int Add(int x, int y)
{
  return x + y;
}
int Sub(int x, int y)
{
  return x - y;
}
int Mul(int x, int y)
{
  return x * y;
}
int Div(int x, int y)
{
  return x / y;
}
void calc(int(*pf)(int, int))
{
  int x = 0;
  int y = 0;
  printf("请输入两个操作数>");
  scanf("%d%d", &x, &y);
  int ret = pf(x, y);
  printf("%d\n", ret);
}
int main()
{
  int input = 1;
  do
  {
  menu();
  printf("请选择>");
  scanf("%d", &input);
  switch (input)
  {
  case 1:
    calc(Add);
    break;
  case 2:
    calc(Sub);
    break;
  case 3:
    calc(Mul);
    break;
  case 4:
    calc(Div);
    break;
  case 0:
    printf("退出计算器\n");
    break;
  default:
    printf("选择错误\n");
    break;
  }
  } while (input);
  return 0;
}

e779f2c226700f8d74aee6081bf0b244_0da2293a8c414d66bd975f2674411bd7.png


目录
相关文章
|
6月前
|
C语言
指针进阶(C语言终)
指针进阶(C语言终)
|
6月前
|
机器学习/深度学习 搜索推荐 算法
【再识C进阶2(下)】详细介绍指针的进阶——利用冒泡排序算法模拟实现qsort函数,以及一下习题和指针笔试题
【再识C进阶2(下)】详细介绍指针的进阶——利用冒泡排序算法模拟实现qsort函数,以及一下习题和指针笔试题
|
6月前
|
C语言
指针进阶(回调函数)(C语言)
指针进阶(回调函数)(C语言)
|
6月前
|
存储 C语言 C++
指针进阶(函数指针)(C语言)
指针进阶(函数指针)(C语言)
|
6月前
|
编译器 C语言
指针进阶(数组指针 )(C语言)
指针进阶(数组指针 )(C语言)
|
6月前
|
搜索推荐
指针进阶(2)
指针进阶(2)
52 4
|
6月前
指针进阶(3)
指针进阶(3)
44 1
|
6月前
|
C++
指针进阶(1)
指针进阶(1)
47 1
|
6月前
|
存储 安全 编译器
C++进阶之路:何为引用、内联函数、auto与指针空值nullptr关键字
C++进阶之路:何为引用、内联函数、auto与指针空值nullptr关键字
50 2
|
7月前
|
C语言
C语言进阶:进阶指针(下)
C语言进阶:进阶指针(下)
51 2