热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

C语言中的指针详解

1.什么是指针C语言中指针是一种数据类型,指针是存放数据的内存单元地址。计算机系统的内存拥有大量的存储单元,每个存储单元的大小为1字节,

1. 什么是指针

C语言中指针是一种数据类型,指针是存放数据的内存单元地址。

计算机系统的内存拥有大量的存储单元,每个存储单元的大小为1字节,为了便于管理,必须为每个存储单元编号,该编号就是存储单元的“地址”,每个存储单元拥有一个唯一的地址。

指针变量除了可以存放变量的地址外,还可以存放其他数据的地址,例如可以存放数组和函数的地址。


2. 指针的定义和初始化

格式:数据类型符 *指针变量名[=初始地址值]。

功能:定义指向“数据类型符”的变量或数组的指针变量,同时为其赋初值。

定义说明:

1. “*” 表示定义的是一个指针变量,指针变量的前面必须有 “*” 号;

2. 在定义指针变量的同时也可以定义普通变量或数组等其它变量;

3. “数据类型符” 是指针变量所指向变量的数据类型,可以是任何基本数据类型,也可以是其他数据类型;

4. “初始地址值” 通常是 “&变量名” “&数组元素” 或 “一维数组名”,这里的变量或数组必须是已定义的;

5. 在定义指针变量时,可以只给部分指针变量赋初值;

6. 指针变量的初始化,除了可以是已定义变量的地址,也可以是已初始化的同类型的指针变量,也可以是NULL(空指针);

7. 指针变量初始化时,指针变量的“数据类型符”必须与其“初始地址值”中保存的数据的类型相同;

8. 不能用auto类型的地址去初始化static型指针。


3. 指针变量的使用

1. 给指针变量赋值

格式:指针变量=地址型表达式

“地址型表达式”即运算结果是地址型的表达式。C语言规定,变量地址只能通过取地址运算符获得,即“&”,其运算对象是变量数组元素名,运算结果是对应变量或数组元素的地址。

需要注意的是,虽然地址是一个整数,但是C语言中不允许把整数看成“地址常量”,所以此处的“地址型表达式”不能是整数。

2. 使用指针变量

格式:指针变量名

需要使用地址时,可以直接引用指针变量名。

3. 通过指针变量引用所指向的变量

格式:*指针变量名

“*指针变量名” 代表其指向的变量或数组元素,其中的“*”称为指针运算符。需要注意的是,这种引用方式要求指针变量必须已经定义且有值。


4. 指针的基本运算

1. 取地址运算符 &

取地址运算符“&”的功能是取变量的地址,它是单目运算符。取地址运算符的运算对象必须是已经定义的变量或数组元素,但不能是数组名。运算结果是运算对象的地址。

2. 指针运算符 *

指针运算符“*”的功能是取指针变量所指向地址中的内容,与取地址运算符“&”的运算是互逆的,它是单目运算符。指针运算符的运算对象必须是地址,可以是已赋值的指针变量,也可以是变量或数组元素的地址,但不能是整数,也不能是非地址型的变量。运算结果就是地址对应的变量。

 取地址运算符和指针运算符的优先级和结合性:

1. 取地址运算符、指针运算符和自增、自减等单目运算符的优先级相同;

2. 所有单目运算符的结合性为从右至左。


5. 指针的算术运算

指针变量可以进行的算术运算包括:

1. 指针变量 ± 整数;

2. 指针变量++ ++指针变量;

3. 指针变量-- --指针变量;

4. 指针变量1- 指针变量2;

由于指针运算符*与自增运算符++、自减运算符--的优先级相同,结合方向都是从右至左,因此需要注意以下各种形式的含义不同。


6. 指针的关系运算

两个类型相同的指针变量可以运用关系运算符比较大小,表示两个指针变量所指向地址位置的前后关系,即:前者为小,后者为大

需要注意的是,如果两个指针变量不是指向同一个数组,则比较大小没有实际意义。


7. 指针变量的引用

1. 通过指针变量访问整型变量

2. 指针变量作为函数参数

普通变量作为函数的参数传递时是按值传递,实参与形参不共享内存。指针变量作为函数参数时是地址传递,共享内存,“双向传递”。

以下是按值传递的情况:

 以下是按地址传递的情况:



8. 指针和数组

数组的指针是指向数组在内存的起始地址,数组元素的指针是指向数组元素在内存的起始地址。

1. 当指针变量指向一维数组,可以采用以下两种方法:

(1). 在数据定义语句中用赋初值的方式:*指针变量=数组名;

(2). 在程序中用赋值的方式:指针变量=数组名;

2. 当指针变量指向一维数组元素,可以采用以下两种方法:

(1). 在数据定义语句中用赋初值的方式: *指针变量=&数组名[下标];

(2). 在程序中用赋值的方式: 指针变量=&数组名[下标];

3. 当指针变量指向一维数组,利用指针变量引用一维数组元素的方法如下:

(1). 引用下标为0的数组元素:*(指针变量+0) *指针变量指针变量[0];

(2). 引用下标为 i 的数组元素:*(指针变量+i) 等同于 指针变量[i] 或者 指针变量[i] 等同于 数组名[i];

4. 当指针变量指向一维数组元素,利用指针变量引用数组元素的方法如下:

(1). 引用下标为 i 的数组元素:*(指针变量 + 0)*指针变量;

(2). 引用下标为 i-k 的数组元素:*(指针变量 - k);

(3). 引用下标为 i+k 的数组元素:*(指针变量 + k);

上面的总结文字看起来有枯燥,下面两张图看起来会更生动和形象一些。

 还有下面这张:


9. 指针和字符串

将指针变量指向字符串的方法如下:

1. 在数据定义语句中用赋初值的方式:*指针变量=字符串;

2. 在程序中用赋值的方式:指针变量=字符串;

需要注意的是,这两种方法并不是将字符串赋予指针变量,而是将存放字符串的连续内存单元的首地址赋予指针变量。

当指针变量指向字符串时,则可以利用指针变量处理字符串,处理方式有以下几种:

1. 处理整个字符串

(1). 输出整个字符串:printf("%s",指针变量);

(2). 输入整个字符串:scanf("%s",指针变量);

#include "stdio.h"
int main(){char *string = "I love China";printf("%s",string);// I love Chinareturn 0;
}

2. 处理字符串中的单个字符

(1). 输出整个字符串:printf("%c",指针变量);

(2). 输入整个字符串:scanf("%c",指针变量);

#include "stdio.h"
int main(){char *string = "I love China";for(;*string!='\0';string++){printf("%c",*string);// I love China};return 0;
}

C语言中,字符串是按字符数组进行处理的,系统存储一个字符串时先分配一个起始地址,从该地址开始连续存放字符串中的字符,这一起始地址即字符串首字符的地址。所以,可以将一个字符串赋值给一个字符数组,也可以赋值给一个字符指针变量。

常见的字符串的表现形式如下:

1. 用字符数组表示字符串

2. 用字符指针表示字符串

3. 用下标存取字符串中的字符

字符指针和字符数组的区别:

1. 存储内容不同;

2. 赋值方式不同;

3. 字符指针变量在定义后应先赋值才能引用;

4. 指针变量的值是可以改变的,字符指针变量也不例外;而数组名代表数组的首地址,是一个常量,而常量是不能改变的。



10. 指针和函数

指针变量既可以作为函数的形参,也可以作为函数的实参。指针变量作为函数参数,形参和实参之间的数据传递方式本质上是值传递,只是在调用函数时传递的内容是地址,这样使得形参变量和实参变量指向同一个变量。若被调函数中有对形参所指变量内存的改变,实际上是改变了实参所指变量的内容。

数组名作为函数形参时,接收实参数组的首地址;数组名作为函数实参时,将数组的首地址传递给形参数组。

引入指向数组的指针变量后,数组及指向数组的指针变量作为函数参数时,可有四种等价形式:

1. 形参、实参均为数组名;

 2. 形参、实参均为指针变量;

3. 形参为指针变量、实参为数组名;

 4. 形参为数组名、实参为指针变量

C语言中,函数可以返回整型、实型、字符型数据,也可以返回指针类型数据,即返回一个地址。指针型函数是指函数的返回值是指针型,即这类函数的返回值必须是地址值,调用该类函数时,接收返回值的必须是指针变量、指针数组元素等能够存放地址值的对象。

定义指针型函数的格式和有返回值的函数的定义格式基本相同,唯一的区别是在函数名前面加一个“*”,表示函数的返回值是指针型数据。

指针型函数的调用和一般函数的调用方法完全相同,但需要注意的是只能使用指针变量或指针数组元素接收指针型函数的返回值,不能使用数组名接收指针型函数的返回值,因为函数名是地址常量,不是地址型变量,不能接收地址型变量数据。


11. 指针数组

指针数组是数组中的元素均为指针变量。

格式:数据类型符 *指针数组名[数组长度]。

功能:定义指针数组,有“长度”个数组元素。

定义说明:

1. 指针数组名是标识符,前面必须加“*”号;

2. 定义指针数组的同时可以定义普通变量、数组和指针变量等;

3. “数据类型符” 可以是任何基本数据类型,“数据类型符”不是指针数组元素中存放的数据类型,而是其所指向数据的数据类型。

指针数组的初始化

1. char *ps[]={"China","America","Russia",NULL};

定义了一个用于指向字符型数据的指针数组ps,其长度为4,同时对指针数组元素赋初值,前面三个是字符型指针,最后一个是空指针。

2. int a[3][3]={1,2,3,4,5,6,7,8,9}; int *p[3]={a[0],a[1],a[2]};

利用二维数组元素初始化指针数组p,其长度为3,分别指向二维数组a中的三个一维数组的首地址。

指针数组元素的赋值

1. 将数组名赋予指针数组各元素

char s[4][20]={“China”,”America”,”Russia”,NULL}; char *p[4]; p[0]=s[0];

给指针数组元素p[0]赋值s[0],s[0]是字符串“China”的首地址。

2. 将字符串直接赋予指针数组元素

char *p[4]; p[0]=“China”;

直接给指针数组元素p[0]赋值为字符串“China”的首地址。

指针元素的使用

指针数元素的使用和指针变量的使用完全相同,可以对其赋予地址值,可以利用其引用所指向的变量或数组元素,也可以参与运算。

 指针元素应用实例

1. 指针在整形二维数组中的使用

 2. 定义三个国家的名称,将国家名称按字母顺序排序后输出。


推荐阅读
  • 本题来自WC2014,题目编号为BZOJ3435、洛谷P3920和UOJ55。该问题描述了一棵不断生长的带权树及其节点上小精灵之间的友谊关系,要求实时计算每次新增节点后树上所有可能的朋友对数。 ... [详细]
  • 本文介绍如何从字符串中移除大写、小写、特殊、数字和非数字字符,并提供了多种编程语言的实现示例。 ... [详细]
  • 在高并发需求的C++项目中,我们最初选择了JsonCpp进行JSON解析和序列化。然而,在处理大数据量时,JsonCpp频繁抛出异常,尤其是在多线程环境下问题更为突出。通过分析发现,旧版本的JsonCpp存在多线程安全性和性能瓶颈。经过评估,我们最终选择了RapidJSON作为替代方案,并实现了显著的性能提升。 ... [详细]
  • 丽江客栈选择问题
    本文介绍了一道经典的算法题,题目涉及在丽江河边的n家特色客栈中选择住宿方案。两位游客希望住在色调相同的两家客栈,并在晚上选择一家最低消费不超过p元的咖啡店小聚。我们将详细探讨如何计算满足条件的住宿方案总数。 ... [详细]
  • JSOI2010 蔬菜庆典:树结构中的无限大权值问题
    本文探讨了 JSOI2010 的蔬菜庆典问题,主要关注如何处理非根非叶子节点的无限大权值情况。通过分析根节点及其子树的特性,提出了有效的解决方案,并详细解释了算法的实现过程。 ... [详细]
  • 本题要求实现一个函数,用于检查给定的字符串是否为回文。回文是指正向和反向读取都相同的字符串。例如,“XYZYX”和“xyzzyx”都是回文。 ... [详细]
  • 深入解析Java枚举及其高级特性
    本文详细介绍了Java枚举的概念、语法、使用规则和应用场景,并探讨了其在实际编程中的高级应用。所有相关内容已收录于GitHub仓库[JavaLearningmanual](https://github.com/Ziphtracks/JavaLearningmanual),欢迎Star并持续关注。 ... [详细]
  • 深入解析Java虚拟机(JVM)架构与原理
    本文旨在为读者提供对Java虚拟机(JVM)的全面理解,涵盖其主要组成部分、工作原理及其在不同平台上的实现。通过详细探讨JVM的结构和内部机制,帮助开发者更好地掌握Java编程的核心技术。 ... [详细]
  • 深入解析Spring启动过程
    本文详细介绍了Spring框架的启动流程,帮助开发者理解其内部机制。通过具体示例和代码片段,解释了Bean定义、工厂类、读取器以及条件评估等关键概念,使读者能够更全面地掌握Spring的初始化过程。 ... [详细]
  • 实用正则表达式有哪些
    小编给大家分享一下实用正则表达式有哪些,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下 ... [详细]
  • 本文介绍如何利用栈数据结构在C++中判断字符串中的括号是否匹配。通过顺序栈和链栈两种方式实现,并详细解释了算法的核心思想和具体实现步骤。 ... [详细]
  • Linux环境下C语言实现定时向文件写入当前时间
    本文介绍如何在Linux系统中使用C语言编程,实现在每秒钟向指定文件中写入当前时间戳。通过此示例,读者可以了解基本的文件操作、时间处理以及循环控制。 ... [详细]
  • 在尝试使用C# Windows Forms客户端通过SignalR连接到ASP.NET服务器时,遇到了内部服务器错误(500)。本文将详细探讨问题的原因及解决方案。 ... [详细]
  • 深入解析动态代理模式:23种设计模式之三
    在设计模式中,动态代理模式是应用最为广泛的一种代理模式。它允许我们在运行时动态创建代理对象,并在调用方法时进行增强处理。本文将详细介绍动态代理的实现机制及其应用场景。 ... [详细]
  • 为了解决不同服务器间共享图片的需求,我们最初考虑建立一个FTP图片服务器。然而,考虑到项目是一个简单的CMS系统,为了简化流程,团队决定探索七牛云存储的解决方案。本文将详细介绍使用七牛云存储的过程和心得。 ... [详细]
author-avatar
262610
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有