c语言指针范文

时间:2023-03-18 18:05:58

c语言指针

c语言指针范文第1篇

指针是C语言的一个最重要的特征,它提供了一种统一的方法,使其能访问远程的数据结构。但对C语言初学者而言,在编程过程中熟练的使用指针并不能像使用int型变量一样地轻松愉快,容易上手,往往是不得其精髓。我们知道,不论什么时候,运行一个程序A,首先都是操作系统自身的加载器把A装入内存,然后CPU才能执行。所以A程序的所有要素都会驻留在内存的某个位置。

下面我们看一段示例程序。

#include

intcmp(int first, int second)

{

return ( first > second ? first : second );

}

int main(intargc, char **argv)

{

inti = 5;

int j = 9;

returncmp(i, j);

}

首先,编译器会为变量i和j开辟内存空间,用来存储i和j的值。同时也会为函数cmp开辟空间来存放其代码。这样使得最终的可执行程序就变为了跟内存一一对应的序列。操作系统的加载器把这个可执行程序载入内存后,cpu就可以按一条条的语句顺序执行了。

既然内存空间同程序的所有要素是一一对应的,那么怎么区分各要素的存放位置呢?内存使用不同的地址存放不同的要素,如下所示。

由于变量都存放于内存地址空间,并且与地址之间是一一对应的,那么利用地址能做些什么呢?我们可以把地址存放到别的变量中,以便我们可以在以后程序的某个地方使用它。C语言有一个专门用来存储内存地址的变量,这就是指针变量,通常我们称之为指针(pointer)。它是一种变量类型,这种变量方便我们把需要操控的内存地址记忆起来。

定义指针

定义指针的运算符同乘法运算符是一样的,都用“*”表示。定义一个指针变量在语法上是简单的,同我们定义其他变量的区别是:首先规定它指向的变量类型,然后并不是立即就给出其变量的标识符,而是在变量类型同变量标识符之间插入指针运算符(星号),这样就告诉编译器这是一个指针变量。

C语言中指针可以指向任何的数据类型,包括函数。函数指针的定义是:函数返回值+(* + 函数指针变量标识符)+(函数的参数列表)。函数指针能构建出更加清晰的程序结构。编程中经常使用的指针定义就是这两种,当然有些定义可能只是语法上面有意义,但是语义上面不一定有具体的意义。例如,int *(*(*(*f)())[])()声明f是一个函数指针,该函数返回一个指针,该指针指向数组,该数组元素是指针,那些指针指向返回值类型为整型指针的函数。这样的声明可能永远也不能应用到实际的代码中。

指针和数组

数组是内存中一段连续相同类型的内存数据,这组数据的首地址以数组名字来标识。所有数组对其数据的操控都可以使用指针来实现,同理,指针指向一段内存数据时,也可以使用数组下标的方式来实现操作。

数组与指针在使用上的某些地方是非常相似的,但是数组与指针又有一些细小的区别。数组名表现为一个静态指针,也可以直接把它赋值给指针变量,但它的大小与指针通常是不同的。数组名的内涵在于其指代的实体是一种数据结构,这种数据结构就是数组。数组名可以作为参数传入一个接受参数为指针的函数内部,但是此时数组完全丢失了数组的本义,变成了完全的指针类型,其常量特性(可以作自增、自减等操作)可以被修改。并且,数组名不能再重新赋值为其他的数组名字,而指针变量是可以被重新赋值并指向一段新的内存地址的。

指针的运算

指针的运算指的是指针的--、++、-和+运算,一个指针可以加上或者减去一个整数。两个指针相减得到的是指针之间相隔的元素个数。不同的指针变量之间进行相加运算尽管在语法上是合理的,但是从语义上来讲是没有意义的。除了void型指针和函数指针以外,所有其他类型的指针都可以进行指针运算。通过指针变量的增加或减少,指针变量会指向新的内存地址。

一般来说,指针变量自身的大小在理论上是指机器的字长,但是指针变量的运算并不是按照指针变量自身的大小进行内存偏移的,而是按照指针变量指向的变量类型大小进行内存偏移的。比如,声明一个整形的指针p,假定p的地址是0x4323672,那么++p后p的值变为0x43236726。偏移的内存大小等于整形变量的内存大小4(sizeof(int))。同理,double型指针进行++运算后偏移值就是8(sizeof(double))。

指针强转

如同整形变量可以强转为浮点型变量一样,指针类型也可以通过强转变成新的指针类型,比如我们可以把整形指针强转为字符型指针。指针强转最诱人的地方就在于对内存数据进行操控就够了。指针强转使得指针对数据的操控更具有针对性,而且通过指针的默认强转可以使得函数的参数更简单,且传递的信息量是不变的。比如,void*作为参数时可以把任意的指针变量传递到函数内部进行相关的操作。

下面我们来看一个具体的例子。数据的内存布局如下图所示,首先是一个字符型数据,紧接着的是两个整形数据,最后面是三个结构体A型数据。我们需要做的就是把这些数据读出来。

我们先声明一个字符型的指针p,使其指向第一个数据的内存地址。取完第一个字符型数据后,通过p++,然后强转指针为整形指针,就可以很方便地取出整形数据,同理可取出三个结构体数据。

指针作为参数

先看一个例子,我们有两个整形变量,x的值为777,y的值为888,现在想构建一个函数用来交换两个整形变量的值,使得x的值为888,y的值为777。首先我们以传值的方式构建

voidswap_value(int Param1,int Param2)

{

int Temp = Param1;

Param1 = Param2;

Param2 = Temp;

}

我们调用函数swap_value(x,y)后,发现x、y的值并没有被交换。造成这种结果的原因是由于函数调用时,首先对传入的实参进行变量的拷贝,交换的值是形参的值,并不是实参的值。而原来的实参与拷贝后的形参变量所处的内存也不同,所以并没有交换成功。

要想实现函数内部对这两个值的交换,必须使得实参与拷贝后的形参变量所处的内存是相同的。我们知道了原理后,修正函数参数列表,以指针的方式重新构建函数如下:

voidswap_value(int*Param1,int*Param2)

{

int Temp=*Param1;

*Param1=*Param2;

*Param2=Temp;

}

这时候我们发现x、y的值被交换了。通过上面的例子可以看出,使用指针作为参数可以修改原来的变量值,使得函数实现的机能更加模块化,方便了程序的设计。

野指针

前面我们已经讨论过指针变量同内存的关系,了解了指针变量里面存放的是某个变量的内存地址,该地址可以在程序的某个位置使用,以方便我们更改或取得该变量的值。指针使得我们拥有了操控内存的利器,但同时指针也是一把双刃剑。我们必须时刻确保指针变量的值是我们意图操控的内存地址。如果指针变量的值被不受控的更改或者初始化不正确,那么我们就使用了错误的地址,从而导致程序错误,通常我们称这个导致程序错误的指针变量为野指针。由于使用了野指针而产生的程序错误大多时候是隐蔽的,难于跟踪的。野指针的产生主要是由于以下几种情况。

(1)声明了指针变量,但是没有正确的初始化就使用了该指针变量。

(2)使用指针变量之前没有对其进行安全检查。

(3)指针指向的内存变为了无效值,但没有及时对指针清零,导致程序某处引用了该指针。

(4)多个指针同时指向同一内存区域,程序某处通过某个指针释放了该内存,但是没有及时对其他的指针清零,导致程序某处进行了错误的引用。

(5)多线程时,对全局的指针变量没有进行锁处理。

多级指针

定义一级指针我们使用一个‘*’,在定义多级指针时,是几级指针我们就使用几个‘*’。例如,声明一个整型的二级指针(int ** ppVar;)。下面以这个二级指针为例说明一下二级指针的意义。

二级指针变量同样是保存了一个地址,这个地址就是某个一级指针变量的地址,而一级指针变量里面保存了最终需要操作的变量的地址,如下所示。

0x4323640 0x4323668

二级指针变量的值为0x4323640,就是一级指针变量pVar的地址,变量pVar的值为0x4323668,就是变量Var的地址。如果需要修改变量Var的值,我们可以直接修正**ppVar的值就可以了。

三级指针或者更多级指针的原理与二级指针的原理是相同的,只是需要索引的内存空间的深度增加了。在程序设计中,引入多级指针更多的时候并不仅仅是为了关注最后一级指针所能取得的变量,而更多的是为了使用和操控其中间的级数的内存值。比如利用二级指针作为函数的参数在某个函数内部对其分配内存,我们更想利用的是一级指针变量自身。当然,在进行程序设计时,有时我们要在可读性与语法有效性之间做出选择,在实现代码的过程中能用低级指针实现的尽量不要使用多级指针实现,这样的代码更利于维护。

小结

在C语言中指针的使用非常的广泛,有时指针是实现某个计算的唯一方法。同样的机能使用指针通常也可以获得更加高效、紧凑的代码。指针使得函数构建的机能更加的模块化,使得函数参数栈更加的短小。同时在操纵字符串的运算中,指针更加简单直观。

在大项目构建时,把函数指针同数据封装在一起能够使得代码编程面向对象的结构,使得后期代码的维护成本大大降低,代码的表现也更加具有现实意义。

c语言指针范文第2篇

关键词 C语言 运算 指针

指针是C语言最强大的功能,也是C语言中最难以掌握的功能。掌握指针的应用,可以使程序简洁、高效。每一个学习和使用C语言的人,都应当深入的学习和掌握指针。指针算术运算是指针操作中比较难掌握的部分。在本文中,我们将总结C语言的指针运算。

指针可以执行的算术运算有:①指针自增;②指针自减;③指针加上一个整型常量或整型变量n;④指针减去一个整型常量或整型变量n;⑤两个指针相减。

需要注意的是,通常只有当指针指向某个数组元素时,才对指针作上述5种算术运算。

一、指针自增

指针自增就是指向本数组的下一个元素。

假设有数组定义如下:double a[5] = {3.2, 4.75, 7.2, 9, 1.7};

double *p = a;

此时内存图示如下:

此时若执行p++,指针p指向数组的下一个元素,图示如下:

二、指针自减

指针自减就是指向本数组的上一个元素。

例如有数组定义如下:double a[5] = {3.2, 4.75, 7.2, 9, 1.7};

double *p = &a[4];

内存图示如下:

此时若执行p--,指针p指向数组的上一个元素,图示如下:

三、指针加上一个整型常量或整型变量n

指针加上一个整型常量或整型变量n的结果是得到一个指向本指针所指向的数组元素之后第n个元素的指针。例如数组定义如下:

double a[5] = {3.2, 4.75, 7.2, 9, 1.7};

double *p = a;

此时指针p指向数组a的第一个元素。

若执行 p = p + 3,指针p指向数组元素a[3]

四、指针减去一个整型常量或整型变量n

指针减去一个整型常量或整型变量n的结果是得到一个指向本指针所指向的数组元素之前第n个元素的指针。

若有定义 double a[5] = {3.2, 4.75, 7.2, 9, 1.7};

double *p = &a[4];

指针p指向数组元素a[4]。

如果执行p = p - 3之后,指针p指向数组元素a[1]

五、两个指针相减

首先必须明确,通常只有当两个指针指向同一个数组时才对两个指针相减。

两个指针相减得到的整数是这两个指针所指向的元素索引值之差。

例如有如下代码:

int a[5] = {10, 20, 30, 40, 50};

int *p1 = a;

int *p2 = &a[3];

int x = p2 - p1;

因为p1和p2位置如下:

所以表达式 p2 - p1的值是3

结语:指针算术运算是初学者感到比较困惑的问题,希望本文能对他们有所帮助。

作者简介:

c语言指针范文第3篇

【关键词】C语言 指针 反汇编 间接寻址 寄存器 栈

1 引言

C语言诞生于20世纪70年代的美国贝尔实验室,它是面向过程的,可移植的,功能强大的高级程序设计语言。尽管现如今有许多功能更强大的面向对象的高级程序设计语言(如C++,Java,C#等),C语言仍然具有旺盛的生命力,其仍是计算机领域的通用程序设计语言,特别是在底层的硬件驱动领域。这一切都要归功于指针,指针是C语言最重要的特性之一,利用它可以直接操作硬件,这是它的优点,也是它的缺点,因为直接操作硬件稍有不慎,就会导致非常严重的后果。

2 C语言指针简介

现代计算机中大部分都是按字节划分内存的,每个字节都有唯一的地址,C语言中的所有指针操作都是基于这些地址的。在C程序中一个变量会占用一个或多个字节,第一个字节的地址就是该变量的地址,将该地址赋值给某个变量后,就称其为指针。指针在C程序开发过程中发挥着举足轻重的作用,其基本应用有如下三点:

2.1 指向基本数据类型

假设我们定义int i = 10,则我们就占用了4个字节的内存(假设是在32位架构下),这4个字节就和变量名i建立了某种特殊联系,就可以通过该变量i对这4个字节进行读写操作。或者可以通过指针方式操控这4个字节。定义int*p = &i,就将该变量的首地址赋值给了指针变量p。然后就可以通过*p,对这4个字节进行读写操作。此时*p和i是完全等价的,即*p是变量i的别名。这是指针最基础的应用。

2.2 当指针作为函数参数时,它就可以发挥出强大的作用,特别是在数组,字符串,文件等的处理中

主要作用有如下两点:

2.2.1 让函数返回多个值。假设有如下函数声明

int foo(double * a,double * b);

则我们可以在函数内部修改a和b,在函数返回时,除了返回一个整型值外,还可以返回这两个被修改过的浮点数。假如不希望修改这两个浮点数,可以加上const修饰,如下所示:

int foo(const double *a,const double *b);

则在函数内部就不可以对变量a和b进行修改。这种技术在字符串处理函数中应用的特别多,是因为不希望源字符串被误改。例如:

char * strcpy(char *dest,const char *src);

2.2.2 节约内存空间,提高运行速度

在函数间传递数组,结构体或文件时,如果像传递普通变量那样,将参数复制一个副本到函数栈帧,就会给程序带来很大的开销,浪费空间和时间,因为这几个变量不再像普通变量那样只占几个字节,特别是文件通常都是很大的,从几K到几百M。这时最好的解决方法就是把该结构体变量或文件的地址传递出去,即多个函数操作的是同一个内存块。

2.3 指针还可应用于动态内存分配,从而修补数组在程序运行期间无法动态改变大小这一缺陷。动态内存分配主要用于构建链表,数,图等数据结构

但指针的操作需要很仔细,稍有疏忽就会导致程序崩溃。例如当我们申明了一个指针,而没有及时初始化,此时它就是一个野指针,对野指针指向的位置进行读写就会导致程序出错,因为有可能程序关键部分被无意修改了。再比如在某个函数内部动态申请一块内存,但在函数退出之前却忘记了及时的回收它,就会导致指向那块内存的指针丢失,即程序失去了对那块内存的控制,但那块内存仍然被占用着,如果继续重复执行该函数,就会导致内存大量被占用,而无法释放,直到系统崩溃。还有就是我们动态申请内存时,没有判断申请是否成功(即判断是否为NULL),而刚好此时系统无法提供我们所需的内存块,就直接操作指针,也会导致程序出错。正是基于这方面的考量,后来许多基于C语言发展起来的语言(如Java,C#),都舍弃了指针操作。

3 寄存器间接寻址模式简介

C语言函数的执行都是依赖于栈的,每个函数在执行之前都需要在栈上开辟一块属于自己的空间,这个空间就是栈帧。这个栈帧的建立和释放是依靠编译器在函数头部和尾部添加的一段汇编代码完成的。这就是任何高级语言编写的程序在链接成为可执行程序之前都必须被编译为汇编语言程序的原因之一。当栈帧建立完成后,寄存器ESP指向栈帧的头部,EBP指向栈帧的尾部,即此时ESP和EBP分别保存栈帧的头部和尾部的内存地址。随着数据的压栈和出栈,会导致栈顶会不断变化,即ESP保存的内存地址会不断变化,而栈底在整个函数执行期都保持不变,所以EBP可以作为访问当前栈底前后内存块的基准。例如:movl 0xa,-0x14(%ebp)就表示从EBP指向的内存位置向下偏移20个字节处开始保存0xa,这就是寄存器间接寻址。

4 分析反汇编代码

测试代码如下:

int main(void)

{

int i = 10;

int *p = &i;

*p = 123;

printf("%d\n",*p);

return 0;

}

本次测试的环境是32位架构Ubuntu 4.2.0-42-generic,gcc版本是: 5.2.1 20151010。不同的版本在生成的汇编代码上可能略有差别,但基本原理是不变的。

对上述代码进行反汇编,在段截取一段与本文相关的代码。这是在Linux下的反汇编结果,所以是AT&T汇编格式。

......

1. movl $0xa,-0x14(%ebp)

2. lea -0x14(%ebp),%eax

3. mov %eax,-0x10(%ebp)

4. mov -0x10(%ebp),%eax

5. movl $0x7b,(%eax)

6. mov -0x10(%ebp),%eax

7. mov (%eax),%eax

8. sub $0x8,%esp

9. push %eax

10. push $0x8048560

11. call 8048330

......

Main函数执行时,其栈帧会不断变化,其变化过程如图1和图2所示。为了叙述的方便,假设栈帧-0x14(%ebp)处的内存地址为0x12345678,即灰色部分。这11行汇编代码具体功能详述如下:

(1)在栈低下方偏移0x14处保存数字10。

(2)将内存地址0x12345678,存入到CPU的寄存器EAX中。

(3)将地址0x12345678存入到-0x10(%ebp)中。

(4)再将地址0x12345678存储到EAX中。

(5)在地址0x12345678地址处保存0x7b。

(6)将地址0x12345678保存到EAX中。

(7)从地址0x12345678处加载4字节的数据到EAX中。

(8)更新ESP,因为-0x10(%ebp)和-0x14(%ebp)处这8个字节被占用了。

(9)将EAX压栈,为调用printf做准备。

(10)将字符串“%d\n”的地址压栈。

(11)调用printf函数。

简单来说,就是把某个需要操作的对象的内存地址保存到了栈帧中,当需要读写该对象时,就把该地址加载到寄存器中,然后通过寄存器间接寻址实现读写。另外,汇编语言中并没有局部变量这一概念,C语言程序中的局部变量也是通过寄存器间接寻址实现读写的。例如上述汇编代码的第一句就是通过寄存器间接寻址找到0x12345678这个内存位置,然后写入数字10的。

而在嵌入式系统中,需要读写大量的寄存器,此时最好的方法就是通过指针操控它们。要操控这些寄存器的唯一的方法就是通过地址访问它们,即通过指针读写寄存器。跟一般桌面应用开发相比,唯一不同的就是需要先把由CPU厂商提供的寄存器编号强制转换为地址(桌面应用开发中,由于系统保护,不允许直接把一个整数强转为地址)。该强转一般是通过宏定义来实现的,如下所示:

#define GPJ0CON = (*(volatile unsigned int *)0xXXXXXXXX)

然后在程序中就可以像对待普通变量一样对它进行写入和读取工作。而在汇编层,依然是寄存器间接寻址,在此不再赘述。因为涉及到大量的寄存器的读写,所以通常的做法就是把大量的与寄存器读写有关的宏定义放在一个单独的文件,便于查找和修改。

5 总结

指针运算就是对寄存器间接寻址的封装,目的是隐藏汇编层的寄存器,栈帧,栈顶和栈底等复杂概念,从而为开发人员提供一个更加友好,逻辑上更接近人类思维的操作。而寄存器间接寻址依赖的是内存地址,即指针运算依赖的就是内存地址。所以说指针的本质就是内存地址。则对指针执行乘法或除法运算在逻辑上是无法说通的,当然编译器也会报错。因此指针的合法算术运算只能是加减整数或两个指针相减,这在数组运算别有用。通过指针加减整数就可以读写数组中不同的元素,但一定要注意不能越界。当两个指针指向同一个数组的不同元素时,可以执行指针相减运算,得出它们之间相差几个元素。理解了指针的本质就是内存地址之后,对数组指针,函数指针,多级指针的理解会有很大的帮助。

参考文献

[1][美]K.N.King著.吕秀锋,黄倩,译.C语言程序设计现代方法(第2版)[M].北京:人民邮电出版社,2010.

[2][美]Richard Blum著.马朝辉,等译.汇编语言程序设计[M].北京:机械工业出版社,2006.

[3]韦东山.嵌入式Linux语言程序开发完全手册[M].北京:人民邮电出版社,2008.77-78.

单位单位

c语言指针范文第4篇

【关键词】指针;情景创设;主动探索;协作学习;游戏案例导入

一、引言

指针是C语言中广泛使用的一种数据类型,运用指针编程是C语言最主要的风格之一。正确而灵活地运用它,可以有效地表示复杂的数据结构;能动态分配内存;能方便地使用字符串;有效而方便地使用数组;在调用函数时能得到多于1个的值;并能像汇编语言一样处理内存地址,从而变出精练而高效的程序等,这对设计系统软件是很必要的。掌握指针的应用,可以使程序简洁、紧凑、高效。指针极大地丰富了C语言的功能。每一个学习和使用C语言的人,都应当深入地学习和掌握指针。可以说,不掌握指针就是没有掌握C语言的精华。

二、教学现状

高职学生的基础普遍较差,数学与英语基础较为薄弱,在碰到程序逻辑思维分析,程序代码编写及调试的过程中,往往会感到困难,这是高职C语言课程教学中的共性问题。学习指针是学习C语言中最重要的一环,能否正确理解和使用指针是学生是否掌握C语言的一个标志。同时,指针也是C语言中最为困难的一部分,学生很难正确理解基本概念,就指针的教学谈谈自己的想法。

三、教学方法

1、情景创设教学法。课堂教学是获取知识和技能的主要阵地,应当成为培养学生独立思考的摇篮。情景创设教学方法把学习设置到简单的、有意义的问题情境中,学生通过互相合作来解决这些问题,发现隐含于问题背后的科学知识,形成让学生掌握解决问题的技能和提高自主学习的能力。例如,讲解指针的基本概念,计算机中的所有数据都是顺序存放在存储器中的。一般把存储器中的一个字节称为一个内存单元,不同数据类型的值所占用的内存单元数亦不同。为了正确地访问这些内存单元。内存单元的编号也叫地址,通常也把这个地址称为指针。内存单元的指针和内存单元的内容是两个不同的概念。为让学生掌握并理解内存单元的指针和内存单元的内容,我采用了情景创设的教学方法。我们到银行去存、取款时,银行工作人员将根据我们的账号去查找存款单,找到之后在存单上写入存款、取款的金额。在这里,账号就是存单的指针,存款数就是存单的内容。这样就能让学生明白内存单元的指针和内存单元的内容之间的关系了。

2、主动探索、协作学习教学法。根据已有信息,从不同角度、不同方向思考问题,从多方面寻求多样性答案的一种思维形式,是主动探索的教学方法。为走出传统教学中的泥滩,教师应转变教学观念,砸碎应试教育的模式和框架,克服单纯传授知识的倾向,注重顺向思维、逆向思维、多向思维的训练,培养学生思维的深刻性、批判性和创新性。具体来讲,就是要通过挖掘教材中能一题多解、一法多用、一题多变的教学内容,来引导学生主动探索,使他们的思考朝多种方向扩散,提出各种设想、多种解答。在指针教学中还可以进行协作学习中培养学生们的思维。协作学习是在解题中,尽可能利用自己已有的知识和经验与同学一起讨论,将不同的方法进行比较,从中确定出最佳方案。在教学中,引导学生从不同方向利用其他学科的理论,开阔思路,找出解决问题的多种方法。然后在众多的解法中,经过归纳、判断和比较,最终得出一个最优化的结论。比如在教学生如何通过指针引用数组元素,先请学生协作学习开阔思路用不同方法编写“输出数组中的全部元素”程序。

方法一:下标法

方法二:通过数组名计算数组元素地址,找出元素的值

方法三:用指针变量指向数组元素

通过该教学方法,这个知识点学生掌握得很好,找出解决问题的多种方法,能深刻地、高水平地掌握知识,并能把这些知识广泛应用到学习新知识的过程中,举一反三,提高了对知识的理解能力,使学习活动顺利进行。

3、游戏案例导入教学法

在指针教学中通过游戏案例导入教学法可以营造学生独立思考的心理氛围。在分析指向多维数组的指针和指针变量中的“多维数组的地址”知识点,我先请同学做游戏,一个当“排长”,三个当“班长”,十二个当“战士”,游戏是:有一个排,下设3个班,每个班有4名战士。规定排长只管理到班,班长管理战士。在排长眼里只有第0、1、2班。排长从第0班的起始位置走到第1班的起始位置,看来只走了一步,但实际上他跳过了4名战士。为了找到某一班内某一个战士,必须给两个参数,即第i班第j个战士,先找到第i班,然后由该班班长在本班范围内找第j个战士。这个战士的位置就是a[i]+i.。开始时班长面对第0个战士。注意,排长和班长的初始位置是相同的。但他们的“指向”是不同的。排长“指向”班,他走一步就跳过1个班,而班长“指向”战士,走一步只是指向下一个战士。可以看到排长是“宏观管理”,只管班,班长则是“微观管理”,管理到战士。如果要找第1班第2个战士,则先由排长找到第1班的班长,然后,由班长在本班范围内找到第2个战士。二维数组a相当于排长,每一行(即一维数组a[0]、a[1]、a[2])相当于班长,每一行中的元素(如a[1][2])相当于战士。

请同学们打开书,仔细看插图,边看边想:谁是排长?班长在哪儿?管多少个战士?

这段游戏导入把贯穿全文的线索用三个问题串起来,让学生从静态的图中找答案,思考、讨论结果。这一过程学生的思维也是最活跃的,对问题的思考是深入而全方位的,这些问题激发了学生们的心理驱动力,在讨论争议中,让学生迸发出创新思维的火花。

四、总结

c语言指针范文第5篇

C语言编程过程中,假设定义一个变量,编译时就为这个变量分配一定长度的内存空间。而在内存区每一个内存单元都有一个地址,用来标识内存单元,在地址所标识的单元存放数据。而正确使用指针变量,区分指针变量和指针的指向变量的含义和用法,判断变量与运算符的结合顺序来确定变量的数据类型以及指向变量或成员变量的类型。通过指针来访问数组元素和下标法数组元素的等价关系,作为函数参数的指针变量,可以改变所指向的主调函数变量的值。动态存储分配、对链表的创建以及相关操作都可以运用指针实现。

类成员的指针,类成员与外部变量相互比较,进行区分的方法就是它所在的域的不同,因为域的不同而决定了变量可以使用的范围,一个指向类的成员函数或者成员变量的指针,就要规范它的参数列表、返回类型,以及被指向变量或函数的域,所以使用类域限定如下:

classNJUPT{ staticdoublenumber=20000000; intnum; public: NJUPT():num(10){}; intget(){returnnum;}; doublegetNumber(){reuturnnumber;}}

在这里定义的成员指针为intNJUPT::*p;//指向int型成员变量int(NJUPt::*)p()//指向intf()型成员函数。

那么调用的方式为:cout<;

返回指针的函数,一个函数的接口是它的返回值,C语言可以自定义类型,我们使用引用作为函数的实际参数,或在函数的实际参数中使用指针。使用一个函数返回一个指针很容易将一个局部变量的地址传出来。例如:

UserType*Process(){ UserTypeut(param—list); //processut; return&;ut;//}

变量在函数运行结束已经被销毁,被传出的地址实际已经不存在被释放了。所以很容易出错。另一点是在运用new的时候。易造成内存泄露。

UserType*Process(){ UserTpye*put=newUserType(param—list); //processput; returnput;}

在函数内部使用一个new,分配了一个空间传出来。这样就不会发生问题,只是编程过程中通常会忘记在程序的外面把借来的空间还回去而造成内存泄露,所以把函数的参数设定为指针或引用作为代替。

两指针变量相减:所得之差是两个指针所指数组元素之间相差的元素个数。实际上是两个指针值(地址)相减之差再除以该数组元素的长度(字节数)。例如pf1和pf2是指向同一浮点数组的两个指针变量,设pf1的值为2010H,pf2的值为2000H,而浮点数组每个元素占4个字节,所以pf1—pf2的结果为(2000H—2010H)/4=4,表示pf1和pf2之间相差4个元素。两个指针变量不能进行加法运算。例如,pf1+pf2是什么意思呢?毫无实际意义。

this指针的用处:一个对象的this指针并不是对象本身的一部分,不会影响sizeof(对象)的结果。this作用域是在类内部,当在类的非静态成员函数中访问类的非静态成员的时候,编译器会自动将对象本身的地址作为一个隐含参数传递给函数。也就是说,即使你没有写上this指针,编译器在编译的时候也是加上this的,它作为非静态成员函数的隐含形参,对各成员的访问均通过this进行。例如:调用date.SetMonth(9)SetMonth(&date,9),this帮助完成了这一转换.

c语言指针范文第6篇

关键词: C语言;指针;应用

中图分类号:TP3 文献标识码:A 文章编号:1671-7597(2013)0120059-02

1 C语言指针重要性

指针是C语言中最重要的概念之一,运用好指针不就能够很方便灵活的处理好复杂的程序的设计,依靠指针的特性能够完成其他高级语言所无法完成的功能,在有些场合运用指针的灵活性是解决问题的唯一方式。如目前很多远程攻击都利用内存的缓冲区溢出来攻击,C语言本身特点不进行变量边界检测,人为介入检查,不仅工作量加大,同时很容易犯错,而所采取的检测库函数,同时也是安全漏洞,在这种情况下,利用指针分析,它可以本质上在C语言程序编译过程中,完成对程序的静态分析,完成对程序的变量边界检查,这种方式只有指针能够完成。指针同时在程序切片调试、自动化硬件技术有着广泛的应用。

同时指针也是最难掌握的一部份内容,指针的难以理解和应用中潜在危险,如应用指针不小心,也会使得整个程序奔溃。所以,指针在C语言占有非常重要的位置,在C语言的程序设计中应用非常广泛。

2 指针在C语言中应用

实际上,指针为变量地址,用于存储地址,程序设计在跟数据类型定义变量,同时为其分配一定大小的存储空间,同时建立变量名与地址空间关联。而指针变量简称指针,它是一种特殊的变量。它的特殊性在于:首先系统为变量,其所存储的内容为地址,而不是常用变量所存储的地址,它只能是整数值,具有一定的含义和运算规则所形成的整型。其次指针的类型指的不是存储数值的类型,而是指针变量的类型。在C语言中,指针的类包括整型、字符型、实型、数组型、结构型、联合型和枚举型等构造类型,它还可以指向函数、文件和指针。

程序开发人员,在使用C语言的指针时要特别的谨慎,因为如果指针被赋以错误的值,可能无法察觉问题,同时对于系统可能造成很大的影响。程序在调用每次错误的指针时,都会对错误指针所对应的存储单元进行读写。程序中的读操作,只能得到无用或者无效的值;程序中的写操作,所输入的数据将存入未知的地方,这类情况的发生,将使得使程序出现错误,开发人员无法找到错误所在,因此使用指针必须谨慎,建立相应的判别的条件,防止错误无法巡查。

下面就C语言程序设计中指针使用过程中遇到的特殊问题进行分析并对解决策略进行详细阐述。

1)其中指针初始化问题,指针初始化相比其他的变量不同,指针是用来存储地址。所以指针初始化形如:

jnt n=1;

jnt * str=&b;

而不能形如:jnt *str=1,由于str为指针,上面str所获得的值不是地址,而是将一个具体的值赋予指针,所以指针指向哪里,就不清楚,这种错误,很容易造成不易察觉的程序BUG。

2)指针与数组问题,指针和数组存在很紧密的联系,这是C语言构造比较神奇的地方,通过如下的例子了解指针与数组的关系。

jnt j,b[]={1,4,5,6,7,1};

for (j=0;j

{

prjntf ( “%d”, b[j] );

如上例子,b[j]是显示b 数组的各元素值。同样也可以指针访问元素,如下

jnt j,b[]={1,4,5,6,7,1};

for (j=0;j

{

prjntf (“%d”,*(b+j) );

}

如上例子运行结果和作用跟上面的数组的完全一样,所以可知指针str=*(b+j);

在看例子来分析数组名与指针变量的关系。

jnt j,*pb,b[]={3,4,5,6,7};

pb =b;

for (j=0;j

{

prjntf ( “%d”, *pb );

pb++ ; //注意这里,指针值被修改

}

这段代码也是将数组各元素值输出。不过,如果把{}中的pb改成b。程序编译出错,不能成功。可知指针和数组名还是不同的。其实上面的指针是指针变量,而数组名只是一个指针常量。指针pb在整个循环中,其值是不断递增的,即指针值被修改了。数组名是指针常量,其值是不能修改的,因此不能类似这样操作:b++。而指针pb的值是终没有改变。所以变量指针pb与数组名b可以互换。

3)指针与函数

C语言规定函数的参数传送有两种:值传递和地址值传递,其中实参变量对形参变量的数据传递是值传递,即单向传递只由实参传给形参,而不能由形参传回来给实参,但采用指针变量作为函数参数,可以改变所指向的变量的值,指针作为参数传递为地址传递。不过要注意只有在被调用的函数中指针形参所指向的变量值发生变化函数调用后在主调函数中才能使用这些改变了的值。若在被调用的函数中指针形参的值不发生变化。则不能改变指针实参所指向的主调函数中变量的值。

vojd fjnd1(chbr [] brrby, chbr sebrch, chbr * pb)

{

jnt j;

for (j=0;*(brrby+j)!=0;j++)

{

jf (*(brrby+j)==sebrch)

{

pb=brrby+j

brebk;

}

else jf (*(brrby+j)==0)

{

pb=0;

brebk;

}

}

}

如上例是传送的地址,所以在函数内地址进行改变,对应的指也进行了改变,而跟值传送的方式正好相反。一般在函数的参数应用中,利用指针进行地址传送是最普遍的方式,并且能够保持数据的一致性。

3 深析指针

指针为C语言难点,如果理解不深,很容易造成错误。一旦造成了错误,也无法容易找出来。此节将对指针容易出现问题,进行分析。

1)指针分配不一定成功,若不进行事前判断处理,容易造成错误。对于程序开发者容易犯这样的错误,其实通malloc()等函数动态分配空间时,不一定能成功。还有如打开文件时,也应该判断一下是否打开成功了,以防给程序带来不必要的麻烦。在程序设计上,在动态分配空间后,先应该判断是否分配成功,要养成这种程序设计习惯。

2)通过指针赋值,可能导致内存的数据丢失。在程序设计过程中,容易把指针b=“123”理解成是把字符串赋到分配的空间中了,其实这样理解是错误的。语句指针b=“123”,是把静态存储区的字符串的首地址赋给b指针变量,这样使得p指针又指向其它位置(字符串的首地址),不再指向刚才分配的新空间。所以在进行程序设计时,要理清楚函数赋值的真正含义。

3)在数组中使用指针及指针函数容易出现的问题。对于组i`nt b[3],其中p指针可以指向数组中任何一个元素,但是对于二维数组而言,情况就比较复杂,也不容易理解。二维数组中数组名b代表第0行的地址,b[0]才代表第0行第0列的地址(这才是二维数组元素的地址)所以不能使得p=b,但可以这样赋值p=b[0];或p=&b[0][0];这里尽管b和b[0]的值是相等的,但意义不同。大部分初学者对这一部分的学是比较含糊,下面我们以一种新的思路来理解。

4)使用指针,容易使人以为传送值,产生内存值变化。程序中的指针使用,特别是函数调用的过程,使用指针作为参数传送时,由于所传送是指针,实际上为地址,所以当函数中地址中的值进行修改时候,实际上内存的值也改变,若程序员不注意,很容易造成数据丢失,时间长了,会造成系统奔溃。

5)使用指针,很容易使得释放内存在使用。如果程序中没有释放内存的语句。PC的内存空间是一定的,当多次分配内存空间而没有及时释放不用的空间,这部分空间将被认为丢失,不能再被分配,所以很容易造成内存分配完而无法继续分配的情况,这时就造成系统奔溃。所以在新增新空间之后,一定要注意对内存的释放,这样很容易造成内存混乱

4 总结

本文对C语言的指针部分进行详细的分析和介绍,特别是对于使用指针过程中遇到的问题进行深入的分析。指针部分在C语言的体系是非常的重要的,其所应用的领域和范围很广,还有很多使用技巧,难点还需要慢慢分析和总结。

参考文献:

[1]魏扬,C语言中的指针[J].电脑编程技巧与维护,2008(17).

[2]韩雨涝,C语言指针与数组关系研究及应用[J].福建电脑,2009(07).

[3]丁春芳,浅析c语言中指针作函数参数[J].科学大众(科学教育),2010(03).

[4]张颖,C语言中数组与指针的使用技巧[J].信息通信,2009(04).

[5]李芳菊,蒋建.C++语言中指针的妙用[J].中国科技信息,2009(01).

[6]孙泽宇,C语言中指针探讨[J].甘肃科技纵横,2006(05).

c语言指针范文第7篇

关键词:C语言;指针;程序设计

中图分类号:TP311.1 文献标识码:A文章编号:1007-9599 (2010) 05-0000-01

C Language Pointer

Li Peng

(Tianjin Polytechnic University,Tianjin300160,China)

Abstract:C-language is a programming language,teaching in the program design plays an important role.In the C language,difficult to understand is the pointer.This article intends to discuss the indicators of definitions,classifications,operations and 3 special purpose,so that we can more clearly understand the nature pointer.Can be expected that only a thorough grasp of the pointer can truly grasp of the C language. Applications through in-depth pointers,C language will be used more widely in the field.

Keywords:C language;Pointer;Programming

一、引言

C语言是目前教学中使用最广的程序设计语言。虽然近年来产生了许多功能丰富的计算机程序设计语言,但鲜有能代替C语言的。其主要原因就是它不仅是一门高级语言更重要的是它能直接对物理地址进行访问,具有双重功能,是嵌入式设计中必不可少的一门语言。C语言功能强大的主要原因就是具有指针结构。指针是一种特殊的数据类型,直接指向目标的存储地址,实现直接访问对象存储空间的功能,具有重要的作用。

二、C语言中的指针简介

在C语言中,任何一个变量总结起来包括变量的数据类型、存储空间。在数据类型中定义的变量的基本范围和操作类型。存储空间就是变量在计算机中的存储地址,如何有效的存储变量并能有效的访问到它这是一个必须解决的问题。指针就是表示地址的一种变量,所以指针的范围严格来说只能是自然数的,并且不能在两个指针间进行加、乘、除这样的运算。由于在C语言中每个数据类型都必有存储空间,所以指针可以应用于几乎所有的数据类型中。所以,从这个角度出发可以将指针分为:指向变量的指针、数组指针、字符指针、指向指针的指针、函数指针、结构变量的指针以及文件指针等等。其中,指向变量的指针就是存储变量的地址的。如 int * s这就是一个指向整型的指针,可以用于指向一个整型变量。如int a; 当p=&a时,就是将p存储整型变量a的地址。这是指针最简单的一种类型。所谓数组指针,就是指数组的名称实际上是指向整个数组空间的首指针。如 int a[10];其中a本质上是一个指针,指向该数组的第一个位置,a[2]表示距离a指向空间向后2个位置所在空间中的存放的值。所以,a[2]=*(a+2)。字符指针本质上是数组指针的一种特殊情况,就是存放字符串的数组所对应的数组名。指向指针的指针这是一类很特殊的指针,用于存放指针的一类指针,在本质上与指向变量的指针十分相似。例如 char *ss[N]={“java”,”sss”,’’rrr”}。指向函数的指针就是指向函数入口地址的指针。结构变量的指针这类指针和指向变量的指针很类似,主要的区别在于结构变量可能有多个类型不同的变量,所以一般空间较大。文件指针就是对文件进行操作的指针。从上述的分类可以看出无论什么类型的指针其功能都是一样的就是用于指向对象的地址空间罢了。

上面简要的介绍了指针的定义和分类,现在简要的论述一下指针涉及到的运算操作。首先由于指针是存放的变量地址的,所以第一个操作就是对指针进行地址赋值。如int a,*p;

P=&a,这就是对指针p进行进行赋变量a的地址,p指向变量a。当然也可以通过指针获取指针指向地址空间所存储的值。如int b=2,*p;p=&a,这是*p就表示p指向空间所存储的值,在本例中就是a的值2。为了能在数组指针中通过指针能访问到整个数组的值,所以。可以对指针进行加减整数值,表示地址的前移或后移。如int a[10],*p,*s; p=a;s=p+2;其中s 的值表示数组中首地址向前移动2的位置,表示 a[2]对应的地址。 为了表示两个地址间存在的距离,可以通过指针间的减法实现。当然指针涉及到的还有其他运算,现不详述了。

三、C语言中的指针应用

在C语言中指针的十分应用广泛,除具有一般的功能外,具体特殊功能的应用总结起来有三个方面:一是用于在函数中可以返回多个值;还有就是可以实现动态调用函数;最后就是实现数组的动态定义。其中,由于由函数的特点,一个函数只能有一个返回值,但在有些场合需要返回多个值,就可以定义指针参量来实现,其定义的基本框架如下:

Sss( int a,int *p )

{int s;

…….

………

Return s;

}

在这中情况下,函数不仅可以得到返回值(通过Return s来实现的),还可以通过指针p来返回相应的值。所谓指针能实现动态调用函数,这里用到的指针就是上文中提到的函数指针。函数指针就是指向函数入口地址的指针,我们还知道其实函数名就是一个函数指针。我们就是通过函数名实现动态调用函数的。在主调函数的参数中采用函数名充当实参就能实现函数的动态调用。该方法以简短的代码实现了复杂的功能。最后讲到指针能实现数组的动态定义。从C语言的学习中,我们知道在定义数组时一定要指定数组的大小,否则,不能完整数组的定义。那么如何实现数组的动态定义?数组从本质上来讲就是连续的空间集合罢了。那么,我们可以通过申请一个空间并赋值给一个指针变量,以此指针变量为首空间,就能获取连续的空间,这与数组相同。当然数组还有许多应用,只有认真分析就能得到更多更好的应用实例。

四、结论

C语言是到目前为止学习最多的程序设计语言之一,也是计算机教育中的必修课。在整个C语言教学中,指针是一个十分重要的部分,也是最难掌握的部分之一。论文通过对指针的概念、分类、运算类型和应用等方面,系统的论述了指针,目的就是让大家能清晰的了解指针、掌握指针,从而实现高效的应用指针。只有掌握好了指针,才能发挥C语言的优势,可见指针具有重要的作用。

参考文献:

[1]张丽霞.C 语言指针详解[J].赤峰学院学报(自然科学版);2005;21(5);37-38

c语言指针范文第8篇

关键词:C语言教学 指针 复杂数据结构

中图分类号:G64 文献标识码:A 文章编号:1673-9795(2014)03(b)-0137-02

C语言的精华在于指针,正确理解指针及相关概念是学好C语言的关键。作者在C语言教学实践中发现许多学生在学好指针的有关知识及掌握其应用方面存在困难。本文针对C语言教学中的几个难点问题进行了分析,特别是对指针在定义复杂数据结构中的作用及其理解方法进行了探讨,期望抛砖引玉,有助于读者加深对指针概念和用法的理解。

1 指针和指针变量

计算机内存区的最小可编号存储单元是一个字节,每个字节都有一个唯一的编号,这就是“地址”。如果在程序中定义了一个变量,在对程序进行编译时,系统就会给这个变量分配若干字节(字节数决定于该变量的类型)的内存空间,所分配的内存空间起始字节的编号就是该变量的地址,一个变量的地址称为该变量的“指针”。如果有一个变量专门用来存放另一变量的地址(即指针),则它称为“指针变量”。

设有如下的C语句:

其中第1条语句定义了整型变量a和指向整型的指针变量p,则编译系统会为这两个变量分配内存空间(假若其分得的内存空间地址分别为2008、6430)。第2条语句把整数7存储到变量a中,第3条语句则把变量a的地址存储到指针变量p中,图1表示了语句被执行后变量a、p的状态以及它们之间的关系。

图1中指针变量p指向了变量a,因为其存储了变量a的地址,今后可以有两种方式访问变量a的内容,一种是通过变量名a来直接访问,另一种是通过指针变量p来间接访问。

2 指针变量的基类型和步长

C语言中定义指针变量的一般形式为:

基类型*指针变量名;

定义指针变量时必须指定基类型,而且指针变量的赋值必须做到类型匹配,即指针变量只能存放类型为其基类型的变量的地址。

比如在下面的C语句中:

第3、4条语句是错误的。既然指针变量是用来存放变量地址的,而所有变量的地址在形式上都一样,都是固定长度(地址的长度取决于计算机地址总线的宽度)的整数,那为什么上述第3、4条语句就不正确呢?换言之,指针变量的定义为什么要指定基类型,并且规定指针变量只能存放类型为其基类型的变量的地址呢?这样做的原因主要有两点:其一是为了安全考虑,避免指针变量随意指向不确定的内存区引起程序崩溃;其二是为指针运算提供支持。“指针”含有指向的意思,在数据处理中,经常需要通过移动指针来处理连续存储的数据对象,比如数组元素的处理。在C语言中,移动指针是通过对指针变量进行简单的加减运算来进行的,指针变量加1则指向前一个数据对象,减1则指向后一个数据对象。这样所有指针变量的移动操作都统一化了,使得代码更加简洁精炼。但是C程序中对指针变量加1,实际上指针变量的值并不一定是加1,而是要加上一个整数n,这个n就是指针变量所指向的数据对象所占用的字节数,为了确定n的值,需要在定义指针变量时指定其所指向的数据对象的类型,也就是基类型,基类型数据对象的长度(字节数)就是指针变量的步长。

指向函数的指针变量较特殊,它用来存放函数的入口地址,这类指针变量的步长无意义。

3 正确理解运算符&、*和[]

C语言中和指针相关的运算符主要有&、*和[]三种,分别是取地址运算符、指针运算符和下标运算符,其中*和[]在表达式中起运算符作用,而在指针变量定义中只起说明作用,不能看作运算符。

上述C语句定义了一个二维整型数组c。 c是数组名,它是一个指针常量,指向的数据对象为该二维数组的行,代表数组c第0行的首地址,步长为8(假设一个数组元素占用2个字节)。那么&c的含义是什么呢?c是常量,不占内存空间,自然无地址可言,按&“取地址”的本义,则&c无意义。要理解&c的含义需要用到&的引申义,其引申义为“使指针升级”。&c也是指针常量,指向的数据对象为整个二维数组c,代表数组c的首地址,步长为24。同样,*的引申义为“使指针降级”,*c是指针常量,指向的数据对象为二维数组中的元素,代表数组c第0行第0列元素的地址,步长为2。

4 指针和复杂数据结构

利用指针可以定义和说明复杂对象,包括具有复杂元素的数组、复杂的指针函数和指针等,以满足应用编程描述复杂对象的需要。

要注意,在C说明中*和[]都不是运算符,而分别是指针标志和数组标志。对于小括号(),则需要正确区分它是函数标志还是一般的括号运算符。()为函数标志的充分必要条件是:(1)()紧跟在用户标识符的后面,或紧跟在一个被小括号括起来的字符串后面;(2)()内部为空或为一个形参表列。

理解复杂说明的方法是:从用户标识符出发,按照()(括号运算符)、()(函数标志)、[](数组标志)和*(指针标志)从高到低的优先级以及其结合性顺序逐步解释说明符。下面用具体例子来加以说明。

5 结语

指针是C语言中的精粹,但由于其概念复杂、使用灵活,许多学生难以掌握。本文对教学过程中的一些难点问题进行了简单的分析、探讨,希望引导学生由浅入深地掌握指针的相关概念,在编程实践中更深入地理解和把握C语言指针的精髓。

参考文献

[1] 谭浩强.C程序设计[M].4版.北京:清华大学出版社,2010.

c语言指针范文第9篇

关键词:C语言;数组;教学;指针

中图分类号:G718.5 文献标志码:A 文章编号:1674-9324(2015)45-0228-02

在C语言的教学中,“指针”这一部分内容一直是C语言的教学重点和难点,直接影响学生对后续课程的学习和把握[1-3]。作为软件开发入门课程,绝大多数时间是在讲条件、循环、数组、函数,而指针内容却是省、国家计算机二级、程序员等考试的必考内容。为了在最短的时间内达到较好的教学效果。笔者从多年的教学经验认为C语言的指针教学应该注意以下几点:

一、输入函数scanf()和数组中地址的应用

所有的书本上都有介绍scanf(格式控制字符串,输入项列表),此函数的输入项列表要用“&”加变量名,要将所输入的内容放入变量的地址中,其中格式控制串中如果有普通字符也要输入普通字符,且有很多输入后不能正确读取的情况,初学者往往感到非常困惑难以理解。其实,连续定义的多个变量在内存中也是占用连续的内存单元,只是不同的数据类型所占的字节不同,程序在运行过程中遇到第一个scanf()函数时,将要求用户从键盘上按要求输入内容,所有输入的内容都将先放入缓冲区且你可以输入很多内容,输入完成后再按scanf的格式控制字符串的格式来存入到变量的地址中,一旦输入不合法,则认为输入结束,后面的变量将取不到值。如:scanf(“%d:%d”,&a,&b);若输入时你输入3,4L其中a的值为3,输入格式串中本来要求你输入的是“:”而你输入的是“,”,明显不合法,则scanf函数输入结束,后面的变量b将取不到值。同时这也很好解释了若程序中有多个scanf函数时,为了保证每次输入都有效,则应该在输入函数前加一个清空缓存函数fflush(stdin)。

数组名代表的是数组的首地址,所以在scanf()函数中以”%s”为格式串所对应输入项列表不需要加“&”。如:char str[20];

scanf(“%s”,str);/*将输入的内容存储到从数组首地址开始的地址中*/

printf(“%s”,str);/*从数组的首地址开始输出字符数组的内容*/。

这些内容都与计算机的实际存储有关(即和地址有关)。

二、指针

指针就是地址。其实前面我们在讲解输入输出函数和数组时,我们就介绍了一些有关地址的应用。一听自己已经用过且有所接触了,学生也就不会感到太畏惧了。再加上时间有限,我们要言简意赅地说明指针的用法。

1.指针的概念。指针就是内存地址。这里首先要区分三个比较接近的概念:名称、地址和内容(值)。名称是给内存空间取的一个容易记忆的名字;内存中每个字节都有一个编号,就是“地址”;在地址所对应的内存单元中存放的数值即为内容或值。

为了帮助读者理解三者之间的联系与区别,我们不妨打个比方,有一座教师办公楼,各房间都有一个编号,如101,102,…,201,202,…。一旦各房间被分配给相应的职能部门后,各房间就挂起了部门名称:如电子系、计算机系、环境工程系等,假如电子系被分配在101房间,我们要找到电子系的教师(内容),可以去找电子系(按名称找),也可以去找101房间(按地址找)。类似地,对一个存储空间的访问既可以指出它的名称,也可以指出它的地址。

在C语言中,如果变量p中的内容是另一个变量i的地址,则称变量p指向变量i,或称p是指向变量i的指针变量,形象地用图1所示的箭头表示。

由此可以得出结论:变量的指针即为变量的地址,而存放其他变量地址的变量是指针变量。

指针变量是一种变量,因而也具有变量的三个要素,但它是一种特殊的变量,其特殊性表现在它的类型取值上。具体而言:①变量名:与一般的变量命名规则相同。②变量的值:是某个变量的内存地址。③变量的类型:主要是其指向的变量的类型。

2.指针指向简单变量。

如:int a=100,*p;/*指针变量的定义*/

p=&a;/*指针变量的赋值*/

*p=200;/*指针变量的应用*/

printf(“%d”,a);则输出值为200。

在此我们要理解指针一旦定义且指向了一简单变量,除定义和初始化时的*p,其他的*p等价于它所指向的简单变量(即这里的*p<=>a),p(指针)等价于简单变量的地址(即这里的p<=>&a)。上面的输出语句可以变为:printf(“%d”,*p)。

3.指针指向数组。

(1)指针指向一维数组。

如:int a[5]={10,20,30,40,50},*p=a;

p++;

printf(“%d,%d,%d”,*p,*(p+2),*p++);则输出结果为:30,50,20

以上是指针指向一维数组的基本应用,首先我们要理解有关指针的运算。

&:取地址运算符[5]。

*:指针运算符(间址访问运算符),取指针所指向的值,若所指向二维数组则表示离取值进了一步。

++:算术运算符,表示指针往下或右移一个单位(其中这个单位和具体的数据类型有关,如果是整型数一个单位就指2个字节,实型指4个字节)。

--:算术运算符,表示指针往上或左移一个单位。

若定义了一个指针指向了一个一维数组,则p<=>a的使用(原来的a[i],也可以用p[i]表示,*p<=>*a),即*(p+i)<=>a[i] <=>p[i] <=>*(a+i)。但要注意p和a同为地址它们是有区别的,p为变量地址,而a是常量地址。有p++而不能用a++。

(2)指针指向二维数组。对于指针指向二维数组,要理解行地址和列地址的含义(*运算符能实现行地址向列地址的转换)再加上一维数组中的等价关系,能理解下面的二维数组的指针表示形式表即可。

(3)数组指针与指针数组的含义。前者是指针,后者是数组。定义格式:仅差一对圆括号。①指向一维数组的指针。假设有定义语句:int (*p)[4];②指针数组。假设有定义语句:int *p[4];

(4)应用场合:前者是一个指针,后者是多个指针。①指向一维数组的指针。一般将一个二维数组名赋值给一个指向一维数组的指针,来访问二维数组中的某一行。②指针数组。适合存放若干个字符串,使字符串的处理更加方便灵活。例如:

char *menu1[]={"Copy","Cut","Paste","Delete"};

char menu2[4][7]={"Copy","Cut","Paste","Delete"};

用字符指针数组处理字符串不仅可以节省内存,还可以提高运行效率。

4.指针指向函数。

(1)指针作为函数的参数。

其中左边交换完后,能传递给实参,因为它是指针所指向的值发生交换,而右边只是指针的指向发生改变原本值未发生交换。

(2)指针函数与函数指针。这是两个完全不同的概念,前者是函数,后者是指针。

a定义格式:仅差一对圆括号。

①指针函数。假设有定义语句:

int *fp(int x,int y);

②指向函数的指针(函数指针)。假设有定义语句:

int (*fp)(int x,int y);

b应用场合:前者是一个函数,只是函数的返回值是指针;后者是一个指向函数的指针,通过这个指针可以间接地调用所指向的函数。

三、总结

本文探讨了指针教学中,通过截取最基本且最重要的知识来解析其应用问题,目的在于使学生在较短的时间内掌握其基本知识,预计可作为指针教学的有效方案之一。

参考文献:

[1]管银枝.C语言程序设计实例教程[M].北京:人民邮电出版社,2011.

[2]谭浩强.C程序设计(第二版)[M].北京:清华大学出版社,2001.

c语言指针范文第10篇

【关键词】C语言;指针;数组;字符串;函数

C语言把内存存储单元的地址视为一种数据类型,而地址起到指向某个存储单元的作用,因此常称地址为“指针”,即指针就是地址。指针变量是用于存放指针(即地址)的变量,该变量的值是一个指针,一个要访问对象的地址。在C语言中,引入指针变量的目的主要是用来间接访问数据对象,有效地表示复杂的数据结构。例如:设有指向整型变量的指针变量p,要求指向整型变量a,那么用C语言可描述为:

int a=100;/*定义整型变量a,并赋初值100*/int*p=&a;/*定义指针变量p,并将变量a的地址送给p*/用图表示为:

要存取变量a的值,有两种方法可以完成。一种可通过变量名直接对内存单元进行存取操作,这种方式称为直接访问。另一种方式:先找到存放“a的地址”的变量p,从中取出a的地址(2000),然后到这个地址中对a进行存取a的值,这种访问方式称为间接访问。通过对变量p进行取内容运算*p值就得到a的值100。

有时为了方便,常将指针变量简称为指针。正确而灵活地运用指针不仅能够提高效C程序的效率,而且能有效地表示复杂的数据结构。所以指针的主要用途有:进行指针运算;引用数组元素;使用字符串;作为函数参数,实现地址传递;处理链表等等。

1.指针运算

指针的运算主要指指针的算术运算,其实质就是指向的地址发生变化。指针实际增(减)多少由指针的类型决定。指针加上(或减去)一个整数n,表示将指针由当前位置移动到后面(或前面)的第n个数据处。两个指针相减,表示两指针所指向的地址相减。得到两指针之间数据的个数,结果是一个整数,而不是地址值。如:

int a[5]={2,4,6,8,10};/*定义一个整型数组a并初始化*/

int*p=a,*q=a;/*定义指针p和q,均指向a数组的首地址*/

当p=p+2时,表示将指针p向后移动的二个数据,移向了a数组中第3个数组元素(即6),p-q结果为p与q这两个指针之间数据的个数等于2。利用这个特点,若将p指向数组a的首地址,将p移到a数组的末尾,则用p-q就可以求出数组a的长度,即a中数据的个数。

2.数组与指针

数组在内存中占据一块连续的存储区,数组名代表这个区域的起始地址,即数据名是一个指向该数组首地址的常量指针。当指针指向一维数组首地址后,C语言可有4种直接访问该数组的第i个元素的方法:“数组名[i]”,“指针名[i]”,“*(指针名+i)”,“*(数组名+i)”。前两种使用了数组的下标,称为“下标法”。后面两种使用指针运算符,称为“指针法”。

如:int a[10],*p=a;

则:对数组元素a[i](0

a[i]或p[i](下标法);*(a+i)或*(p+i)(指针法)

例如:以下程序有两个功能完成的函数(计算数组中各元素值的总和)。

int sum1(int a[],int n)/*函数1*/

{int sum=0,*p,*q=a+n;

for(p=a;p

sum+=*p;

return(sum);

}

int sum2(int a[],int n)/*函数2*/

{int sum=0,i;

for(i=0;i

sum+=a[i];

return(sum);

}

main()

{int a[5]={2,4,6,8,10};

printf(“%d”,sum1(a,5));

printf(“%d”,sum2(a,5));

}

上述主程序分别调用sum1()和sum2(),调用结果都为30,说明sum1()与sum2()功能完成相同,从表面看来,函数2似乎比函数1简单、直观,但其执行速度sum1比sum2要快,效率要高。

3.字符串与指针

访问一个字符串,除了用字符数组外,还可以定义一个字符指针,用字符指针指向字符串中的字符。如:char*p=“C Program”;这样,可以方便地用字符指针p来处理字符串。

如:打印图案:

*

**

***

****

*****

下面3个程序都能实现”

程序1:

main()

{int i,j;

for(i=1;i

{for(j=1;j

printf(“*”);

printf(“\n”);

}

}

程序2:

Void gra(int n)

{int j;

for(j=1;j

printf(“*”);

printf("\n");

}

main()

{int i;

for(i=1;i

gra(i);

}

程序3:

#include“string.h”

main()

{char a[5]=“*****”,*p;

for(p=a;p

printf(“%s\n”,p);

}

程序1用常用的两重循环结构实现;程序2在main()函数中5次调用gra()函数(gra()函数的功能是打印输出每一行中的“*”符号);而程序3中用一个字符指针p指向字符串,通过一个单循环,每一次输出一行中的“*”符号。由此可见,程序3最方便。所以,如果能灵活运用指针,可以使程序更简洁、更紧凑、更高效。

4.函数与指针

函数调用时,数据的传递可采用数值传递、地址传递、返回值等方式。

数值传递一般指参数为普通变量,这种方式无法通过调用函数来改变实参变量的值,有时也称这种数据传递是“单向的”。如:

Void f1(int p)

{p=p+3;}

.

.

.

int x=2;

f1(x);/*调用函数f1后,实参x的值仍然为2*/。

如果用指针作为函数参数,采用地址传递方式,却能改变实参的值。如:

Void f2(int*p)

{*p=*p+3;

}

.

.

.

int*q,x=2;

q=&x

f2(q);/*调用函数f2后,实参x的值改变为5*/。

返回值方式只能从被调函数中将一个值返回主调函数,如果上例中用指针作为函数实参和形参,采用地址传递方式则能改变实参的值。因为当调用者与被调用者之间是以指针变量作为参数进行传递时,调用者是把实参指针变量的值赋给被调用者的形参指针变量,于是实参指针和形参指针指向同一个地址,实现的地址的传递,当对形参所指变量的处理,也就是对实参做了相同的处理。如:地址传递方式可以得到多于一个的值”

Void f3(int*p)

{*p=1;

*(p+1)=2;

*(p+2)=3;

}

.

.

.

int a[3];

f3(a);/*调用函数f3后,实现了对a[0]、a[1]、a[2]的赋值,s[0]=1,s[1]=2,s[2]=3*/

此外,通过指向一个函数的指针,还可以调用相应的函数。

如:doublex,(*p)(double);/*A行,定义一个指向返回浮点型值的函数的指针p*/。

p=sin;/*B行,将正弦函数名sin赋给p*/。

x=(*p)(3.14/6);/*C行,通过指针p调用正弦函数sin*/。

函数名代表该函数的入口地址,所以B行赋值语句“p=sin;”的作用是将sin的入口地址赋给指针变量p。这时,p就是指向函数sin的函数指针,也就是p和sin都指向函数的开头。根据本文所列的参考文献[1][2],通过函数指针调用函数的格式为:(*指针名)(实参表);所以,上面的C行写成:x=(*p)(3.14/6);直接调用库函数sin的格式为:函数名(实参表),如:x=sin(3.14/6);那么,既然把sin赋给了函数指针变量p,则变量p就和sin具有相同的内容。能不能用格式:指针名(实参表)呢?经试验,结果运行完全正确。所以,C行可以改成x=p(3.14/6)。函数指针的这种用法更简单,且也更容易理解[3]。

5.结语

指针运用千变万化。对熟练的程序人员来说,可以利用它编写出颇有特色的、质量优良的程序,实现许多用其他高级语言难以实现的功能,但指针使用实在太灵活,也十分容易出错。所以,要学好指针,一定要在实践中不断摸索,从而能够更好地驾驭指针。

参考文献

[1]迟成文.高级语言程序设计[M].北京:经济科学出版社,2000.

[2]谭浩强.C程序设计[M].北京:清华大学出版社,1999,2.

[3]康牧,杨泽民.如何用简单的方法使用C语言[J].雁北师范学院学报,2002,18(5):30-240.

[4]HerbertS.C The Complete Reference[M].New York McGraw2Hill 1993.

上一篇:vb语言范文 下一篇:视听语言范文