指针就该这么学->C指针进阶

简介: 指针就该这么学->C指针进阶

下面代码分别代表什么?

int *parr[4];    //1
int (*parr)[4];    //2

结果:1是指针数组,2是数组指针,初学者很容易把他俩搞混,或者不知道怎么用???

读完本篇文章你会有新的理解和认识>_<

🍌指针数组

1.定义

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

指针数组是  指针?数组?

很明显是数组。

下面代码解释为

  • 创建了一个指针数组类型的变量
  • 数组中有三个元素,元素的类型为char*
char* ptr[3] = {"I", "LOVE", "YOU"};

🍌数组指针

1.定义

数组指针是一个指向数组的指针

int arr[5] = {0};
int (*parr)[5] = &arr;

2. &数组名 与 数组名

int arr[3] = {0};        //arr 与 &arr 相同吗???

在VS中输出看一下

打印出来的结果是一样,但是事实不是这样的。

当我们对上面两个地址同时加1时,观察结果他们相差了8

🍋先说结论,指针类型决定指针运算时跳过的字节数,数组名就是地址,地址就是指针嘛,所以遵循这个原则!!!

 

两个地址相差了8个字节,我们画下内存图,看看为什么是8

 

=========================================================================

补充:数组名在除以下两种情况外,其他都代表首元素地址

          1.sizeof(数组名)        -计算的是整个数组的大小

          2.&数组名                  -拿到的数组的地址

=========================================================================

 

3.数组指针的使用

那数组指针有什么用呢?

很明显数组指针存放的数组的地址,看代码

void print_arr1(int arr[3][2]) {
  for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 2; j++) {
      printf("%d ", arr[i][j]);
    }
  }
}
void print_arr2(int (*parr)[2]) {
  for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 2; j++) {
      printf("%d ", parr[i][j]);
    }
  }
}
int main()
{
  int arr[3][2] = { {1 ,2}, {3 ,4},{5 ,6} };
  print_arr1(arr);
  printf("\n");
  print_arr2(arr);
  return 0;
}

可以作为形参接受二维数组的首元素地址

🐒总结

学完上面指针数组与数组指针,总结和回顾下所学内容,解释代码:

int arr[5];

int *parr1[10];

int (*parr2)[10];

int (*parr3[10])[5];

//  1 数组 -> 声明一个整形数组,大小为5

//  2 数组指针 -> parr1先跟[]结合,说明是数组,去掉parr1[10],剩下的就是数组存放类型为int*

//  3 指针型数组 -> parr2先跟*结合,说明是指针,去掉指针部分*parr2,剩下的是指针的指向int()[10],指向的是一个数组

//  4 指针数组型的数组 -> parr3先与[]结合,是数组,去掉parr3[10],剩下的就是数组存放的类型int(*)[5]。可以对比int arr[5]去掉arr[5]就是数组存放的类型int。

🍋规律:先看是指针还是数组,是指针就看指针指向的是什么,是数组就看数组里面存放的是什么,复杂无非就是这部分复杂。

🍌指针数组与数组指针的传参

💧一位数组的传参:

当我们把一维数组作为参数是,函数的形参可以怎么设计呢?

// 一维数组的传参
void test1(int arr[]) {
}
void test2(int* arr) {
}
int main()
{
  int arr[] = { 1,2,3 };
  test1(arr);
  test2(arr);
  return 0;
}

💧二维数组的传参:

二维数组写法就比较多了,不妨自己先试着写写看能写几个?

在这先说明二维数组可以看成n个一维数组,arr数组名代表首元素地址,也就是int [3]地址,总起来arr就是&int [3]。

int arr[2][3];

test(arr);

void test1(int arr[][3]) {
}
void test2(int arr[2][3]) {
}
void test3(int (*parr)[3]) {
}
int main()
{
  int arr[2][3] = { 0 };
  test1(arr);
  test2(arr);
  test3(arr);
  test4(arr);
  return 0;
}

思考一下 可不可以用下面这样形式接受呢

void test(int *parr[3])            //这是数组,压根不是指针

void test(int** parr)              //二级指针存放int*的地址

void test(int* parr)                //存放int的地址

🍌🍌指针笔试题

秘诀:指针指向的类型决定运算时跳过的字节

🔪 -> offer ①

int main()
{
 int a[5] = { 1, 2, 3, 4, 5 };
 int *ptr = (int *)(&a + 1);
 printf( "%d,%d", *(a + 1), *(ptr - 1));
 return 0;
}
//程序的结果是什么?

=========================================================================

运行结果:

🔪 -> offer ②

//结构体的大小是8个字节
struct Test
{
    int val;
    char c;
}*p;
//假设p 的值为0x100000。 如下表表达式的值分别为多少?
//已知,结构体Test类型的变量大小是8个字节
int main()
{
 printf("%p\n", p + 0x1);
 printf("%p\n", (unsigned long)p + 0x1);
 printf("%p\n", (unsigned int*)p + 0x1);
 return 0;
}

=========================================================================运行结果:

分析:

       p+0x1 等价于 p+1,p指向的结构体类型大小为8,所以跳过8个字节

       p强制转为unsigned long,我们说地址也是个整数嘛,整数加1不就是答案嘛

       同理1,强转后跳过4个字节

🔪 -> offer ③

int main()
{
 int a[5][5];
 int(*p)[4];
 p = a;
 printf( "%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
 return 0;
}

=========================================================================运行结果:

指针相减结果为元素个数

%d格式化输出为-4

-4补码        // 11111111 11111111 11111111 11111100

%p输出为十六进制的unsigned int,所以把-4当作无符号整数输出了。

好啦,感谢观看!!!

相关文章
|
5月前
|
C语言
指针进阶(C语言终)
指针进阶(C语言终)
|
5月前
|
机器学习/深度学习 搜索推荐 算法
【再识C进阶2(下)】详细介绍指针的进阶——利用冒泡排序算法模拟实现qsort函数,以及一下习题和指针笔试题
【再识C进阶2(下)】详细介绍指针的进阶——利用冒泡排序算法模拟实现qsort函数,以及一下习题和指针笔试题
|
5月前
|
C语言
指针进阶(回调函数)(C语言)
指针进阶(回调函数)(C语言)
|
5月前
|
存储 C语言 C++
指针进阶(函数指针)(C语言)
指针进阶(函数指针)(C语言)
|
5月前
|
编译器 C语言
指针进阶(数组指针 )(C语言)
指针进阶(数组指针 )(C语言)
|
5月前
|
搜索推荐
指针进阶(2)
指针进阶(2)
50 4
|
5月前
指针进阶(3)
指针进阶(3)
43 1
|
5月前
|
C++
指针进阶(1)
指针进阶(1)
45 1
|
5月前
|
存储 安全 编译器
C++进阶之路:何为引用、内联函数、auto与指针空值nullptr关键字
C++进阶之路:何为引用、内联函数、auto与指针空值nullptr关键字
44 2
|
5月前
|
Java 程序员 Linux
探索C语言宝库:从基础到进阶的干货知识(类型变量+条件循环+函数模块+指针+内存+文件)
探索C语言宝库:从基础到进阶的干货知识(类型变量+条件循环+函数模块+指针+内存+文件)
49 0