zerglurker的C语言教程004——指针初步讲解

在上次的教程里面,我提到了指针。

针对指针,这次我将简单的讲讲,后面我还会讲到——那个时候你应该有了相当的基础。

首先,先讲讲指针类型。

任何类型关键字后面加一个*符号,就会变成指针类型。

比如:

char → char* 字符指针

int → int* 整数指针

double→double* 双精度指针

甚至还可以这样:

char*→char** 字符指针的指针类型
→char*** 字符指针的指针的指针类型…

指针本质上是一个内存地址值,该内存地址上存放的是相关类型的数值。但是void*指针类型例外,它指向的内存地址存放的不是void值。

由于现在的内存都很大,动不动都是上G。为了说明上面的情况,我假设存在一个16字节的内存如下图:

图中每个格子代表一字节内存,可以存放8个bit

依据上节教程说的,1个char变量a,它的尺寸大小是1字节。可以放在上面的任意一格,这里我假设放在第一格:

即 假如存在这样的情况

char a=‘z‘;

a的值‘z‘存放在第一格

然后char* pa = &a;

这里&运算符表示,取变量a的地址。

那么pa的值一定就是0

如果变量a在第二格,那么pa的值就一定是1

这就是说指针是一个地址值,它是由运行时变量的地址决定的。

由于指针也是一个值,所以指针变量也有长度。

在手机和嵌入式环境上,这个地址值通常是4字节

在PC环境上,这个值会随系统而变化:

windows: xp上是4字节 其他系统中,32位程序中是4字节 64位程序则是8字节

linux系统:ubuntu 一般是6字节(实际上是8字节,只是中间两个字节会做加法,最后合成一个6字节地址,形如:0xffff12345678这样的地址值)

Mac系统:同linux

在部分单片机,例如51单片机,plc单片机中,这个值甚至只有2字节,即只有64k内存寻址范围

在我上面假设的内存环境中,这个值只有半个字节0x0~0xF

既然指针变量是一个值,所以它也在内存中,也有地址。而要记录这个值,可以用一个指向指针的指针。

继续上面的假设

char** ppa = &pa;

加入pa的值存放在1的位置

那么ppa就等于1

即pa=0 ppa=1

当然实际上pa不一定会顺序存放在1的位置,也可能在其他位置,视程序实际运行的情况而定。

由于指针记录的是地址值,所以存在一种特别的指针void*

这种指针记录的仅仅是地址值,完全不能说明指向的是什么类型数据的地址。

但是这也有很大的好处,对于那些不关心数据类型的用户,这个指针就非常有用了。

例如下面的系统函数:

void* memset(void* dest,int val,int count);

该函数的作用是将指定的dest位置的内存,填充val,直到填满count字节

该函数不关心指定的dest是什么类型的地址,char的也好,int的也好,double也好,反正我就是往里面填入val,直到填满count字节为止。

所以这种时候,void*指针类型就非常好。

有鉴于此,所有的编译器都会提供一种默认的方便:即任何类型指针都可以转换为void*类型,编译器不会报错

比如

char* pa = &a;

memset(pa,1,1);

编译器不会报错,提示你pa的指针类型不对。而是默默的将其转换为void*类型。

本节主要初步讲解了指针,后面还会继续慢慢深入讲解指针。指针的变化非常多,应用也非常广。

ps:

编译器还会默默的进行下列转换:

char→int

short→int

上述的unsigned版 unsigned char→unsigned int

时间: 2024-12-19 13:51:07

zerglurker的C语言教程004——指针初步讲解的相关文章

Swift3.0语言教程使用指针创建和初始化字符串

Swift3.0语言教程使用指针创建和初始化字符串 Swift3.0语言教程使用指针创建和初始化字符串苹果的Swift团队花了不少功夫来支持C的一些基础特性.C语言中为我们提供了指针,Swift也不例外,开发者可以使用指针去创建和初始化字符串. (1)在NSString中init(bytes:length:encoding:)方法可以从给定字符串按照指定获取方向,得到指定个数的字符,然后使用这些字符创建和初始化字符串.其语法形式如下: convenience init?(bytes: Unsaf

zerglurker的C语言教程009——运算符详解(一)

在之前几节我们讲过数据类型.讲过函数.讲过代码执行顺序以及一些添加简单函数的方法. 这一节我们将着重讲讲运算符.包括运算符的含义以及优先级的概念 在C语言中,以下运算符是被公认的: C/C++语言运算符详解 优先级 运算符 名称以及含义 运算目 使用示例 结合方向 可否重载 附加说明 无 () 圆括弧 单目 (表达式) 无 否 括弧内的表达永远先计算 无 dynamic_cast<>() 类型动态转化 单目 dynamic_cast<目标类型>(源) 无 否 C++专有,不能转换返

zerglurker的c语言教程006——第一功能

行,以往的经验教训后,.成员main性能.变数.命名等基本概念应该有一个初步的了解 下面,我们就可以开始我们自己的第一个定义的函数. 仿照头等舱.操作的第二个教训.添加一个新的项目的解决方案Lession006 第一课main.cpppublic.h复制过来 然后例如以下图示意的那样增加到项目中来: 右键单击项目 在加入栏 选择现有项 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemVyZ2x1cmtlcg==/font/5a6L5L2T/fonts

zerglurker的C语言教程002

经过上节课,大家现在已经有了一个可运行的C语言程序.相关代码和开发环境. 也许你会有一点疑问,为什么是建立main.cpp而不是main.c 另外,printf是什么?main是什么?#include是什么? 嗯,不要急,这些问题我都会慢慢告诉你们. 通过上节课的内容,我们知道代码要想编程程序,是需要一个工具的. 在windows下面,该工具vs提供了:而在linux下面,该工具叫做gcc. 这个工具,就是我们后面会提到的,称为编译器的东西.因为它将源代码编码转译为可运行文件,所以叫做编译器.

zerglurker的C语言教程008——循环语句详解

上节课我们提到了程序语句的三大执行顺序:顺序执行.条件执行和循环执行 今天我们详细讲讲循环执行,不废话,先上代码和运行效果 首先来一段示例代码,老规矩,新建一个空项目(参考006课) 新建一个空的main.cpp和public.h public.h里面定义代码如下: void LargeDistributionSequence(unsigned int nLength); main.cpp代码如下: #include <stdio.h> #include "public.h"

zerglurker的C语言教程010——运算符详解(三)

同上节课,请参考运算符总览 本节主要讲讲sizeof 也许有的资料提到过C++的typeid,但是这个根本不是运算符,而是一个类,有文件定义的 所谓运算符必须是无需头文件即可使用的符号.如果要使用一个运算符,还需要头文件,那么这个运算符就不是基本的运算符,是开发人员重载或者自己写的. 从这个角度看typeid就不是运算符,而是微软自定义的. 运算符的另一个特点是,对常量进行操作,编译阶段就会进行处理. 比如 int a = sizeof(int) ; 编译器会在编译的时候直接将4用来初始化a.所

zerglurker的C语言教程010——运算符详解(二)

首先,请参考上节课我们提到的运算符总览 今天我们主要讲解下面几个运算符: ()圆括弧运算符 {}组合运算符 ::作用域解析 throw运算符 ,逗号运算符 ()圆括弧运算符 使用示例: a*(b+c) (b>=a)&&(c<=a) (a%(b/c))*d 特点说明: 1 圆括弧拥有优先执行权限.即运算表达式时,优先运算圆括弧内的表达. 2 圆括弧可以嵌套,嵌套时内部的圆括弧拥有更高的优先级. 注意: 由于()作为圆括弧运算符的时候,里面的表达式不可以为空,也不可以有多个语句,所

zerglurker的c语言教程——命名规则

今天讲讲C/C++中的命名规则 命名规则或者说命名限制可以应用于函数命名.变量命名.常量命名.结构体命名.自定义类型命名以及C++中类命名.对象命名.模板类或对象命名等等 第一条:名称的第一个字符只能是字母或者下划线. int _,_a,A1,_9;//合法 int 1_a,1_,$S;//非法 注意:只有一个下划线的名称,在C/C++中是一个合法的名称! 第二条:名称中可以包含数字 第三条:名称中不能包含除了下划线.字母和数字之外的其他符号 第四条:名称是大小写敏感的 也就是说name和NAM

zerglurker的C语言教程007——代码运行的顺序

软件开发中.代码有三种基本运行顺序: 顺序运行 代码从入口開始一条一条运行.直到返回或者结束 循环运行 在设定条件后,代码反复运行某一个或多个部分,直到达到某些条件后终止 条件运行 代码会先推断某些条件,假设满足则运行部分代码,假设不满足则运行还有一部分代码 实际其中,这三种运行顺序是交错出现的.你中有我,我中有你. 以下是上节课的代码,我们来一句一句的分析看.你就会明确我上面说的是什么了: #include <stdio.h> #include "public.h" in