结构体内存分配分析

结构体内存分配分析
结构体内存分配分析

结构体成员的内存分布与对齐

我们先看一道IBM和微软的笔试题:

IBM笔试题:

struct{

short a1;

short a2;

short a3;

}A;

struct{

long a1;

short a2;

}B;

sizeof( A)=6, sizeof(B)=8,为什么?

注:sizeof(short)=2,sizeof(long)=4

微软笔试题:

struct example1

{

short a ;

long b;

};

struct example2

{

char c;

example1 struct1;

short e;

};

int main(int argc, char* argv[])

{

example2 e2;

int d=(unsigned int)&e2.struct1-(unsigned int)&e2.c;

printf("%d,%d,%d\n",sizeof(example1),sizeof(example2),d);

return 0;

}

输出结果?

要能清除的分析上面的问题就要搞清楚结构体变量的成员在内存里是如何分布的、成员先后顺序是怎样的、成员之间是连续的还是分散的、还是其他的什么形式?其实这些问题既和软件相关又和硬

件相关。所谓软件相关主要是指和具体的编程语言的编译器的特性相关,编译器为了优化CPU访问内存的效率,在生成结构体成员的起始地址时遵循着某种特定的规则,这就是所谓的结构体成员“对齐”;所谓硬件相关主要是指CPU的“字节序”问题,也就是大于一个字节类型的数据如int类型、short类型等,在内存中的存放顺序,即单个字节与高低地址的对应关系。字节序分为两类:Big-Endian和Little-Endian,有的文章上称之为“大端”和“小端”,他们是这样定义的:

Little-Endian就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端;Big-Endian 就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。

Intel、VAX和Unisys处理器的计算机中的数据的字节顺序是Little-Endian,IBM 大型机和大多数Unix平台的计算机中字节顺序是Big –Endian。

关与Big-Endian和Little-Endian问题本文暂不做详细讨论,本文将以小端机(此处为intel x86架构的计算机)、OS:WindowsXp和VC++6.0编译器来详细讨论结构体成员的“对齐”问题。

前面说了,为了优化CPU访问内存的效率,程序语言的编译器在做变量的存储分配时就进行了分配优化处理,优化规则大致原则是这样:

对于n字节的元素(n=2,4,8,...),它的首地址能被n整除,这种原则称为“对齐”,如WORD(2字节)的值应该能被2整除的位置,DWORD(4字节)应该在能被4整除的位置。

对于结构体来说,结构体的成员在内存中顺序存放,所占内存地址依次增高,第一个成员处于低地址处,最后一个成员处于最高地址处,但结构体成员的内存分配不一定是连续的,编译器会对其成员变量依据前面介绍的“对齐”原则进行处理。对待每个成员类似于对待单个n字节的元素一样,依次为每个元素找一个适合的首地址,使得其符合上述的“对齐”原则。通常编译器中可以设置一个对齐参数n,但这个n并不是结构体成员实际的对齐参数,VC++6.0中结构体的每个成员实际对齐参数N通常是这样计算得到的N=min(sizeof(该成员类型),n)(n为VC++6.0中可设置的值)。

成员的内存分配规律是这样的:从结构体的首地址开始向后依次为每个成员寻找第一个满足条件的首地址x,该条件是x % N = 0,并且整个结构的长度必须为各个成员所使用的对齐参数中最大的那个值的最小整数倍,不够就补空字节。

结构体中所有成员的对齐参数N的最大值称为结构体的对齐参数。

VC++6.0中n默认是8个字节,可以修改这个设定的对齐参数,方法为在菜单“工程”的“设置”中的“C/C++”选项卡的“分类”中“Code Generation ”的“Struct member alignment”中设置,1byte、2byte、4byte、8byte、16byte等几种,默认为8byte

也可以程序控制,采用指令:#pragma pack(xx)控制

如#pragma pack(1),1字节对齐,#pragma pack(4),4字节对齐 #pragma pack(16),16字节对齐

接下来我们将分不同的情况来详细讨论结构体成员的分布情况,顺便提醒一下, 常见类型的长度: Int 4byte, Short 2byte, Char 1byte, Double 8byte, Long 4byte

让我们先看下例: struct A { char c; //1byte double d; //8byte short s; //2byte int

i; //4byte

};

int main(int argc, char* argv[]) { A strua;

printf("%len:d\n",sizeof(A));

printf("%d,%d,%d,%d",&strua.c,&strua.d,&strua.s,&strua.i); return 0;

}

1)n 设置为8byte 时 结果:len:24,

1245032,1245040,1245048,1245052 内存中成员分布如下:

strua.c 分配在一个起始于8的整数倍的地址1245032(为什么是这样读者先自己思考,读完就会明白),接下来要在strua.c 之后分配strua.d ,由于double 为8字节,取N=min(8,8),8字节来对齐,所以从strua.c 向后找第一个能被8整除的地址,所以取1245032+8得1245040, strua.s 为2byte 小于参数n,所以N=min

补0

d 补0

c s

4byte

4byte

Strua 1245032

i

1245040

1245048

(2,8),即N=2,取2字节长度对齐,所以要从strua.d 后面寻找第一个能被2整除的地址来存储strua.s ,由于strua.d 后面的地址为1245048可以被2整除,所以strua.s 紧接着分配,现在来分配strua.i,int 为4byte ,小于指定对齐参数8byte ,所以N=min (4,8)取N=4byte 对齐,strua.s 后面第一个能被4整除地址为1245048+4,所以在1245048+4的位置分配了strua.i ,中间补空,同时由于所有成员的N 值的最大值为8,所以整个结构长度为8byte 的最小整数倍,即取24byte 其余均补0. 于是该结构体的对齐参数就是8byte 。

2)当对齐参数n 设置为16byte 时,结果同上,不再分析

3)当对齐参数设置为4byte 时 上例结果为:Len:20

1245036,1245040,1245048,1245052 内存中成员分布如下:

Strua.c 起始于一个4的整数倍的地址,接下来要在strua.c 之后分配strua.d ,由于strua.d 长度为8byte ,大于对齐参数4byte ,所以N=min (8,4)取最小的4字节,所以向后找第一个能被4整除的地址来作为strua.d 首地址,故取1245036+4,接着要在strua.d 后分配strua.s ,strua.s 长度为2byte 小于4byte ,取N=min (2,4)2byte 对齐,由于strua.d 后的地址为1245048可以被2

整除,所以直接在strua.d 后面分配,strua.i 的长度为4byte ,所以取N=min (4,4)4byte 对齐,所以从strua.s 向后找第一个能被4整除的位置即1245048+4来分配和strua.i ,同时N 的最大值为4byte ,所以整个结构的长度为4byte 的最小整数倍16byte

4)当对齐参数设置为2byte 时 上例结果为:Len:16

1245040,1245042,1245050,1245052

c d

s 补0

补0

4byte

Strua

1245036

1245040

1245052

i

1245048

Strua.c 分配后,向后找一第一个能被2整除的位置来存放strua.d,依次类推

5)1byte 对齐时: 上例结果为:Len:15

1245040,1245041,1245049,1245051

此时,N=min (sizeof (成员),1),取N=1,由于1可以整除任何整数,所以各个成员依次分配,没有间空,如下图所示:

6)当结构体成员为数组时,并不是将整个数组当成一个成员来对待,而是将数组的每个元素当一个成员来分配,其他分配规则不变,如将上例的结构体改为: struct A { char c ; //1byte double d; //8byte short s; //2byte char

szBuf[5];

};

对齐参数设置为8byte ,则,运行结果如下: Len:24

1245032,1245040,1245048,1245050

Strua 的s 分配后,接下来分配Strua 的数组szBuf[5],这里要单独分配它的每个元素,由于是char 类

补0

d szBuf

c s1

补0

8byte

c

d

s

i

1byte

8byte

2byte

4byte

补0

d

c s i

Strua.c 1245040

2byte

型,所以N=min(1,8),取N=1,所以数组szBuf[5]的元素依次分配没有间隙。

7)当结构中有成员不是一个完整的类型单元,如int或short型,而是该类型的一段时,即位段时,如

struct A

{

int a1:5;

int a2:9;

char c;

int b:4;

short s;

};

对于位段成员,存储是按其类型分配空间的,如int 型就分配4个连续的存储单元,如果是相邻的同类型的段位成员就连续存放,共用存储单元,此处如a1,a2将公用一个4字节的存储单元,当该类型的长度不够用时,就另起一个该类型长度的存储空间。有位段时的对齐规则是这样:同类型的、相邻的可连续在一个类型的存储空间中存放的位段成员作为一个该类型的成员变量来对待,不是同类型的、相邻的位段成员,分别当作一个单独得该类型的成员来对待,分配一个完整的类型空间,其长度为该类型的长度,其他成员的分配规则不变,仍然按照前述的对齐规则进行。

对于 struct A,VC++6.0中n设置为8时,sizeof(A)=16,内存分布:

a1 a2

c

d 空

s

又如:

struct B

{

int a:5;

int b:7;

int c:6;

int d:9;

char e:2;

int x;

};

Vc++6.0的对齐参数设置为8、16、4字节对齐时,sizeof(A)=12内存分布为:

(灰色部分未使用)

当对齐参数设置为2字节时:(灰色部分未使用)sizeof(A)=10

又如intel 的笔试题: #include “stdafx.h ” #include struct bit {

int a:3; int b:2; int c:3; };

int main(int argc, char* argv[]) { bit s;

char *c = (char*)&s; *c = 0x99;

cout<

运行的结果是 1 -1 -4

结构bit 的成员在内存中由低地址到高地址顺序存放,执行 *c=0x99;后成员的内存分布情况为:

x

e a b

d 2byte

空 x

ec d c b

a

4byte

8)当结构体成员是结构体类型时,那么该过程是个递归过程,且把该成员作为一个整体来对待,如(微软笔试题): struct example1 { short a ; long b;

};

struct example2 { char c;

example1 struct1; short e; };

int main(int argc, char* argv[]) { example2 e2;

int d=(unsigned int)&e2.struct1-(unsigned int)&e2.c; printf("%d,%d,%d\n",sizeof(example1),sizeof(example2),d); return 0;

}

8byte 对齐时,结果为: 8,16,4 内存分布为:

因为example1的对齐参数为4,分配完c 后要接着分配struct1,这时的对齐参数为min(struct1的对齐参数,指定对齐参数),开始分配struct1,在struct1的成员分配过程中又是按照前述的规则来分配的。

c 补0

a 补0

b e

补0

example2

example1

4byte

&s

100

11

001

c

a

b

c

关于结构体内存对齐

内存对齐”应该是编译器的“管辖范围”。编译器为程序中的每个“数据单元”安排在适当的位置上。但是C语言的一个特点就是太灵活,太强大,它允许你干预“内存对齐”。如果你想了解更加底层的秘密,“内存对齐”对你就不应该再透明了。

一、内存对齐的原因

大部分的参考资料都是如是说的:

1、平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。

2、性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。

二、对齐规则

每个特定平台上的编译器都有自己的默认“对齐系数”(也叫对齐模数)。程序员可以通过预编译命令#pragma pack(n),n=1,2,4,8,16来改变这一系数,其中的n就是你要指定的“对齐系数”。

对齐步骤:

1、数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员的对齐按照#pragma pack指定的数值和这个数据成员自身长度中,比较小的那个进行。

2、结构(或联合)的整体对齐规则:在数据成员完成各自对齐之后,结构(或联合)本身也要进行对齐,对齐将按照#pragma pack指定的数值和结构(或联合)最大数据成员长度中,比较小的那个进行。

3、结合1、2颗推断:当#pragma pack的n值等于或超过所有数据成员长度的时候,这个n值的大小将不产生任何效果。

备注:数组成员按长度按数组类型长度计算,如char t[9],在第1步中数据自身长度按1算,累加结构体时长度为9;第2步中,找最大数据长度时,如果结构体T有复杂类型成员A的,该A成员的长度为该复杂类型成员A的最大成员长度。

三、试验

我们通过一系列例子的详细说明来证明这个规则吧!

我试验用的编译器包括GCC 3.4.2和VC6.0的C编译器,平台为Windows XP + Sp2。

我们将用典型的struct对齐来说明。首先我们定义一个struct:

#pragma pack(n) /* n = 1, 2, 4, 8, 16 */

struct test_t {

int a;

char b;

short c;

char d;

#pragma pack(n)

首先我们首先确认在试验平台上的各个类型的size,经验证两个编译器的输出均为:

sizeof(char) = 1

sizeof(short) = 2

sizeof(int) = 4

我们的试验过程如下:通过#pragma pack(n)改变“对齐系数”,然后察看sizeof(struct test_t)的值。

1、1字节对齐(#pragma pack(1))

输出结果:sizeof(struct test_t) = 8 [两个编译器输出一致]

分析过程:

1) 成员数据对齐

#pragma pack(1)

struct test_t {

int a; /* 长度4 < 1 按1对齐;起始offset=0 0%1=0;存放位置区间[0,3] */

char b; /* 长度1 = 1 按1对齐;起始offset=4 4%1=0;存放位置区间[4] */

short c; /* 长度2 > 1 按1对齐;起始offset=5 5%1=0;存放位置区间[5,6] */

char d; /* 长度1 = 1 按1对齐;起始offset=7 7%1=0;存放位置区间[7] */

};

#pragma pack()

成员总大小=8

2) 整体对齐

整体对齐系数= min((max(int,short,char), 1) = 1

整体大小(size)=$(成员总大小) 按$(整体对齐系数) 圆整= 8 /* 8%1=0 */ [注1]

2、2字节对齐(#pragma pack(2))

输出结果:sizeof(struct test_t) = 10 [两个编译器输出一致]

分析过程:

1) 成员数据对齐

#pragma pack(2)

struct test_t {

int a; /* 长度4 > 2 按2对齐;起始offset=0 0%2=0;存放位置区间[0,3] */

char b; /* 长度1 < 2 按1对齐;起始offset=4 4%1=0;存放位置区间[4] */

short c; /* 长度2 = 2 按2对齐;起始offset=6 6%2=0;存放位置区间[6,7] */

char d; /* 长度1 < 2 按1对齐;起始offset=8 8%1=0;存放位置区间[8] */

};

#pragma pack()

成员总大小=9

2) 整体对齐

整体对齐系数= min((max(int,short,char), 2) = 2

整体大小(size)=$(成员总大小) 按$(整体对齐系数) 圆整= 10 /* 10%2=0 */ 3、4字节对齐(#pragma pack(4))

输出结果:sizeof(struct test_t) = 12 [两个编译器输出一致]

分析过程:

1) 成员数据对齐

#pragma pack(4)

struct test_t {

int a; /* 长度4 = 4 按4对齐;起始offset=0 0%4=0;存放位置区间[0,3] */ char b; /* 长度1 < 4 按1对齐;起始offset=4 4%1=0;存放位置区间[4] */ short c; /* 长度2 < 4 按2对齐;起始offset=6 6%2=0;存放位置区间[6,7] */ char d; /* 长度1 < 4 按1对齐;起始offset=8 8%1=0;存放位置区间[8] */ };

#pragma pack()

成员总大小=9

2) 整体对齐

整体对齐系数= min((max(int,short,char), 4) = 4

整体大小(size)=$(成员总大小) 按$(整体对齐系数) 圆整= 12 /* 12%4=0 */ 4、8字节对齐(#pragma pack(8))

输出结果:sizeof(struct test_t) = 12 [两个编译器输出一致]

分析过程:

1) 成员数据对齐

#pragma pack(8)

struct test_t {

int a; /* 长度4 < 8 按4对齐;起始offset=0 0%4=0;存放位置区间[0,3] */ char b; /* 长度1 < 8 按1对齐;起始offset=4 4%1=0;存放位置区间[4] */ short c; /* 长度2 < 8 按2对齐;起始offset=6 6%2=0;存放位置区间[6,7] */ char d; /* 长度1 < 8 按1对齐;起始offset=8 8%1=0;存放位置区间[8] */ };

#pragma pack()

成员总大小=9

2) 整体对齐

整体对齐系数= min((max(int,short,char), 8) = 4

整体大小(size)=$(成员总大小) 按$(整体对齐系数) 圆整= 12 /* 12%4=0 */

5、16字节对齐(#pragma pack(16))

输出结果:sizeof(struct test_t) = 12 [两个编译器输出一致]

分析过程:

1) 成员数据对齐

#pragma pack(16)

struct test_t {

int a; /* 长度4 < 16 按4对齐;起始offset=0 0%4=0;存放位置区间[0,3] */ char b; /* 长度1 < 16 按1对齐;起始offset=4 4%1=0;存放位置区间[4] */ short c; /* 长度2 < 16 按2对齐;起始offset=6 6%2=0;存放位置区间[6,7] */ char d; /* 长度1 < 16 按1对齐;起始offset=8 8%1=0;存放位置区间[8] */ };

#pragma pack()

成员总大小=9

2) 整体对齐

整体对齐系数= min((max(int,short,char), 16) = 4

整体大小(size)=$(成员总大小) 按$(整体对齐系数) 圆整= 12 /* 12%4=0 */

记录类型的内存分配!

Packed Record和Record的不同之处!

type

MyRec=Record

var1:integer;

var2,var3,var4,var5,var6,var7,var8:shortint;

var9:integer;

var10:shortint;

var11:integer;

var12,var13:shortint;

end;

...

ShowMessage(intTostr(SizeOf(MyRec)));

结果显示为18,而按我想象应为16。请高手讲解一下Delphi5.0中变量内存空间分配机制,因为我有一个数组MyArray:Array[1..1000000] of MyRec;需要考虑节省内存问题,

另外不要说我懒不爱看书,我手头所有关于Delphi的书都没有提到这个问题。

回答:

显示的结果应该为28,而不是18!按道理应该是22。用Packed的结果就是22。

拟定义的数组比较大,应该用packed record!

原因如下:

在Windows中内存的分配一次是4个字节的。而Packed按字节进行内存的申请和分配,这样速度要慢一些,因为需要额外的时间来进行指针的定位。因此如果不用Packed的话,Delphi将按一次4个字节的方式申请内存,因此如果一个变量没有4个字节宽的话也要占4个字节!这样就浪费了。按上面的例子来说:

var1:integer;//integer刚好4个字节!

var2-var5占用4个字节,Var6-Var8占用4个字节,浪费了一个字节。

var9:integer//占用4个字节;

var10:占用4个字节;浪费3个字节

var11:占用4个字节;

var12,var13占用4个字节;浪费2个字节

所以,如果不用packed的话,那么一共浪费6个字节!所以原来22个字节的记录需要28个字节的内存空间!

****************

回复人:eDRIVE(eDRIVE)(2001-3-2 17:45:00) 得0分

这是因为在32位的环境中,所有变量分配的内存都进行“边界对齐”造成的。这样做可以对速度有优化作用;但是单个定义的变量至少会占用32位,即4个字节。所以会有长度误差,你可以用packed关键字取消这种优化。

深入的分析,内存空间(不是内存地址)在计算机中划分为无数与总线宽度一致的单位,单位之间相接的地方称为“边界”;总线在对内存进行访问时,每次访问周期只能读写一个单位(32bit),如果一个变量横跨“边界”的话,则读或写这个变量就得用两个访问周期,而“边界对齐”时,只需一个访问周期,速度当然会有所优化。

Record的数据各个字节都是对齐的,数据格式比较完整,所以这种格式相对packed占用的内存比较大,但是因为格式比较整齐,所以电脑读取这个类型的数据的时候速度比较快。

而Packed Record对数据进行了压缩,节省了内存空间,当然他的速度也变的慢了。

type

// Declare an unpacked record

TDefaultRecord = Record

name1 : string[4];

floater : single;

name2 : char;

int : Integer;

end;

// Declare a packed record

TPackedRecord = Packed Record

name1 : string[4];

floater : single;

name2 : char;

int : Integer;

end;

var

defaultRec : TDefaultRecord;

packedRec : TPackedRecord;

begin

ShowMessage('Default record size = '+IntToStr(SizeOf(defaultRec)));

ShowMessage('Packed record size = '+IntToStr(SizeOf(packedRec)));

end;

Default record size = 20

Packed record size = 14

不过,对于现在的操作系统来,packed Record 节省的那些空间已不用考虑他了。除了做DLL(不用packed容易造成内存混乱)和做硬件编程时(比如串口)编程时必须用到packed Record,其它情况都可以用Record

C的结构体与Delphi中的记录类型

Object Pascal的指针

一、类型指针的定义。对于指向特定类型的指针,在C中是这样定义的:

int *ptr;

char *ptr;

与之等价的Object Pascal是如何定义的呢?

var

ptr : ^Integer;

ptr : ^char;

其实也就是符号的差别而已。

二、无类型指针的定义。C中有void *类型,也就是可以指向任何类型数据的指针。Object Pasca

l为其定义了一个专门的类型:Pointer。于是,

ptr : Pointer;

就与C中的

void *ptr;

等价了。

三、指针的解除引用。要解除指针引用(即取出指针所指区域的值),C 的语法是(*ptr),Object

Pascal则是ptr^。

四、取地址(指针赋值)。取某对象的地址并将其赋值给指针变量,C 的语法是

ptr = &Object;

Object Pascal 则是

ptr := @Object;

也只是符号的差别而已。

五、指针运算。在C中,可以对指针进行移动的运算,如:

char a[20];

char *ptr=a;

ptr++;

ptr+=2;

当执行ptr++;时,编译器会产生让ptr前进sizeof(char)步长的代码,之后,ptr将指向a[1]。ptr+=2;这句使得ptr前进两个sizeof(char)大小的步长。同样,我们来看一下Object Pascal中如何实现:

var

a : array [1..20] of Char;

ptr : PChar; //PChar 可以看作^Char

begin

ptr := @a;

Inc(ptr); // 这句等价于C 的ptr++;

Inc(ptr, 2); //这句等价于C 的ptr+=2;

end;

六、动态内存分配。C中,使用malloc()库函数分配内存,free()函数释放内存。如这样的代码: int *ptr, *ptr2;

int i;

ptr = (int*) malloc(sizeof(int) * 20);

ptr2 = ptr;

for (i=0; i<20; i++){

*ptr = i;

ptr++;

}

free(ptr2);

Object Pascal中,动态分配内存的函数是GetMem(),与之对应的释放函数为FreeMem()(传统Pascal中获取内存的函数是New()和Dispose(),但New()只能获得对象的单个实体的内存大小,无法取得连续的存放多个对象的内存块)。因此,与上面那段C的代码等价的Object Pascal的代码为: var ptr, ptr2 : ^integer;

i : integer;

begin

GetMem(ptr, sizeof(integer) * 20);

//这句等价于C的ptr = (int*) malloc(sizeof(int) * 20);

ptr2 := ptr; //保留原始指针位置

for i := 0 to 19 do

begin

ptr^ := i;

Inc(ptr);

end;

FreeMem(ptr2);

end;

对于以上这个例子(无论是C版本的,还是Object Pascal版本的),都要注意一个问题,就是分配内存的单位是字节(BYTE),因此在使用GetMem时,其第二个参数如果想当然的写成20,那么就会出问题了(内存访问越界)。因为GetMem(ptr, 20);实际只分配了20个字节的内存空间,而一个整形的大小是四个字节,那么访问第五个之后的所有元素都是非法的了(对于malloc()的参数同样)。

七、字符数组的运算。C语言中,是没有字符串类型的,因此,字符串都是用字符数组来实现,于是也有一套str打头的库函数以进行字符数组的运算,如以下代码:

char str[15];

char *pstr;

strcpy(str, "teststr");

strcat(str, "_testok");

pstr = (char*) malloc(sizeof(char) * 15);

strcpy(pstr, str);

printf(pstr);

free(pstr);

而在Object Pascal中,有了String类型,因此可以很方便的对字符串进行各种运算。但是,有时我们的Pascal代码需要与C的代码交互(比如:用Object Pascal的代码调用C写的DLL或者用O bject Pascal写的DLL准备允许用C写客户端的代码)的话,就不能使用String类型了,而必须使用两种语言通用的字符数组。其实,Object Pascal提供了完全相似C的一整套字符数组的运算函数,以上那段代码的Object Pascal版本是这样的:

var str : array [1..15] of char;

pstr : PChar; //Pchar 也就是^Char

begin

StrCopy(@str, 'teststr'); //在C中,数组的名称可以直接作为数组首地址指针来用

//但Pascal不是这样的,因此str前要加上取地址的运算符

StrCat(@str, '_testok');

GetMem(pstr, sizeof(char) * 15);

StrCopy(pstr, @str);

Write(pstr);

FreeMem(pstr);

end;

八、函数指针。在动态调用DLL中的函数时,就会用到函数指针。假设用C写的一段代码如下: typedef int (*PVFN)(int); //定义函数指针类型

int main()

{

HMODULE hModule = LoadLibrary("test.dll");

PVFN pvfn = NULL;

pvfn = (PVFN) GetProcAddress(hModule, "Function1");

pvfn(2);

FreeLibrary(hModule);

}

就我个人感觉来说,C语言中定义函数指针类型的typedef代码的语法有些晦涩,而同样的代码在Object Pascal中却非常易懂:

type PVFN = Function (para : Integer) : Integer;

var

fn : PVFN;

//也可以直接在此处定义,如:fn : function (para:Integer):Integer;

hm : HMODULE;

begin

hm := LoadLibrary('test.dll');

fn := GetProcAddress(hm, 'Function1');

fn(2);

FreeLibrary(hm);

end;

以上是一位Delphi高手给我回的贴!

c语言结构体作业

1、当说明一个结构体变量时系统分配给它的内存是A A)各成员所需内存量的总和 B)结构中第一个成员所需内存量 C)成员中占内存量最大者所需的容量 D)结构中最后一个成员所需内存量 2、以下对结构体类型变量td的定义中,错误的是C A)typedef struct aa {int n; fliat m; }AA; AA td; B)struct aa {int n; fliat m; }; struct aa td; C)struct yy {int n; float m; }aa; Struct yy td; D)struct yy { int n; float m; }td; 3、下列程序的输出结果是B struct abc { int a, b, c; }; main() { struct abc s[2]={{1,2,3},{4,5,6}}; int t; t=s[0].a+s[1].b; printf("%d \n",t); } A)5 B)6 C)7 D)8 4、设有如下说明A typedef struct yy { int n; char c; double x;}STD; 则以下选项中,能正确定义结构体数组并赋初值的语句是 A)STD tt[2]={{1,'A',62},{2, 'B',75}}; B)STD tt[2]={1,"A",62},{2, "B",75}; C)struct yy tt[2]={{1,'A'},{2, 'B'}}; D)struct yy tt[2]={{1,"A",62.5},{2,"B",75.0}}; 5、在32位IBM-PC机上使用C语言,若有如下定义 struct data { int i; char ch[8]; double f; }b; 则结构变量b占用内存的字节数是C A)13 B)8 C)16 D)24

结构体指针

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语言,结构体(struct) 用法 结构(struct) 结构是由基本数据类型构成的、并用一个标识符来命名的各种变量的组合。 结构中可以使用不同的数据类型。 1. 结构说明和结构变量定义 在T urbo C中, 结构也是一种数据类型, 可以使用结构变量, 因此, 象其它 类型的变量一样, 在使用结构变量时要先对其定义。 定义结构变量的一般格式为: struct 结构名 { 类型变量名; 类型变量名; ... } 结构变量; 结构名是结构的标识符不是变量名。 类型为第二节中所讲述的五种数据类型(整型、浮点型、字符型、指针型和 无值型)。 构成结构的每一个类型变量称为结构成员, 它象数组的元素一样, 但数组中 元素是以下标来访问的, 而结构是按变量名字来访问成员的。

下面举一个例子来说明怎样定义结构变量。 struct string { char name[8]; int age; char sex[2]; char depart[20]; float wage1, wage2, wage3, wage4, wage5; } person; 这个例子定义了一个结构名为string的结构变量person, 如果省略变量名 person, 则变成对结构的说明。用已说明的结构名也可定义结构变量。这样定义 时上例变成: struct string { char name[8]; int age; char sex[2]; char depart[20]; float wage1, wage2, wage3, wage4, wage5; }; struct string person; 如果需要定义多个具有相同形式的结构变量时用这种方法比较方便, 它先作 结构说明, 再用结构名来定义变量。 例如: struct string T ianyr, Liuqi, ...; 如果省略结构名, 则称之为无名结构, 这种情况常常出现在函数内部, 用这 种结构时前面的例子变成:

C语言结构体习题及答案

第9章结构体 1.定义以下结构体类型 struct s { int a; char b; float f; }; 则语句printf("%d",sizeof(struct s))的输出结果为【】。 A) 3 B) 7 C) 6 D) 4 2.当定义一个结构体变量时,系统为它分配的内存空间是【】 A)结构中一个成员所需的内存容量 B)结构中第一个成员所需的内存容量 C)结构体中占内存容量最大者所需的容量 D)结构中各成员所需内存容量之和 3.定义以下结构体类型 struct s { int x; float f; }a[3]; 语句printf("%d",sizeof(a))的输出结果为【】 A) 4 B) 12 C) 18 D) 6 7.定义以下结构体类型 struct student { char name[10]; int score[50]; float average; }stud1; 则stud1占用内存的字节数是【】。 A) 64 B) 114 C) 228 D) 7 9、设有一结构体类型变量定义如下: struct date { int year; int month; int day; }; struct worklist { char name[20]; char sex; struct date birthday; } person; 若对结构体变量person的出生年份进行赋值时,下面正确的赋值语句是。。。。

A. year=1976 B. birthday.year=1976 C. person.birthday.year=1976 D. person.year=1976 1、若程序中有以下的说明和定义: struct abc { int x;char y; } 花括号后少了分号。 struct abc s1,s2; 则会发生的情况是______。 A) 编译时错B) 程序将顺序编译、连接、执行C) 能顺序通过编译、连接、但不能执行D) 能顺序通过编译、但连接出错

指针和结构体练习题.

第十章指针 一.选择题 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”;}

结构体的指针应用

什么是结构体? 简单的来说,结构体就是一个可以包含不同数据类型的一个结构,它是一种可以自己定义的数据类型,它的特点和数组主要有两点不同,首先结构体可以在一个结构中声明不同的数据类型,第二相同结构的结构体变量是可以相互赋值的,而数组是做不到的,因为数组是单一数据类型的数据集合,它本身不是数据类型(而结构体是),数组名称是常量指针,所以不可以作为左值进行运算,所以数组之间就不能通过数组名称相互复制了,即使数据类型和数组大小完全相同。 定义结构体使用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赋值

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;

指针和结构体练习题

第十章指针 一?选择题 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 prin t_value(i nt *x) { printf( %d\n ”++*x); } A) 23 B )24 C ) 25 D )26 5. 若有说明:int *p1, *p2,m=5,n; _____________ 以下均是正确赋值语句的选项是 B) p 仁&m; p2=&n; *p1 =* p2 ; C) p 仁&m; p2=p1 ; D ) p 仁&m; *p 仁*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= "ch in a ” 等价于 char *a; *a= "ch in a "; B) char str[1O]={ “hina ”;等价于 char str[1O]; str[ ]={ “hina";} C) char *s= "ch in a "; 等价于 char *s; s= "ch in a "; D) char c[4]= "abc ",d[4]= "abc ";等价于 char c[4]=d[4]= "abc "; 8. _______________________________________________ 下面程序段中,for 循环的执行次数是 ______________________________________________________ 。 char *s= "\ta\018bc "; for ( ; *s!= '\0'; s++) printf( *” A) 9 B ) 7 9. 下面能正确进行字符串赋值操作的是 A) char s[5]={ ABCDE ”; C ) char *s ; s= "ABCDE "; 10. 下面程序段的运行结果是 ________ char *s= "abcde"; s+=2 ; printf( %d",s); A) cde B )字符'' C )字符’c'的地址 D )不确定 11. 设pl 和p2是指向同一个字符串的指针变量, c 为字符变量,则以下不能正确执行的赋 值语句是 ________________ 。 A) c=*p1+*p2 B ) p2=c C ) p 仁p2 D ) c=*p1*(*p2) A ) p 仁&m; p2=&p1 ; C ) 6 D ) 5 B ) char s[5]={ A \'\'C','D','E '; D ) char *s; scanf( %s",s);

结构体的定义及初始化

?结构体类型定义 struct [结构体名] { 类型标识符成员名; 类型标识符成员名; ……………. };成员类型可以是基本型或构造型 struct是关键字,不能省略合法标识符 可省:无名结构体 结构体的说明及结构体变量的定义

例struct student { int num; char name[20]; char sex; int age; float score; char addr[30]; }; name num sex age score addr 2字节 2字节 20字节 1字节 4字节 30字节 … ….. 结构体类型定义描述结构 的组织形式,不分配内存 例子图解

?结构体类型定义 struct [结构体名] { 类型标识符成员名; 类型标识符成员名; ……………. };成员类型可以是基本型或构造型 struct是关键字,不能省略合法标识符 可省:无名结构体 结构体的说明及结构体变量的定义

(1) 在结构体说明的同时定义结构体变量,例如:struct example { char *name; int age; }guo,zhang;(2)直接定义结构体变量,例如: struct {char *name; int age; }guo,zhang 未给 出结 构体 名 (3) 把定义和说明分开,例如:struct example { char *name; int age; }; struct example guo,zhang;结构体变量占用内存的大小可用sizeof()运算来求出 ?结构体变量的定义

结构体的说明及结构体变量的定义?变量说明形式 struct 结构体名结构体变量名; ?注意: 结构变量的存储类型概念、它的寿命、可见 性及使用范围与普通变量、数组等完全一致。 结构体变量说明必须在结构类型定义之后, 二者也可同时进行。

《动态分配内存与数据结构》课后习题

《动态分配内存与数据结构》习题 学号姓名 一、选择题 1、是一种限制存取位置的线性表,元素的存取必须服从先进先出的规则。 A.顺序表B.链表C.栈D.队列 2、是一种限制存取位置的线性表,元素的存取必须服从先进后出的规则。 A.顺序表B.链表C.栈D.队列 3、与顺序表相比,链表不具有的特点是。 A.能够分散存储数据,无需连续内存空间 B.插入和删除无需移动数据 C.能够根据下标随机访问 D.只要内存足够,没有最大长度的限制 4、如果通过new运算符动态分配失败,返回结果是。 A.-1 B.0 C.1D.不确定 5、实现深复制中,不是必须自定义的。 A.构造函数B.复制构造函数 C.析构函数D.复制赋值操作符函数 6、分析下列代码是否存在问题,选择合适的选项:。 int main(void) { int *p = new int [10]; p = new int [10]; delete [] p; p = NULL; return 0; } A.没有问题 B.有内存泄漏 C.存在空悬指针 D.存在重复释放同一空间 7、通过new运算符动态分配的对象,存储于内存中的。 A.全局变量与静态变量区 B.代码区 C.栈区 D.堆区 8、下列函数中,可以是虚函数。 A.构造函数 B.析构函数 C.静态成员函数 D.友元函数 9、关于通过new运算符动态创建的对象数组,下列判断中是错误的。 A. 动态创建的对象数组只能调用默认构造函数 B. 动态创建的对象数组必须调用delete []动态撤销 C. 动态创建的对象数组的大小必须是常数或常变量 D. 动态创建的对象数组没有数组名 10、顺序表不具有的特点是 A. 元素的存储地址连续 B. 存储空间根据需要动态开辟,不会溢出 C. 可以直接随机访问元素 D. 插入和删除元素的时间开销与位置有关 11、假设一个对象Ob1的数据成员是指向动态对象的指针,如果采用浅复制的方式复制该对象得到对象Ob2,那么在析构对象Ob1和对象Ob2时会的问题。 A. 有重复释放 B. 没有 C. 内存泄漏 D. 动态分配失败 12、假设对5个元素A、B、C、D、E进行压栈或出栈的操作,压栈的先后顺序是ABCDE,则出栈的先后顺序不可能是。 A. ABCDE B. EDCBA C. EDBCA D. BCADE 13、假设对4个元素A、B、C、D、E进行压栈或出栈的操作,压栈的先后顺序是ABCD,则出栈的先后顺序不可能是。 A. ABCD B. DCBA C. BCAD D. DCAB 14、通过new运算符动态创建的对象的存放在中。 A. 代码区 B. 栈区 C. 自由存储区 D. 全局数据区 15、链表不具有的特点是。 A. 元素的存储地址可以不连续 B. 存储空间根据需要动态开辟,不会溢出 C. 可以直接随机访问元素 D. 插入和删除元素的时间开销与位置无关 16、有关内存分配和释放的说法,下面当中错误的是 A.new运算符的结果只能赋值给指针变量 B.动态创建的对象数组必须调用delete []动态撤销 C.用new分配的空间位置是在内存的栈区 D.动态创建的对象数组没有数组名 17、关于栈,下列哪项不是基本操作 A.删除栈顶元素 B.删除栈底元素 C.判断栈是否为空 D.把栈置空 18、关于链表,说法错误的是

指针与结构体 上机

指针 1.在主函数中输入一个字符串str,调用函数统计字符串中出现的字母(含大 小写)、数字、空格及其他字符出现的次数,在主函数中输出统计结果。要求写三个版本的程序:(1)用指针作参数返回统计结果。(2)用引用做参数返回统计结果(引用做参数效率更高,代码更简单。)(3)用数组做参数返回统计结果(当返回多个同类型结果时用数组做参数更简单)。 1.#include using namespace std; void stat(char *str,int *letters,int *digits,int *others){ char c; for(char *str;*str!='\0';str++) {c=*str; if((c>'a'&&c<'z')||(c>'A'&&c<'Z')) (*letters)++; else if('0'<=c&&c<='9') (*digits)++; else (*others)++; } } void main(){ char str[100]; cin.getline(str,100); int letters=0; int digits=0; int others=0; stat(str,&letters,&digits,&others); cout<<"letters="< #include using namespace std; void stat(char *str,int *a){ char c; for(int i=0;str[i]!='\0';i++) {c=str[i];

【c语言程序设计】结构体

第一章CH9 结构体9.1 选择题 1.若有以下说明语句: struct student { int num; char name[ ]; float score; }stu; 则下面的叙述不正确的是: ( D ) A. struct是结构体类型的关键字 B. struct student 是用户定义的结构体类型 C. num, score都是结构体成员名 D. stu是用户定义的结构体类型名 2.若有以下说明语句: struct date { int year; int month; int day; }brithday; 则下面的叙述不正确的是__C___. A) struct是声明结构体类型时用的关键字 B) struct date 是用户定义的结构体类型名 C) brithday是用户定义的结构体类型名 D) year,day 都是结构体成员名 3.以下对结构变量stul中成员age的非法引用是B struct student { int age; int num; }stu1,*p; p=&stu1; A) stu1.age B) student.age C) p->age D) (*p).age 4.设有以下说明语句: typedef struct stu { int a; float b; } stutype; 则下面叙述中错误的是(D)。 A、struct是结构类型的关键字

B、struct stu是用户定义的结构类型 C、a和b都是结构成员名 D、stutype是用户定义的结构体变量名 5.设有以下定义,值为5的枚举常量是()。 enum week{sun,mon=4,tue,wed,thu,fri,sat} w; A tue B sat C fri D thu 6.设有如下定义: struct sk {int a;float b;}data,*p; 若有p=&data;,则对data中的a域的正确引用是(B)。 A)(*p).data.a B)(*p).a C)p->data.a D)p.data.a 7.根据以下定义,能输出字母M的语句是(D)。 A、printf(“%c\n”,class[3].name) B、printf(“%c\n”,class[3].name[1]); C、printf(“%c\n”,class[2].name[1]) D、printf(“%c\n”,class[2].name[0]); struct person{char name[9];int age;}; struct person class[10]={“John”,17,”Paul”,19,”Mary”,18,”Adam”,16,}; 8.以下程序的输出结果是(D)。 A、0 B、1 C、3 D、6 #include void main() { struct emplx{int x;int y;}enum[2]={1,3,2,7}; printf(“%d\n”,enum[0].y/enum[0].x*enum[1].x); } 9.若有以下说明及语句,则值为6的表达式是(D)。 A、p++->n B、p->n++ C、(*p).n++ D、++p->n struct st{int n;struct st *next;}; struct st a[3],*p; a[0].n=5;a[0].next=&a[1];a[1].n=7;a[1].next=&a[2]; a[2].n=9;a[2].next=’\0’;p=&a[0]; 10.已知字符0的ASCII码的十进制的值是48,且数组的第0个元素在低位,以下程序的输出结果是(B)。 A、39 B、9 C、38 D、8 void main() {

函数、指针与结构体练习题_参考答案

函数 (一)选择题 1.以下正确的说法是_________. 建立函数的目的之一是a)提高程序的执行效率 b)提高程序的可读性 c)减少程序的篇幅 d)减少程序文件所占存 2.以下正确的函数原型声明形式是________. a)double fun(int x,int y) b)double fun(int x; int y) c)double fun(int x, int y); d)double fun(int x,y); 3.C语言规定,简单变量做实参时,它和对应形参之间的数据传递方式为______. A)地址传递 B)单向值传递 C)由实参传给形参,再由形参传回给实参 D)由用户指定传递方式 4.C语言允许函数值类型缺省定义,此时该函数值隐含的类型是______. a)float b)int c)long d)double 5.已有以下数组定义和f函数调用语句,则在f函数的说明中,对形参数组array 的错误定义方式为________. int a[3][4]; f(a); a)f(int array[][6])

b)f(int array[3][]) c)f(int array[][4]) d)f(int array[2][5]) 6.以下程序的正确运行结果是_________. #include void num() { extern int x,y;int a=15,b=10; x=a-b; y=a+b; } int x,y; main() { int a=7,b=5; x=a+b; y=a-b; num(); printf("%d,%d\n",x,y); } a)12,2 b)不确定c)5,25 d)1,12 7.以下正确的描述是____________. a)C语言的预处理功能是指完成宏替换和包含文件的调用 b)预处理指令只能位于C源程序文件的首部 c)凡是C源程序中行首以"#"标识的控制行都是预处理指令 d)C语言的编译预处理就是对源程序进行初步的语法检查 8.在"文件包含"预处理语句的使用形式中,当#include后面的文件名用< >(尖括号)括起时,找寻被包含文件的方式是_______. a)仅仅搜索当前目录 b)仅仅搜索源程序所在目录

结构指针

题目内容: 定义一个学生的结构体,包含姓名,年龄,身高从键盘输入一组学生信息 结果打印4组数据 输入样例 Tom 20 1.70 输出 Tom0 20 1.70 Tom1 21 1.71 Tom2 22 1.72 Tom3 23 1.73 输入描述 从键盘输入一组学生信息 结果打印3组数据 输入样例 Tom 20 1.70 输出描述 结果打印4组数据 输出 Tom0 20 1.70 Tom1 21 1.71 Tom2 22 1.72 Tom3 23 1.73 输入样例 Tom 20 1.70 输出样例 Tom0 20 1.70 Tom1 21 1.71 Tom2 22 1.72 Tom3 23 1.73 程序代码

for(i=0;i<4;i++) printf("%s%d %d %.2f\n",https://www.360docs.net/doc/e014997673.html,,i,a.age+i,a.high+i *0.01); return 0; } 2.c-05-1 回文句子 (10分) C时间限制:3000 毫秒 | C内存限制:3000 Kb 题目内容: "回文句"是一种句型,一个句子如果正着读与倒着读的意思一样,就可以称为"回文句"。 如:蜜蜂酿蜂蜜;风扇能扇风;奶牛产牛奶;清水池里池水清;静泉山上山泉;上海自来水来自海上;雾锁山头山锁雾;天连水尾水连天;门盈喜气喜盈门。 在英文中也是有回文的,而且是一种非常有趣的修辞,即palindrome,其结构跟中文是 一个道理。英文回文举例: Able was I ere I saw Elba。(在我看到厄尔巴岛之前,我曾所向无敌) Madam, I' m Adam.(女士, 我是Adam) Was it a bar or a bat I saw? (我看到的是酒吧还是蝙蝠?) 编写一个函数,判断给定英文句子是不是回文句。 输入描述 输出描述 输入样例 输入样例1: Madam, I' m Adam. 输入样例2:

习题6 结构体

1、可以把结构体数组元素作为一个整体输出。 对 错 2、已知学生记录描述为:struct student { int no; char name[20]; char sex; struct{int year; int month; int day;} birth; }; struct student s; 设变量s中的“生日”应是“1984年11月11日”,下列对“生日”的正确赋值方式是_______。 a. birth.year=1984; birth.month=11; birth.day=11; b. s.year=1984; s.month=11; s.day=11; c. s.birth.year=1984; s.birth.month=11; s.birth.day=11 d. year=1984; month=11; day=11; 3、C语言中,结构的成员可以是一维数组或多维数组。 对 错 4、C语言共用体类型变量在程序运行期间_______。 a. 所有成员一直驻留在内存中 b. 没有成员驻留在内存中 c. 部分成员驻留在内存中 d. 只有一个成员驻留在内存中 5、枚举类型时一种基本的数据类型。 对 错 6、结构体和共用体成员的应用都只能引用最低一级的成员。 对 错 7、将整数值赋给枚举变量时不需要作强制类型转换。 对 错 8、C语言中,结构类型与结构变量的含义一样,都可以用来存放数据。 对 错 9、共用体所有成员共用的内存单元的大小为各成员需要占用内存大小之和。

对 错 10、结构体可以定义在单独的头文件中,使用时需要在对应C文件中包含该头文件。对 错 11、结构体数组不可以在定义时进行初始化。 对 错 12、当说明一个共用体变量时系统分配给它的内存是_______。 a. 结构中第一个成员所需内存量 b. 各成员所需内存量的总和 c. 结构中最后一个成员所需内存量 d. 成员中占用内存量最大者所需的容量 13、下面对typedef的叙述中不正确的是_______。 a. typedef只是将已存在的类型用一个新的标识符来代表 b. 使用typedef有利于程序的通用和移植 c. 用typedef可以定义各种类型名,但不能用来定义变量 d. 用typedef可以增加新类型 14、共用体所有成员都共用同一内存单元。 对 错

【良心出品】第三讲 结构体习题

第三讲结构体与共用体 一、选择题 1.在说明一个结构体变量时系统分配给它的存储空间是。 A)该结构体中第一个成员所需存储空间 B)该结构体中最后一个成员所需存储空间 C)该结构体中占用最大存储空间的成员所需存储空间 D)该结构体中所有成员所需存储空间的总和 2.若有以下说明和语句: struct worker { int no; char ﹡name; }work, ﹡p=&work; 则以下引用方式不正确的是。* A) work.no B) (﹡p).no C) p->no D)work->no3.有如下定义: struct date { int year, month, day; }; struct worklist { char name[20]; char sex; struct date birthday; }person; 对结构体变量person的出生年份进行赋值时,下面正确的赋值语句是。 * A) year=1958 B) birthday.year=1958 C) person.birthday.year=1958 D) person.year=1958 4.以下对结构体类型变量的定义中不正确的是。* A)#define STUDENT struct student B) struct student STUDENT { int num; { int num; float age; float age; }std1; }std1; C) struct D) struct { int num; { int num; float age; float age; } student; }std1; struct student std1; 5.设有以下说明语句 struct stu { int a; float b; }stutype; 则下面的叙述不正确的是。* A)struct是结构体类型的关键字 B)struct stu是用户定义的结构体类型 C)stutype是用户定义的结构体类型名 D)a和b都是结构体成员名 6.C语言结构体类型变量在程序执行期间。 A)所有成员一直驻留在内存中 B)只有一个成员主留在内存中 C)部分成员驻留在内存中 D)没有成员驻留在内存中

结构体变量初始

结构体变量初始

————————————————————————————————作者:————————————————————————————————日期:

9.1.6 结构体变量的初始化 和C语言中其它变量一样,在定义结构体变量时可以进行初始化操作,一般形式为([]中的内容表示可省略): struct [结构体类型名] { 数据类型名1 成员名1; …… 数据类型名n 成员名n; }结构体变量 = {初始数据}; 例如,可以在定义hero型变量wusong时对其进行初始化: struct hero { int number; //排名 char sex; //性别 char star_name[20]; //星名 char name[20]; //名称 char nickname[20]; //绰号 char position[20]; //职业 char weapon[20]; //使用武器 } wusong={14,’m’,”天伤星”,”武松”,”行者”,”步兵头领”,”2把戒刀”}; //定义了结构体变量wusong并初始化。

定义结构体变量wusong但没有初始化时,编译器会给每个成员一个默认值,初始化后就赋予初始化时地赋值,如图9.4所示: 图9.4 结构体变量及其初始化 注意:对结构体变量进行初始化时,必须按照每个成员的顺序和类型一一对应地赋值,少赋值、多赋值,以及类型不符都可能引起编程错误。 9.1.6 结构体变量的引用 在定义了结构体变量后,就可以引用这个变量。所谓引用结构体变量就是使用结构体变量或结构体变量的成员进行运算或者其他操作。 1. “.”运算符 在C语言中,“.”也是一个运算符,叫做成员运算符。一般和结构体或共用体变量名称一起使用,用来指定结构体或共用体变量的成员。例如: linchong.nickname; 用来指定结构体变量linchong的成员nickname。 2. 结构体变量成员的引用 C语言允许引用结构体变量的成员完成某种操作。其一般形式为:

实验6 结构体的应用

实验6 结构体的应用 实验目的 1.掌握结构体类型及结构体变量的定义和使用。 2.掌握结构体类型数据在函数中的应用。 3.掌握结构体数组的使用。 实验内容 1.下列程序完成对一名职工的姓名、出生年月、基本工资的初始化。从键盘输入奖金金额,输出对应职工的姓名、年龄、基本工资和应领金额等信息。阅读、写出并分析运行结果。 #include using namespace std; struct Date { int year,month; }; struct Person { char name[20]; Date birth; float money,salary; // money 为基本工资;salary为应领金额 }; int main() { Person p={"张三",{1982,3},1250,0}; float num; cout<<"请输入"<< https://www.360docs.net/doc/e014997673.html,<<"的奖金金额:"; cin>>num; p.salary=p.money+num; cout<

第11章 结构体

单项选择题 1101. 当说明一个结构体变量时系统分配给它的内存是( )。 A. 各成员所需内存量的总和 B. 结构中第一个成员所需内存量 C. 成员中占内存量最大者所需的容量 D. 结构中最后一个成员所需内存量 1002. 设有以下说明语句 struct uu { int n; char ch[8]; } PER; 则下面叙述中正确的是( )。 A. uu 是结构体标识名 B. PER 是结构体标识名 C. struct uu是结构体标识名 D. struct 是结构体标识名 1003. 已知有如下定义: struct a{char x; double y;}data,*t; 若有t=&data,则对data中的成员的正确引用是( )。 A. (*t).x B. (*t).data.x C. t->data.x D. t.data.x 1004. 设有如下定义: struct sk { int a; float b; } data; int *p; 若要使P指向data中的b域,正确的赋值语句是( )。 A. p=&data.b; B. p=&b; C. p=data.b; D. *p=data.b; 1005. 已知学生记录描述为: struct student { int no; char name[20],sex; struct { int year,month,day;

} birth; }; struct student s; 设变量s中的“生日”是“1984年11月12日”,对“birth”正确赋值的程序段是( )。 A. s.birth.year=1984;s.birth.month=11;s.birth.day=12; B. birth.year=1984;birth.month=11;birth.day=12; C. s.year=1984;s.month=11;s.day=12; D. year=1984;month=11;day=12; 1006. 有如下定义 struct person{char name[9];int age;}; struct person class[10]={"John",17,"paul",19,"Mary",18,"Adam",16,}; 根据上述定义,能输出字母M的语句是( )。 A. printf("%c\n",class[3].name[1]); B. printf("%c\n",class[3].name); C. printf("%c\n",class[2].name[1]); D. printf("%c\n",class[2].name[0]); 1007. 若程序中有以下的说明和定义: struct abc { int x;char y; } struct abc s1,s2; 则会发生的情况是( )。 A. 编译出错 B. 程序将顺序编译、连接、执行 C. 能顺序通过编译、连接、但不能执行 D. 能顺序通过编译、但连接出错 1008. 有以下程序段 struct st { int x; int *y;}*pt; int a[]={1,2};b[]={3,4}; struct st c[2]={10,a,20,b}; pt=c; 以下选项中表达式的值为11的是( )。 A. ++pt->x B. *pt->y C. pt->x D. (pt++)->x 1009. 有以下说明和定义语句 struct student { int age; char num[8];};

相关文档
最新文档