指向指针的指针变量

指向指针的指针变量
指向指针的指针变量

一个指针变量可以指向整型变量、实型变量、字符类型变量,当然也可以指向指针类型变量。当这种指针变量用于指向指针类型变量时,我们称之为指向指针的指针变量,这话可能会感到有些绕口,但你想到一个指针变量的地址就是指向该变量的指针时;这种双重指针的含义就容易理解了。下面用一些图来描述这种双重指针,见图6-13。

在图中,整型变量i的地址是&i,将其传递给指针变量p,则p指向i;实型变量j的地址是&j,将其传递给指针变量p,则p指向j;字符型变量ch的地址是&ch,将其传递给指针变量p,则p指向ch;整型变量x的地址是&x,将其传递给指针变量p2,则p2指向x,p2是指针变量,同

时,将p2的地址&p2传递给p1,则p1指向p2。这里的p1就是我们谈到的指向指针变量的指针变量,即指针的指针。

指向指针的指针变量定义如下:

类型标识符**指针变量名

例如:f l o a t**p t r;

其含义为定义一个指针变量ptr,它指向另一个指针变量(该指针变量又指向一个实型变量)。由于指针运算符“*”是自右至左结合,所以上述定义相当于:

f l o a t*(*p t r);

下面看一下指向指针变量的指针变量怎样正确引用。

[例6-27]用指向指针的指针变量访问一维和二维数组。

#i n c l u d e

#i n c l u d e

m a i n()

{

i n t a[10],b[3][4],*p1,*p2,**p3,i,j;/是*p指3向指针的指针变量*/ f o r(i=0;i<10;i++) s c a n f("%d",&a[i]);/*一维数组的输入*/ f o r(i=0;i<3;i++) f o r(j=0;j<4;j++) s c a n f("%d",&b[i][j]);/*二维数组输入*/ f o r(p1=a,p3=&p1,i=0;i<10;i++) p r i n t f("M",*(*p3+i));/*用指向指针的指针变量输出一维数组*/ p r i n t f("\n");

f o r(p1=a;p1-a<10;p1++)/*用指向指针的指针变量输出一维数组*/

{

p3=&p1; p r i n t f("M",**p3);

}

p r i n t f("\n");

f o r(i=0;i<3;i++)/*用指向指针的指针变量输出二维数组*/

{

p2=b[i]; p3=&p2;

f o r(j=0;j<4;j++) p r i n t f("M",*(*p3+j));

p r i n t f("\n");

}

f o r(i=0;i<3;i++)/*用指向指针的指针变量输出二维数组*/

{

p2=b[i];

f o r(p2=b[i];p2-b[i]<4;p2++)

{

p3=&p2;

p r i n t f("M",**p3);

}

p r i n t f("\n");

}

}

程序的存储示意如图6-14所示,对一维数组a来说,若把数组的首地址即数组名赋给指针变量p1,p1就指向数组a,数组的各元素用p1表示为,*(p1+i),也可以简化为*p1+i表示。同样,对二维数组b来说,b[i]表示第i行首地址,将其传递给指针变量p2,使其指向该行。

该行的元素用p2表示为*(p2+i)。若作p3=&p2,则表示p3指向p2,用p3表示的二维数组第i行元素为:*(*p3+i)。这与程序中的表示完全相同。

运行程序:

[例6-28]利用指向指针的指针变量对二维字符数组的访问。#i n c l u d e #i n c l u d e m a i n()

{

i n t i; s t a t i c c h a r c[][16]={"c l a n g u a g e","f o x","c o m p u t e r","h o m e p a g e"}; /*二维字符数组*/ s t a t i c c h a r*c p[]={c[0],c[1],c[2],c[3]};指/*针数组*/ s t a t i c c h a r**c p p;/*指向字符指针的指针变量*/ c p p=c p;/*将指针数组的首地址传递给指向字符指针的指针变量*/ f o r(i=0;i<4;i++)/*按行输出字符串*/ p r i n t f("%s\n",*c p p++); p r i n t f("-----------\n");

f o r(i=0;i<4;i++)/*按行输出字符串*/

{

c p p=&c p[i]; p r i n t f("%s\n",*c p p);

}

}

程序中需要注意的是,执行cpp=cp是将指针数组的首地址传递给双重指针,所以*(cpp+i)表示第i行的首地址,而不是c p p+i。在程序设计时一定分清。

结构体指针

C++语言结构体和指针 指针也可以指向一个结构体,定义的形式一般为: struct结构体名*变量名; 下面是一个定义结构体指针的实例: 上述代码已经测试。 注意:定义已经命名的结构体指针的时候必须用已命名结构体类型定义的结构体变量的地址进行初始化。 也可以在定义结构体的同时定义结构体指针: 上述代码已经测试 注意,结构体变量名和数组名不同,数组名在表达式中会被转换为数组指针,而结构体变量名不会,无论在任何表达式中它表示的都是整个集合本身,要想取得结构体变量的地址,必 pstu赋值只能写作: struct stu *pstu = &stu1; 而不能写作: struct stu *pstu = stu1; 还应该注意,结构体和结构体变量是两个不同的概念:结构体是一种数据类型,是一种创建变量的模板,编译器不会为它分配内存空间,就像int、float、char 这些关键字本身不占用内存一样;结构体变量才包含实实在在的数据,才需要内存来存储。下面的写法是错误的,不可能去取一个结构体名的地址,也不能将它赋值给其他变量: struct stu *pstu = &stu; struct stu *pstu = stu;

获取结构体成员 通过结构体指针可以获取结构体成员,一般形式为: (*pointer).memberName 或者: pointer->memberName 对了。 ,有了它,可以通过结构体指针 直接取得结构体成员;这C语言中的唯一用途。 上面的两种写法是等效的,我们通常采用后面的写法,这样更加直观。

运行结果: Name Num Age Group Score Zhou ping 5 18 C 145.0 Zhang ping 4 19 A 130.5 Liu fang 1 18 A 148.5 Cheng ling 2 17 F 139.0 Wang ming 3 17 B 144.5 结构体指针作为函数参数 结构体变量名代表的是整个集合本身,作为函数参数时传递的整个集合,也就是所有成员,而不是像数组一样被编译器转换成一个指针。如果结构体成员较多,尤其是成员为数组时,传送的时间和空间开销会很大,影响程序的运行效率。所以最好的办法就是使用结构体指针,这时由实参传向形参的只是一个地址,非常快速。 要铭记的一点就是:数组名称始终代表数组的指针指向第一个元素,数组名称加一始终指向下一个数组元素。

C指针函数习题

C++指针函数习题 一、选择题 1.以下程序的运行结果是()。 sub(int x, int y, int *z) { *z=y-x; } void main() { int a,b; sub(10,5,&a); sub(7,a,&b); cout< #include<>

指向指针的指针——彻底搞定C指针

彻底搞定C指针---指向指针的指针 彻底搞定C指针---指向指针的指针一.回顾指针概念: 今天我们又要学习一个叫做指向另一指针地址的指针。让我们先回顾一下指针的概念吧! 当我们程序如下申明变量: short int i; char a; short int * pi; 程序会在内存某地址空间上为各变量开辟空间,如下图所示。 内存地址→6 7 8 9 10 11 12 13 14 15 ------------------------------------------------------------------------------------- … | | | | | | | | | | ------------------------------------------------------------------------------------- |short int i |char a| |short int * pi| 图中所示中可看出: i 变量在内存地址5的位置,占两个字节。 a变量在内存地址7的位置,占一个字节。 pi变量在内存地址9的位置,占两个字节。(注:pi 是指针,我这里指针的宽度只有两个字节,32位系统是四个字节) 接下来如下赋值: i=50; pi=&i; 经过上在两句的赋值,变量的内存映象如下: 内存地址→6 7 8 9 10 11 12 13 14 15 -------------------------------------------------------------------------------------- … | 50 | | | 6 | | | | -------------------------------------------------------------------------------------- |short int i |char a| |short int * pi| 看到没有:短整型指针变量pi的值为6,它就是I变量的内存起始地址。所以,这时当我们对*pi进行读写操作时,其实就是对i变量的读写操作。如:*pi=5; //就是等价于I=5; 你可以回看本系列的第二篇,那里有更加详细的解说。 二.指针的地址与指向另一指针地址的指针 在上一节中,我们看到,指针变量本身与其它变量一样也是在某个内存地址中的,如pi的内存起始地址是10。同样的,我们也可能让某个指针指向这个

指针数组及指向一维数组的指针讲解

一、指针数组及指向一维数组的指针(数组指针)讲解 1、数组指针(也称行指针) 定义 int (*p)[n]; ()优先级高,首先说明p是一个指针,指向一个整型的一维数组,这个一维数组的长度是n,也可以说是p的步长。也就是说执行p+1时,p要跨过n个整型数据的长度。 如要将二维数组赋给一指针,应这样赋值:int a[3][4];int (*p)[4]; //该语句是定义一个数组指针,指向含4个元素的一维数组。 p=a; //将该二维数组的首地址赋给p,也就是a[0]或&a[0][0] p++; //该语句执行过后,也就是p=p+1;p跨过行a[0][]指向了行a[1][] 所以数组指针也称指向一维数组的指针,亦称行指针。 2、指针数组 定义 int *p[n]; []优先级高,先与p结合成为一个数组,再由int *说明这是一个整型指针数组,它有n个指针类型的数组元素。这样赋值是错误的:p=a;只存在p[0]、p[1]、p[2]...p[n-1],而且它们分别是指针变量可以用来存放变量地址。但可以这样 *p=a; 这里*p表示指针数组第一个元素的值,a的首地址的值。 如要将二维数组赋给一指针数组: int *p[3]; int a[3][4]; for(i=0;i<3;i++) p[i]=a[i]; 这里int *p[3] 表示一个一维数组内存放着三个指针变量,分别是p[0]、p [1]、p[2]所以要分别赋值。 这样两者的区别就豁然开朗了,数组指针只是一个指针变量,似乎是C语言里专门用来指向二维数组的,它占有内存中一个指针的存储空间。指针数组是多个指针变量,以数组形式存在内存当中,占有多个指针的存储空间。 还需要说明的一点就是,同时用来指向二维数组时,其引用和用数组名引用都是一样的。 比如要表示数组中i行j列一个元素: *(p[i]+j)、*(*(p+i)+j)、(*(p+i))[j]、p[i][j] 优先级:()>[]>* 例1、下列给定程序中,函数fun()的功能是:从N个字符串中找出最长的那个串,并将其地址作为函数值返回。 #include #include #define N 4

指针变量作为函数参数

用名作为其他变量名地别名. ; 等价于; ()声明一个引用,不是新定义了一个变量,它只表示该引用名是目标变量名地一个别名,它本身不是一种数据类型,因此引用本身不占存储单元,系统也不给引用分配存储单元.故:对引用求地址,就是对目标变量求地址.与相等. ()不能建立数组地引用.因为数组是一个由若干个元素所组成地集合,所以无法建立一个数组地别名. 引用应用 、引用作为参数 引用地一个重要作用就是作为函数地参数.以前地语言中函数参数传递是值传递,如果有大块数据作为参数传递地时候,采用地方案往往是指针,因为这样可以避免将整块数据全部压栈,可以提高程序地效率.但是现在(中)又增加了一种同样有效率地选择(在某些特殊情况下又是必须地选择),就是引用. 【例】: ( , ) 此处函数地形参, 都是引用 { ; ; ; ; } 为在程序中调用该函数,则相应地主调函数地调用点处,直接以变量作为实参进行调用即可,而不需要实参变量有任何地特殊要求.如:对应上面定义地函数,相应地主调函数可写为: ( ) { ; >>>>; 输入两变量地值 (); 直接以变量和作为实参调用函数 <<<< ' ' <<; 输出结果 }

上述程序运行时,如果输入数据并回车后,则输出结果为. 由【例】可看出: ()传递引用给函数与传递指针地效果是一样地.这时,被调函数地形参就成为原来主调函数中地实参变量或对象地一个别名来使用,所以在被调函数中对形参变量地操作就是对其相应地目标对象(在主调函数中)地操作. ()使用引用传递函数地参数,在内存中并没有产生实参地副本,它是直接对实参操作;而使用一般变量传递函数地参数,当发生函数调用时,需要给形参分配存储单元,形参变量是实参变量地副本;如果传递地是对象,还将调用拷贝构造函数.因此,当参数传递地数据较大时,用引用比用一般变量传递参数地效率和所占空间都好. ()使用指针作为函数地参数虽然也能达到与使用引用地效果,但是,在被调函数中同样要给形参分配存储单元,且需要重复使用"*指针变量名"地形式进行运算,这很容易产生错误且程序地阅读性较差;另一方面,在主调函数地调用点处,必须用变量地地址作为实参.而引用更容易使用,更清晰. 如果既要利用引用提高程序地效率,又要保护传递给函数地数据不在函数中被改变,就应使用常引用. 、常引用 常引用声明方式:类型标识符引用名目标变量名; 用这种方式声明地引用,不能通过引用对目标变量地值进行修改,从而使引用地目标成为,达到了引用地安全性. 【例】: ; ; ; 错误 ; 正确 这不光是让代码更健壮,也有些其它方面地需要. 【例】:假设有如下函数声明:

指针练习题

. 编程题 1用指向数组的指针变量输出数组的全部元素 2 使用函数调用,形参为指针,实参为数组,把一个数组逆序存放在输出 练习题: 一判断题 1.指针是变量,它具有的值是某个变量或对象的地址值,它还具有一个地址值,这两个地址值是相等的。 2.指针的类型是它所指向的变量或对象的类型。 3.定义指针时不可以赋初值。 4.指针可以赋值,给指针赋值时一定要类型相同,级别一致。5.指针可以加上或减去一个int型数,也可以加上一个指针。6.两个指针在任何情况下相减都是有意义的。 7.数组元素可以用下标表示,也可以用指针表示。 8.指向数组元素的指针只可指向数组的首元素。 9.字符指针是指向字符串的指针,可以用字符串常量给字符指针赋值。 10.引用是一种变量,它也有值和地址值。 11.引用是某个变量的别名,引用是被绑定在被引用的变量上。

12.创建引用时要用一个同类型的变量进行初始化。 13.指针是变量,它可以有引用,而引用不能有引用。 ;. . 二单选题 1.下列关于定义一个指向double型变量的指针,正确的是()。A.int a(5);double *pd=a; B.double d(2.5),*pd=&d;C.double d(2.5),*pd=d; D.double a(2.5),pd=d;。).下列关于创建一个int型变量的引用,正确的是(2A.int a(3),&ra=a; B int . a(3),&ra=&a;ra=a;D.int a(3), C.double d(3.1);int &rd=d;.下列关于指针概念的描述中,错误的是()。3 A.指针中存放的 是某变量或对象的地址值.指针的类型是它所存放的数值的类型 B .指针是变量,它也具有一个内存地址值 C .指针的值是可以改 变的D 。.下列关于引用概念的描述中,错误的是()4 A.引 用是变量,它具有值和地址值 B.引用不可以作数组元素 C.引用是变量的别名 D.创建引用时必须进行初始化。++*p相同的是()*p=a5.已知:int a[5],;则与a[0] . B.*++p A++a[0] .C*p++ D.;. . 6.已知:int a[ ]={1,2,3,4,5},*p=a;在下列数组元素地址的表

结构体的指针应用

什么是结构体? 简单的来说,结构体就是一个可以包含不同数据类型的一个结构,它是一种可以自己定义的数据类型,它的特点和数组主要有两点不同,首先结构体可以在一个结构中声明不同的数据类型,第二相同结构的结构体变量是可以相互赋值的,而数组是做不到的,因为数组是单一数据类型的数据集合,它本身不是数据类型(而结构体是),数组名称是常量指针,所以不可以作为左值进行运算,所以数组之间就不能通过数组名称相互复制了,即使数据类型和数组大小完全相同。 定义结构体使用struct修饰符,例如: struct test { float a; int b; }; 上面的代码就定义了一个名为test的结构体,它的数据类型就是test,它包含两个成员a和b,成员a的数据类型为浮点型,成员b的数据类型为整型。由于结构体本身就是自定义的数据类型,定义结构体变量的方法和定义普通变量的方法一样。 test pn1; 这样就定义了一个test结构体数据类型的结构体变量pn1,结构体成员的访问通过点操作符进行,pn1.a=10 就对结构体变量pn1的成员a进行了赋值操作。注意:结构体生命的时候本身不占用任何内存空间,只有当你用你定义的结构体类型定义结构体变量的时候计算机才会分配内存。 结构体,同样是可以定义指针的,那么结构体指针就叫做结构指针。 结构指针通过->符号来访问成员,下面我们就以上所说的看一个完整的例子: #include #include using namespace std; struct test//定义一个名为test的结构体 { int a;//定义结构体成员a int b;//定义结构体成员b }; void main() { test pn1;//定义结构体变量pn1 test pn2;//定义结构体变量pn2 pn2.a=10;//通过成员操作符.给结构体变量pn2中的成员a赋值 pn2.b=3;//通过成员操作符.给结构体变量pn2中的成员b赋值

指针练习题

编程题 1用指向数组的指针变量输出数组的全部元素 2 使用函数调用,形参为指针,实参为数组,把一个数组逆序存放在输出 练习题: 一判断题 1.指针是变量,它具有的值是某个变量或对象的地址值,它还具有一个地址值,这两个地址值是相等的。 2.指针的类型是它所指向的变量或对象的类型。 3.定义指针时不可以赋初值。 4.指针可以赋值,给指针赋值时一定要类型相同,级别一致。 5.指针可以加上或减去一个int型数,也可以加上一个指针。 6.两个指针在任何情况下相减都是有意义的。 7.数组元素可以用下标表示,也可以用指针表示。 8.指向数组元素的指针只可指向数组的首元素。 9.字符指针是指向字符串的指针,可以用字符串常量给字符指针赋值。 10.引用是一种变量,它也有值和地址值。 11.引用是某个变量的别名,引用是被绑定在被引用的变量上。 12.创建引用时要用一个同类型的变量进行初始化。 13.指针是变量,它可以有引用,而引用不能有引用。

二单选题 1.下列关于定义一个指向double型变量的指针,正确的是()。 A.int a(5);double *pd=a;B.double d(2.5),*pd=&d;C.double d(2.5),*pd=d;D.double a(2.5),pd=d; 2.下列关于创建一个int型变量的引用,正确的是()。 A.int a(3),&ra=a;B.int a(3),&ra=&a; C.double d(3.1);int &rd=d;D.int a(3),ra=a; 3.下列关于指针概念的描述中,错误的是()。 A.指针中存放的是某变量或对象的地址值 B.指针的类型是它所存放的数值的类型 C.指针是变量,它也具有一个内存地址值 D.指针的值是可以改变的 4.下列关于引用概念的描述中,错误的是()。 A.引用是变量,它具有值和地址值 B.引用不可以作数组元素 C.引用是变量的别名 D.创建引用时必须进行初始化 5.已知:int a[5],*p=a;则与++*p相同的是()。 A.*++p B.a[0] C.*p++ D.++a[0]

C语言中指针、数组和引用例子实例

一、指针:内容是指示一个内存地址的变量;类型是指示编译器怎么解释指针内容指向地址中的内容,以及该内存区域有多大; 例子: [cpp] int i = 0; int * pi = &i; printf(“pi = %x \n”, pi); // 打印pi的内容: 0x2000 printf(“*pi= %d \n” , *pi); // 打印pi指向地址中的值: 5 printf(“&pi= %x \n”, &pi); // 打印pi的地址: 0x100 从汇编的角度来看,指针是这样的: int i = 0; 010E139E mov dword ptr [i],0 int * pi = &i; 010E13A5 lea eax,[i] 010E13A8 mov dword ptr [pi],eax 二、数组:是一个单一数据类型对象的集合。其中单个对象没有被命名,通过索引访问。 数组名和指针的区别:数组名的内涵在于其指代实体是一种数据结构,这种数据结构就是数组。数组名的外延在于其可以转换为指向其指代实体的指针,而且是一个指针常量。指向数组的指针则是另外一种变量类型,仅仅意味着数组的存放地址 注意:虽然数组名可以转换为指向其指代实体的指针,但是它只能被看作一个指针常量,不能被修改,如下:天骄无双:https://www.360docs.net/doc/a312997156.html, [cpp] int intArray[10]; intArray++; // 错误 “指针和数组等价”说的是什么?索引操作相同,例如:p[2]; a[2]; 三、引用(reference)是一个对象的别名。用对象初始化引用后,对象的名字和引用都指向该对象; 引用是如何实现的?从汇编语言的角度来看,指针和引用是一样的: [cpp] int i = 0; 00E9139E mov dword ptr [i],0 int & ref = i; 00E913A5 lea eax,[i] 00E913A8 mov dword ptr [ref],eax int * pi = &i; 00E913AB lea eax,[i] 00E913AE mov dword ptr [pi],eax 指针和引用的区别(从C++使用角度来看): 不存在空引用 引用要初始化 引用初始化后,不能指向另一个对象 这是由编译阶段保证的。 备注:一个指向非常量的引用不能用字面值或者临时值初始化;但是一个指向常量的引用可以。天骄无双:https://www.360docs.net/doc/a312997156.html,

指向函数的指针

指向函数的指针 c/c++ 2010-11-20 13:17:02 阅读41 评论0 字号:大中小订阅首先看这个程序: #include using namespace std; void max(int a, int b) { cout<<"now call max("<b?a:b; cout<

我曾经写过一个命令行程序,有很多命令,于是构着了一个结构的数组,大概是这样 struct{ char *cmd_name; bool (*cmd_fun)(); }cmd_info_list[MAX_CMD_NUM]; 程序中得到一个用户输入的命令字符串后,就匹配这个数组,找到对应的处理函数。 以后每次添加一个命令,只需要加个函数,然后在这个数组中加一个记录就可以了,不需要修改太多的代码。 这可以算是一种用法吧。呵呵。 Windows 中,窗口的回调函数就用到了函数指针。 用VC向导 New Projects ----> Win32 Application ----> A typical "Hello World!" application 其中的WndProc 是WNDPROC 类型的函数typedef LRESULT (CALLBACK* WNDPROC)(HWND, UINT, WPARAM, LPARAM); WndProc 作为窗口的回调函数,用来填充WNDCLASSEX 结构。 WNDCLASSEX wcex; wcex.lpfnWndProc = (WNDPROC)WndProc; void ListTraverse(LinkList L,void (*visit)(int)) { Link p; p=L->next; while(p) { visit(p->data); p=p->next; } return OK; } void print(int c) { printf("%d",c); } ListTraverse(L,print); 这算是个例子吧??? #include #include #include double Add (double x, double y) { return x+y; } double Sub (double x, double y) { return x-y; } double Mul (double x, double y)

指针和结构体练习题.

第十章指针 一.选择题 1.变量的指针,其含义是指该变量的。 A)值 B)地址 C)名 D)一个标志 2.已有定义int k=2;int *ptr1,*ptr2;且ptr1和ptr2均已指向变量k,下面不能正确执行的赋值语句是。 A)k=*ptr1+*ptr2 B)ptr2=k C)ptr1=ptr2 D)k=*ptr1*(*ptr2 3.若有说明:int *p,m=5,n;以下程序段正确的是。 A)p=&n ; B)p = &n ; scanf(“%d”,&p; scanf(“%d”,*p; C)scanf(“%d”,&n; D)p = &n ; *p=n ; *p = m ; 4.已有变量定义和函数调用语句:int a=25;print_value(&a;下面函数的输出结果是。 void print_value(int *x { printf(“%d\n”,++*x; } A)23 B)24 C)25 D)26 5.若有说明:int *p1, *p2,m=5,n;以下均是正确赋值语句的选项是。 A)p1=&m; p2=&p1 ; B)p1=&m; p2=&n; *p1=*p2 ; C)p1=&m; p2=p1 ; D)p1=&m; *p1=*p2 ; 6.若有语句:int *p,a=4;和p=&a;下面均代表地址的一组选项是。 A)a,p,*&a B)&*a,&a,*p C)*&p,*p,&a D)&a,&*p,p 7.下面判断正确的是。 A)char *a=”china”; 等价于char *a; *a=”china” ; B)char str[10]={“china”}; 等价于char str[10]; str[ ]={“china”;}

指向二维数组的指针

指向二维数组的指针 一. 二维数组元素的地址 为了说明问题, 我们定义以下二维数组: int a[3][4]={{0,1,2,3}, {4,5,6,7}, {8,9,10,11}}; a为二维数组名, 此数组有3行4列, 共12个元素。但也可这样来理解, 数组a由三个元素组成: a[0], a[1], a[2]。而它中每个元素又是一个一维数组, 且都含有4个元素(相当于4列), 例如, a[0]所代表的一维数组所包含的 4 个元素为a[0][0], a[0][1], a[0][2], a[0][3]。如图5.所示: ┏━━━━┓┏━┳━┳━┳━┓ a─→ ┃a[0] ┃─→┃0 ┃1 ┃2 ┃3 ┃ ┣━━━━┫┣━╋━╋━╋━┫ ┃a[1] ┃─→┃4 ┃5 ┃6 ┃7 ┃ ┣━━━━┫┣━╋━╋━╋━┫ ┃a[2] ┃─→┃8 ┃9 ┃10┃11┃ ┗━━━━┛┗━┻━┻━┻━┛ 图5. 但从二维数组的角度来看, a代表二维数组的首地址, 当然也可看成是二维数组第0行的首地址。a+1就代表第1行的首地址, a+2就代表第2行的首地址。如果此二维数组的首地址为1000, 由于第0行有4个整型元素, 所以a+1为1008, a+2 也就为1016。如图6.所示 a[3][4] a ┏━┳━┳━┳━┓ (1000)─→┃0 ┃1 ┃2 ┃3 ┃ a+1 ┣━╋━╋━╋━┫ (1008)─→┃4 ┃5 ┃6 ┃7 ┃ a+2 ┣━╋━╋━╋━┫ (1016)─→┃8 ┃9 ┃10┃11┃ ┗━┻━┻━┻━┛ 图6. 既然我们把a[0], a[1], a[2]看成是一维数组名, 可以认为它们分别代表它们所对应的数组的首地址, 也就是讲, a[0]代表第0 行中第0 列元素的地址, 即&a[0][0], a[1]是第1行中第0列元素的地址, 即&a[1][0], 根据地址运算规则, a[0]+1即代表第0行第1列元素的地址, 即&a[0][1], 一般而言, a[i]+j即代表第i行第j列元素的地址, 即&a[i][j]。 另外, 在二维数组中, 我们还可用指针的形式来表示各元素的地址。如前所述, a[0]与*(a+0)等价, a[1]与*(a+1)等价, 因此a[i]+j就与 *(a+i)+j等价, 它表示数组元素a[i][j]的地址。 因此, 二维数组元素a[i][j]可表示成*(a[i]+j)或*(*(a+i)+j), 它们都与a[i][j]等价, 或者还可写成(*(a+i))[j]。 另外, 要补充说明一下, 如果你编写一个程序输出打印a和*a, 你可发现它们的值是相同的, 这是为什么呢? 我们可这样来理解: 首先, 为了说明问题, 我们把二维数组人为地看成由三个数组元素a[0], a[1], a[2]组成, 将a[0], a[1], a[2]看成是数组名它们又分别是由4个元素组成的一维数组。因此, a表示数组第0行的地址, 而*a即为a[0], 它是数组名, 当然还是地址, 它就是数组第0 行第0 列元素的地址。 二. 指向一个由n个元素所组成的数组指针 在Turbo C中, 可定义如下的指针变量: int (*p)[3]; 指针p为指向一个由3个元素所组成的整型数组指针。在定义中, 圆括号是不能少的, 否则它是指针数组, 这将在后面介绍。这种数组的指针不同于前面介绍的整型指针, 当整型指针指向一个整型数组的元素时, 进行指针(地址)加1运算, 表示指向数组的下一个元素, 此时地址值增加了2(因为放大因子为2),而如上所定义的指向一个由3个元素组成的数组指针, 进行地址加1运算时, 其地址值增加了6(放大因子为2x3=6), 这种数组指针在Turbo C中用得较少, 但在处理二维数组时, 还是很方便的。例如:

指针在结构体中的应用.

实验14 指针在结构体中的应用 一、实验目的 1.掌握结构体类型指针的定义及使用方法。 2.掌握结构体类型指针作为函数参数,实现函数调用。 3.掌握简单链表的基本操作。 二、实验要求 1.通过阅读及编程,掌握结构体类型指针的定义及使用方法。 2.通过阅读及编程,掌握结构体类型指针作为函数参数,实现函数调用。 3.通过阅读及编程,掌握简单链表的基本操作(包括链表的建立、查找、遍历、插入、删除)。 三、实验内容 1.阅读下列程序,预测程序运行结果,然后上机验证。 main () { struct num { int a ; int b ; float f ; } n={ 1 , 3, 5.0 }; struct num * pn =&n ; printf ( “ %d\n ” , ( pn->b/n.a )*(++pn ->b) ); printf ( “ %f \n ” , ( *pn ).a + pn ->f ); } 1.读下列程序,指出程序的功能。 struct tm { int hours ; int minutes ; int seconds ; }; main ( ) { struct tm time ; time. hours=0 ; time. minutes =0; time . seconds =0 ;

for ( ; ; ) { update ( &time ); display (&time ); } } update ( struct tm * t ) { t-> seconds++; if ( t-> seconds= =60 ) { t-> seconds=0; t-> minues++; } if ( t-> minues= =60 ) { t-> minues=0; t-> hours++; } if ( t-> hours= =24 ) t-> hours=0; deday ( ); } display ( struct tm * t ) { printf ( “%d: ” , t-> hours ); printf ( “%d: ” , t-> minutes ); printf ( “%d:\n” , t-> seconds ); } delay ( ) { long int t; for ( t=1; t<12800 ; ++t ); } 3. 阅读并运行下列程序,写出运行结果。 #include “stdio.h” main ( ) { struct person { char name[20];

关于二维数组和指向指针的指针

以前一直有种误解: 二维数组的是数组的数组,所以数组的首地址是指向第一个元素指针,而这个元素又是一个数组,所以把数组首地址理解为指向指针的指针。 如int a[3][2];,以前一直认为a是一个指向int指针的指针,即是一个int**。最近发现这是错的。 如果int **p=a; 编译就会报错。如果强制转换int **p=(int **)a,则使用p[i][j]访问数组元素时出错。 首先,因为a的定义为int a[3][2];则a的类型是int* [3][2]数组类型,或者int* [][2],即指向大小为2的数组的指针,类型与int **不同,所以int **p=a;出错。 其次,考虑p[i][j]访问a的数组元素时出错的问题。当我们使用指向二维数组的指针的下标运算来访问数组元素时,如a[i][j],它等同于*(a+i*2+j);即必须要知道第二维的大小才能访问。考虑我使用p[i][j]的后果:p是int**,所以p[i]为*(p+i),而这个结果被视作一个指针,在这里记做pp=*(p+i),所以p[i][j]等同于pp[j]。最终的结果为*(pp+j),并将这个结果解释为一个int值。 int a[3][2]; int val=0; for(int i=0;i<3;++i) { for(int j=0;j<2;++j) { a[i][j]=val++; } } /*使用a[i][j]的方式显然可以正常访问该二维数组*/ /*下面使用指针直接访问,当然是不是int**了……*/ int *p=&a[0][0];/*注意,此处使用int *p=a;或者int *p=a[0];是不对的,p的类型是int型指针,*a或者a[0]是int (*)[2]类型,编译会报错的,* *尽管&a[0][0]、a、a[0]的数值相同……*/ for(int i=0;i<6;++i) { p[i];/*这样可以遍历所有元素*/ }

C语言中不同的结构体类型的指针间的强制转换详解

C语言中不同类型的结构体的指针间可以强制转换,很自由,也很危险。只要理解了其内部机制,你会发现C是非常灵活的。 一. 结构体声明如何内存的分布, 结构体指针声明结构体的首地址, 结构体成员声明该成员在结构体中的偏移地址。 变量的值是以二进制形式存储在内存中的,每个内存字节对应一个内存地址,而内存存储的值本身是没有整型,指针,字符等的区别的,区别的存在是因为我们对它们有不同的解读,param的值就是一个32位值,并且存储在某个内存单元中,通过这个32位值就能找到param所指向的结构的起始地址,通过这个起始地址和各个结构所包含变量离起始地址的偏移对这些变量进行引用, param->bIsDisable只是这种引用更易读的写法,只要param是指向 PAINT_PARAM的指针,那么param的值就肯定存在,param存在,偏移量已知,那么param->bIsDisable就肯定存在,只是要记住,param->bIsDisable只是代表了对param一定偏移地址的值。 不是说某个地址有那个结构体你才能引用,即使没有,你也能引用,因为你已经告诉了编译器param变量就是指向一个PAINT_PARAM结构体的变量并且指明了param的值,机器码的眼中是没有数据结构一说的,它只是机械的按照 指令的要求从内存地址取值,那刚才的例子来说,peg->x,peg->y的引用无论 0x30000000是否存在一个eg结构体都是合法的,如果0x30000000开始的8 个字节存在eg结构体,那么引用的就是这个结构体的值,如果这个位置是未定义的值,那么引用的结果就是这8个字节中的未定义值,内存位置总是存在的,而对内存中值的引用就是从这些内存位置对应的内存单元取值。 举个例子: typedefstruct_eg { int x; int y; }eg;

指向字符串的指针数组

在初学习C语言时,对于指针是最容易让人迷糊的,尤其对于指针数组,而且是指向字符串的指针数组,恐怕就更难理解了。下面本人给出一个例子,详细讲解指向字符串的指针数组的使用情况。希望给予学习C的朋友一点帮助。 下述程序执行后,输出结果是什么? #include char *p[2][3]={ "abc","defgh","ijkl","mnopqr","stuvw","xyz"}; main(){ printf("%c\n",***(p+1)); printf("%c\n",**p[0]); printf("%c\n",(*(*(p+1)+1))[4]); printf("%c\n",*(p[1][2]+2)); printf("%s\n",**(p+1)); } 答案是: m a w z mnopqr 答案解析: 这里相当于定义了2行3列共6个元素的数组,数组的每一个元素都是指向字符的指针变量。 其中p[0][0]指向串"abc",p[0][1]指向串"defgh",p[0][2] 指向串"ijkl",p[1][0]指向串"mnopqr",p[1][1]指向串"stuvw",p[1][2] 指向串"xyz"。 1、printf("%c\n",***(p+1)); 这里的***(p+1)相当于*(*(*(p+1)+0)+0),而*(*(p+1)+0)+0)的另一种容易懂的形式是p[1][0],在多维数组中这两种写法等价。如上面所写的p[1][0]是指向串"mnopqr",即保存的是串"mnopqr"的首地址,也即字母m的地址。因此***(p+1)是字母m 2、printf("%c\n",**p[0]); 这里的**p[0]等价于*(*(*(p+0)+0)+0),也即*(p[0][0]),而p[0][0])指向串"abc",所以*(p[0][0])是字符a 3、printf("%c\n",(*(*(p+1)+1))[4]); (*(*(p+1)+1))[4]等价于*((p[1][1])+4),而(p[1][1])指向串"stuvw",所以*((p[1][1])+4)是在串首向后移动4个单位的字符,也即w 4、printf("%c\n",*(p[1][2]+2)); 因为p[1][2]指向串"xyz",而p[1][2]+2 就是串首向后移动2个字节(一个字节保存一个字符),也就是指向字符z,所以*(p[1][2]+2)是字符z

C语言结构指针

C语言结构指针 这篇文章是九九年写的,这篇文章适合中级程序员。有不明白之处不要紧,多看几遍,然后花些时间上机操作及认真思考每个问题。遇到难题要研究、解决,难题出现于哪里?该用什么方式来解决?为什么要选择这个方式解决?有其它的解决方法吗?这样的解决方案完美吗?其实做个程序员这些基本的思考心得是要掌握的。记住;遇问题不要逃避,要面对现实、勇于挑战,仔细研究难题的所在,这样相信你会成功的! 指针结构与指针的关系亦有两重:其一是在定义结构时,将指针作为结构中的一个成员;其二是指向结构的指针(称为结构指针)。前者同一般的结构成员一样可直接进行访问,后者是本节讨论的重点。 结构指针说明的一般形式是: struct 结构类型名称* 结构指针变量名; 例如:struct date * pdate, today; 说明了两个变量,一个是指向结构date的结构指针pdate,today是一个date结构变量。语句: pdate = &today; pdate today (struct date) year month day 通过结构变量today访问其成员的操作,也可以用等价的指针形式表示: today.year = 2001;等价于(*pdate).year = 2001;

由于运算符"*"的优先级比运算符"."的优先级低,所以必须有"( )"将*pdate括起来。若省去括号,则含义就变成了"*(pdate.year)"。 在C语言中,通过结构指针访问成员可以采用运算符"->"进行操作,对于指向结 构的指针,为了访问其成员可以采用下列语句形式: 结构指针->成员名; 这样,上面通过结构指针pdate访问成员year的操作就可以写成: pdate->year = 2001; 如果结构指针p指向一个结构数组,那么对指针p的操作就等价于对数组下标的操作。 结构指针是指向一种结构类型的指针变量,它是结构在内存中的首地址,结构指针具有一般指针的特性,如在一定条件下两个指针可以进行比较,也可以与整数进行加减。但在指针操作时应注意:进行地址运算时的放大因子由所指向的结构的实际大小决定。 例11-7:用结构指针改写加密程序。 #include "stdio.h" struct table { char input, output; } ; struct table translate[ ]= { 'a', 'd', 'b', 'w', 'c', 'k', 'd', ';' , 'e', 'i', 'i', 'a', 'k', 'b', ';', 'c', 'w', 'e' }; /* 建立加密对照表*/ main( ) { char ch; struct table *p, *pend; /* p和pend为指向结构table的指针*/ pend = & translate[ sizeof(translate)/sizeof(struct table)-1 ]; /* pend指向结构数组translate的最后一个元素*/ while ( (ch=getchar( )) != '\n')

C语言——指向函数的指针

1函数类型(* 函数指针变量)();//指向函数的入口地址 一个函数是若干语句的集合,经编译后存储在函数代码存储区,并占有一片连续的存储空间,对函数指针只能用函数名赋值而无其他运算 1#include 2 3int max(int x ,int y); 4 5int main() 6{ 7int(* p)() ;//定义p是指向函数的指针变量 8int a , b , c ; 9 10p= max ;//将函数max的入口地址赋给指针变量p 11scanf("%d %d",&a ,&b) ; 12c= (* p)(a , b) ;//用指向函数的指针变量p调用函数 13printf("a = %d , b = %d , max = %d", a , b , c); 14 15return0; 16} 17 18int max(int x ,int y) 19{ 20int k ; 21k= (x> y)? x : y ; 22 23return k ; 24} 函数名作为实际参数: 1 #include 2 3int fun1(int a , int b) 4 { 5return a+b ; 6 } 7 8int fun2(int (*q)() , int x , int y) 9 { 10return (*q)(x , y) ; 11 } 12 13int main() 14 { 15int (*p)() , k ; 16 p = fun1 ;

17 k = fun2( p , 8 , 5 ) ; 18 19printf("k = %d \n" , k); //输出 13 20 21return0 ; 22 } 设置一个函数proc ,每次调用它会实现不同的功能,输入 a , b 两个数,第一次调用proc时,找出两者中最大者,第二次找出最小者,第三次调用求两数之差: 1 #include 2 3int max(int *x , int *y); 4int min(int *x , int *y); 5int a_b(int *x , int *y); 6int proc(int *x , int *y , int(*p)()); 7 8int main() 9 { 10int a , b ; 11 12printf("Enter a and b :"); 13scanf("%d %d" , &a , &b); 14 15printf("a = %d \t b = %d \n" , a , b); 16 17printf("max(%d,%d) = " , a , b); 18 proc(&a , &b , max); 19 20printf("min(%d,%d) = " , a , b); 21 proc(&a , &b , min); 22 23printf("%d - %d = " , a , b); 24 proc(&a , &b , a_b); 25 26return0 ; 27 } 28 29int max(int *x , int *y) 30 { 31int k ; 32 33 k = (*x > *y) ? *x : *y ; 34 35return k ; 36 } 37 38int min(int *x , int *y)

相关文档
最新文档