目录

一.字符指针

1.1字符指针的认识

1.2字符指针存放字符串

1.3字符指针的使用

二.指针数组

2.1指针数组的认识

三.数组指针

3.1数组指针的认识

3.2数组名和&数组名的区别

3.3数组指针的使用

3.4数组参数,指针参数

3.5一维数组传参

3.6二维数组传参

3.7一级指针传参

3.8二级指针传参



一.字符指针

1.1字符指针的认识

字符指针的认识:其实很简单,跟其他类型类比一下就知道了,请看下面的代码。

#define _CRT_SECURE_NO_WARNINGS 1#include<stdio.h>
#include<stdlib.h>int main()
{int a = 10;        //定义一个整型变量printf("%d\n", a);int* p = &a;       //将变量a的地址存放的整型指针变量p中*p = 15;           //对p解引用改变a地址的内容,即把15换成10printf("%d\n", a);printf("-------------\n");char c = 'A';      //定义一个字符变量printf("%c\n", c); //将变量c的地址存放的字符指针变量pc中char* pc = &c;     对pc解引用改变a地址的内容,即把'A'换成'C'*pc = 'C';printf("%c\n", c);return 0;
}

跟整型指针类型用法一样,都是指针用来存放变量的地址,解引用改变地址的内容,不过是把类型不同,整型指针存放的是整型类型变量的地址,字符指针存放的是字符类型变量的地址。

1.2字符指针存放字符串

字符指针我们知道它可以存放一个字符变量的地址,那如果是存放的字符串会怎么样呢?

#define _CRT_SECURE_NO_WARNINGS 1#include<stdio.h>int main()
{char arr[] = "hello classmate!";printf("%s\n", arr);printf("%c\n",*arr);printf("----------------\n");const char* pstr = "hello classmate!";printf("%s\n", pstr);printf("%c\n", *pstr);return 0;
}

分析以上代码,你也会惊奇的发现,字符指针存放字符串变量的方式和数组的数组名表示首元素地址也很类似,根据上面代码我们具体分为上下两部分。

第一部分:定义了一个arr数组名的字符数组,数组名就是数组首元素地址,所以数组名arr就是字符‘h’的地址,而且我们字符串打印时一般都只需要输入数组名就可以打印字符串了,而这也说明了,字符串的打印只要给首元素的地址就可以进行字符串打印了。arr既然是首元素地址,对arr进行解引用就是首元素。

第二部分:跟第一部分极其类似,我们定义一个pstr的字符指针,用来存放字符串的地址,结果打印发现,pstr 存放的不是整个 "hello classmate" 的字符串的地址,存放的就是首字符 'h'的地址。

打印字符串和pstr解引用与上面的数组也是同一道理,就不赘述了。至于为什么要加const,是因为pstr存放的是常量字符串,既然是常量,所以就加const防止被修改。

1.3字符指针的使用

你先看一下代码,自己小小研究一番。

#include <stdio.h>
int main()
{char str1[] = "hello friend.";char str2[] = "hello friend."; const char *str3 = "hello friend.";const char *str4 = "hello friend.";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");return 0;
}

看完了?好的。首先,str1和str2我们都知道是数组首元素地址,然后你发现都是首字符‘ h ’的地址,可能会觉得相同str1 == str2,不要被这样的错觉蒙蔽你明亮的双眼。str1 和 str2 是两个数组,在内存开辟的是两块不同的空间,就算内容是一样的,地址也不可能一样,两者的首元素地址自然也不一样,所以str1 不等于str2。

再看字符指针str3,str4,存放都是字符' h '的地址,但因为str3和str4是指针。当指向同一个字符串的时候,他们实际会指向同一块内存,实际就是同一块地址,简单点讲就是,str3 和str4用的是同一块地址。

二.指针数组

2.1指针数组的认识

什么是指针数组呢,是数组呢还是指针呢,以后咱们就这样判断,谁放在后面就是谁,指针数组,数组放在后面,所以指针数组是数组,是用来存放指针的数组。

#include<stdio.h>int main()
{int arr1[10]; //arr1存放了10个元素,类型是整型char arr2[10];//arr2存放了10个元素,类型是字符型int* arr3[10];//arr3存放了10个元素,类型是整型指针char* arr4[10];//arr4存放了10个元素,类型是字符指针return 0;}

因为指针数组的内容很浅,所以这一点内容应该可以理解了,我们重点放在数组指针上。

三.数组指针

3.1数组指针的认识

数组是指针根据谁放在后面就是谁原则,所以数组指针是指针。那是用来干嘛的呢?我们知道

整形指针: int * pint ; 能够指向整形数据的指针。
浮点型指针: float * pf ; 能够指向浮点型数据的指针。
那数组指针应该是:int (*p)[10]能够指向数组的指针。
在此之前我们先判断一下以下代码:
int main()
{int *p1[10];int (*p2)[10];//p1, p2分别是什么?return 0;
}

我们要记得 [ ] 的优先级要高于 * 号的,所以p1是先和 [10]结合,类型是int*,意思就是p1是指针数组。

p2是先加上()来保证p2先和*结合。p先和*结合,说明p2是一个指针变量,然后指着指向的是一个大小为10个整型的数组。所以p2是一个 指针,指向一个数组,叫数组指针。

3.2数组名和&数组名的区别

因为了解数组指针之前,能区分数组名和&数组名还是很有必要的。

对于下面的数组:
int arr[10];
arr 和 &arr 分别是啥? 我们知道arr 是数组名,数组名表示数组首元素的地址。 那&arr 数组名到底是啥?
#include <stdio.h>
int main()
{int arr[10] = {0};printf("%p\n", arr);printf("%p\n", &arr);return 0;
}
运行结果如下:

可见数组名和&数组名打印的地址是一样的。 难道两个是一样的吗?

我们再看一下以下代码:

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

运行结果如下:

首先,我们要对数组名理解:
数组名是数组首元素的地址
有2个例外:
1. sizeof(数组名),这里的数组名不是数组首元素的地址,数组名表示整个数组,sizeof(数组名)计算的是整个数组的大小,单位是字节。
2. &数组名,这里的数组名表示整个数组, &数组名取出的是整个数组的地址。
除此之外,所有的地方的数组名都是数组首元素的地址。

所以根据上面的代码我们发现,其实 &arr 和 arr ,虽然值是一样的,但是意义应该不一样,实际上 &arr 表示的是整个 数组的地址 ,而不是数组首元素的地址。本例中 &arr 的类型是: int(*)[10] ,是一种数组指针类型,数组的地址+1 ,跳过整个数组的大小,所以 &arr+1 相对于 &arr 的差值是 40个字节.

3.3数组指针的使用

#include <stdio.h>
int main()
{int arr[10] = {1,2,3,4,5,6,7,8,9,0};int (*p)[10] = &arr;//把数组arr的地址赋值给数组指针变量preturn 0;
}

一般呢,数组指针更多是应用在二维数组传参。

#include <stdio.h>void print_arr1(int arr[3][5], int row, int col){int i = 0;int j = 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;int j = 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);printf("-----------------\n");//数组名arr,表示首元素的地址//但是二维数组的首元素是二维数组的第一行//所以这里传递的arr,其实相当于第一行的地址,是一维数组的地址//可以数组指针来接收print_arr2(arr, 3, 5);return 0;}

运行代码如下:

二维数组在传参时,函数既可以接收二维数组,也可以接收数组指针,因为二维数组的数组名时首元素地址,首元素不是一个变量,而是一个一维数组,所以可以用数组指针去接收。

如代码:

#include <stdio.h>

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;
    
}

3.4数组参数,指针参数

3.5一维数组传参

定义了一个数组和函数,在调用函数时放入数组名,函数接收时可以通过数组和指针的方式接收。因为数组在内存中时连续存放的,传入数组名,就可以知道首元素地址,再用指针接收首元素地址,就可以知道整个数组了,用数组接收数组名本质上也是指针接收

用一个简单的例子:

    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[10] = { 0 };test(arr);test2(arr2);}

按顺序解答:

main函数调用test函数传递了arr数组名。

void test(int arr[])//ok?  arr是数组,可以用数组接收。ok
    {}

void test(int arr[10])//ok? 同理,arr是数组,可以用数组接收。ok
    {}

void test(int* arr)//ok?  首元素地址可以用指针接收。ok

{}

main函数调用test2函数传递了arr2数组名。

void test2(int* arr[20])//ok? arr2是指针数组,可以用指针数组接收。ok的
    {}

void test2(int** arr)//ok? arr2首元素是一级指针,必须用二级指针接收。ok的
    {}

3.6二维数组传参

二维数组传参时,实际上传递的时首元素的地址,首元素素是一个一维数组。用数组指针去接收一维数组,也可以用二维数组接收(要记得本质上也是用指针接收)

void test(int arr[3][5])//ok?
{}
void test(int arr[][])//ok?
{}
void test(int arr[][5])//ok?
{}
void test(int *arr)//ok?
{}
void test(int* arr[5])//ok?
{}
void test(int (*arr)[5])//ok?
{}
void test(int **arr)//ok?
{}
int main()
{int arr[3][5] = {0};test(arr);
}
void test ( int arr [ 3 ][ 5 ]) // 传过去的一维数组地址,接收也用可以二维数组接收。ok的
{}  
void test ( int arr [][]) // 二维数组可以省略行,但是不能省略列。不ok
{}
void test ( int arr [][ 5 ]) // 跟上面同理,ok的
{}
void test ( int * arr ) // 传过来的是一维数组的地址,所以要用数组指针接收,不ok
{}
void test ( int* arr [ 5 ]) //别被迷惑了兄弟们,这是指针数组,不是数组指针,不ok
{}
void test ( int ( * arr )[ 5 ]) //确认是数组指针,ok的
{}
void test ( int ** arr ) //二级指针能接收的是一级指针,不能直接接收地址/不ok
{}

3.7一级指针传参

当函数的参数是一级指针时,调用时能传入什么样的参数?

1.单一变量地址,一级指针接收的是地址没什么问题。

void my_printf(char* str)
{printf("%c\n", *str);
}int main()
{char pc = 'K';my_printf(&pc);return 0;
}

2.数组名。因为数组名就是首元素地址;


void my_printf(char* str)
{printf("%s\n", str);
}
int main()
{char arr[] = "CSDN";my_printf(arr);return 0;
}

3.一级指针。用一个变量去接收数组名的地址,此时变量为一级指针,所以一级指针传参,一级指针接收。


void my_printf(char* str)
{printf("%c\n", *str);
}
int main()
{char cp = 'J';char* cpp = &cp;my_printf(cpp);return 0;
}

3.8二级指针传参

1.一级指针的地址。

void my_printf(char** str)
{printf("%c\n", **str);
}int main()
{char pc = 'A';char* pcc = &pc;my_printf(&pcc);return 0;
}

2.二级指针。

void my_printf(char** str)
{printf("%c\n", **str);
}int main()
{char pc = 'B';char* pcc = &pc;char** pccc = &pcc;my_printf(pccc);return 0;
}

3.指针数组。

void my_printf(char** str)
{printf("%s\n", *str);
}int main()
{char* arr[] = {"abcdef"};my_printf(arr);return 0;
}

好了,今天的内容就到这里了,如果能够帮助到看官,就希望看官给个三连支持一下吧!!!、

字符指针?指针数组?数组指针?《C语言指针进阶第一重奏》相关推荐

  1. c语言怎样统计数组的长度,C语言指针难吗?纸老虎而已,纯干货讲解

    原标题:C语言指针难吗?纸老虎而已,纯干货讲解 指针对于C来说太重要.然而,想要全面理解指针,除了要对C语言有熟练的掌握外,还要有计算机硬件以及操作系统等方方面面的基本知识.所以本文尽可能的通过一篇文 ...

  2. C语言中指针与数组的区别,C语言 指针与数组的详解及区别

    C语言 指针与数组的详解及对比 通俗理解数组指针和指针数组 数组指针: eg:int( *arr)[10]; 数组指针通俗理解就是这个数组作为指针,指向某一个变量. 指针数组: eg:int*arr[ ...

  3. c语言指针数组 难点总结,C语言指针与数组的难点分析.pdf

    C语言指针与数组的难点分析,c语言指针数组,c语言二维数组指针,c语言指针数组初始化,c语言函数指针数组,c语言数组与指针,c语言结构体数组指针,c语言指向数组的指针,c语言字符串数组指针,c语言数组 ...

  4. c语言获取指针分配的字节数,c语言指针知识点总结(共6篇).docx

    c语言指针知识点总结(共6篇) C语言指针教学中的知识点分析与总结 摘要:分析指针的基本概念及指针在数组.函数.字符串.动态存储分配等方面的应用,提出指针教学过程中易混淆概念及注意事项,对初学者深入理 ...

  5. 全国计算机二级考试c语言指针,全国计算机二级考试C语言 指针精讲课件.ppt

    全国计算机二级考试C语言 指针精讲课件 第七章:指 针;第一节:指针概述;如:执行以下说明语句后: int a=3,b=4; float c=4.5,d=8.6; char e='x',f='y';其 ...

  6. c语言前后指针怎么用,详解一下——C语言指针该怎么用

    上次貌似有写一篇指针的,详细介绍,那个比较很详细的,这一次简略的说下,以及运用到编程里面,对看这篇文章的亲们,希望能有所帮助吧 一.指针概述 1.指针 内存中每一个字节的编号即是地址,指针就是变量的地 ...

  7. c语言 指针函数 详解,[NOTE-C]C语言指针详解(一)

    C语言指针让一切想法变成可能,强转和指针可以看做一项呼风唤雨的利器,但是C语言中指针应用又需要格外的小心,其更灵活的利用内存,因为不当的应用可能引起各种异常,这篇文章就是让我们一起来认识C指针,更好的 ...

  8. 带你刷笔试关的小怪|详解指针习题和面试题【C语言/指针/进阶】

    文章目录 前言 9. 指针和数组笔试题解析 复习回顾 一维数组 字符数组 二维数组 10. 指针笔试题 笔试题1: 笔试题2 笔试题3 笔试题4 笔试题5 笔试题6 笔试题7 (#)笔试题8 结语 前 ...

  9. c语言指针和结构体难点,C语言指针和结构体

    第一章 指针 知识点1. a. 函数内的局部变量存在了STACK,全球变量存在了GLOBALS. b. 指针和变量一样,内容是地址 c. *variable = address d. &add ...

最新文章

  1. 三星的 Logo 原来是这么来哦! | 每日趣闻
  2. 从Matrix到这个idea
  3. 某金融产品妹纸:四种姿势教你跪舔程序员不要不要的
  4. 随机微分过程matlab求数值解,随机微分方程数值解.pdf
  5. [BUUCTF-pwn]——pwn2_sctf_2016
  6. @NotBlank注解地正确使用
  7. php全站文章搜索,Discuz X3.1全站文章全文检索的实现方法
  8. 绝对路径中“./”、“../”、“../../”代表的含义,包你一看就会
  9. XML(二)有效的XML: DTD(文档类型定义)介绍与三种使用方式
  10. Bing搜索背景图抓取
  11. 【图像分割】基于matlab随机游走算法图像分割【含Matlab源码 149期】
  12. 微软代码审查工具_Microsoft如何进行代码审查?
  13. win10无法装载iso文件_iso镜像安装失败无法安装Windows10解决教程
  14. java求闰年_Java判断闰年的2种方法示例
  15. Windows商店安装问题已解决 Xbox应用将改善游戏安装
  16. IOS图像2之jpg、png图片保存、互转、设置有损压缩因子
  17. VSCode ctrl+鼠标左键无法跳转,F12可以跳转
  18. jmete-jp@gc - Throughput Shaping Timer的使用
  19. 不知道怎么识别手写文字?快来看这些手写文字识别成文档软件
  20. 学微积,用手机,人人“知识共享”学真知

热门文章

  1. 解决chromium对html5 标签的 mp3 等视频音频网页的兼容性问题
  2. 如何解决Keil下出现error: L6050U: The code size of this image exceeds the maximum allowed for this versio
  3. 振幅整合脑电图aEEG绘制方法
  4. 搜索引擎case︱从搜索序列文本看高端商务车︱统计之都
  5. 退休计划失败,64岁高龄程序员重新开始工作
  6. win7 更新 未运行服务器,Win7系统无法启动iis服务器如何解决?
  7. DISPALYCLA色彩管理详解
  8. Jetpack Compose 中的架构思想
  9. ACCESS数据库不能在国外英文操作系统上运行
  10. 一分钟学会看k线图_教你一分钟怎样学会看k线图