当前位置:文档之家› 第八章 指针

第八章 指针

第八章 指针
第八章 指针

第八章指针

【本章要求】

1、指针的声明、定义方法以及通过指针变量引用存储单元中的内容

2、指针作为函数参数,地址传递情况下,函数实参的变化

3、用指针指向函数,并通过指针调用该函数

4、一维数组和字符串中元素地址的计算方法,以及通过指针引用这些元素

5、二维数组中元素的计算方法,以及通过指针数组引用其中元素的方法

6、通过命令行方式调用main函数

7、内存的动态分配和释放

8.1 指针的基本概念

如果在程序中定义了一个变量,在编译时就给这个变量分配内存单元。系统根据程序中定义的变量类型,分配一定长度的空间。内存区的每一个字节有—个编号,这就是“地址”,它相当于旅馆中的房间号。

在程序中一般是通过变量名来对内存单元进行存取操作的。程序经过编译以后己经将变量名转换为变量的地址,对变量值的存取都是通过地址进行的。

按变量地址存取变量值的方式称为“直接访问”方式。

还可以采用另一种称之为“间接访问”的方式,将变量i的地址存放在另一个变量中。按C 语言的规定,可以在程序中定义整型变量、实型变量、字符变量等,也可以定义这样一种特殊的变量,它是存放地址的。

假设我们定义了一个变量i_pointer,用来存放整型变量的地址,它被分配为3010、3011字节。可以通过下面语句将i的地址(2000)存放到i_pointer中。

i_pointer = &i;

这时,i_pointer的值就是2000,即变量i所占用单元的起始地址。要存取变量i的值,也可以采用间接方式;先找到存放“i的地址”的变量,从中取出i的地址(2000),然后到2000、2001字节取出i的值(3)。

所谓“指向”就是通过地址来体现的。i_pointer中的值为2000,它是变量i的地址,这样就在i_pointer和变量i之间建立起一种联系,即通过i_pointer能知道i的地址,从而找到变量i的内存单元。

在C语言中,将地址形象化地称为“指针”。意思是通过它能找到以它为地址的内存单元(例如根据地址2000就能找到变量i的存储单元,从而读取其中的值)。一个变量的地址称为该变量的“指针”。例如,地址2000是变量i的指针。如果有一个变量专门用来存放另一变量的地址(即指针),则它称为“指针变量”。指针变量的值(即指针变量中存放的值)是指针(地址)。

8.2 指针变量

变量的指针就是变量的地址。存放变量地址的变量是指针变量,用来指向另一个变量。为了表示指针变量和它所指向的变量之间的联系,在程序中用“*”符号表示“指向”。

- 93 -

《C语言程序设计》

8.2.1 指针变量的定义

C语言规定所有变量在使用前必须定义,指定其类型,并按此分配内存单元。指针变量不同于整型变量和其他类型的变量,它是用来专门存放地址的。必须将它定义为“指针类型”。先看一个具体例子:

int a, b;

int c1, c2;

第1行定义了两个整型变量a和b,第2行定义了两个指针变量: c1和c2,它们是指向整型变量的指针变量。左端的int是在定义指针变量时必须指定的“基类型”。指针变量的基类型用来指定该指针变量可以指向的变量的类型。

定义指针变量的一般形式为:

基类型*指针变量名

在定义指针变量时要注意两点:

1、指针变量前面的“*”,表示该变量的类型为指针型变量。注意:指针变量名足c1、c2,而不是*c1、*c2。

2、在定义指针变量时必须指定基类型。一个指针变量只能指向同—个类型的变量。

8.2.2 指针变量的赋值

可用运算符“&”求变量的地址。

可以用赋值语句使一个指针变量指向一个变量,例如:

a1=&x;

b2=&y;

也可以在定义指针变量的同时对其赋值,例如:

int x=3,y=4,*c1=&i,*c2=&j;

等价于

int x,y,*c1,*c2;

x=3;y=4;

c1=&x;

c2=&y;

在定义指针变量时应注意:

1、在定义指针变量时,指针变量的值是随机的,不能确定它具体的指向,必须为某赋值,才有意义。

2、指针变量的类型必须与其存放的变量类型一致,即只有变量的地址才能放到指向整型变量的指针变量中。

8.2.3指针的两个运算符

在C语言中有两个关于指针的运算符:

&-------取地址运算符;

*--------指针运算符

取地址运算符“&”可以加在变量和数组元素的前面,其意义是取出变量或数组元素的地址。

- 94 -

第八章指针

因为指针变量也是变量,所以取地址运算符也可以加在指针变量的前面,其含义是取出指针变量的地址。

【例8.1】输入a和b两个整数,按先大后小的顺序输出a和b。

main ( )

{

int *c1,*c2,*c,x,y;

scanf(“%d,%d”,&x,&y);

cl = &x;c2 = &y;

if(x

printf(“\nx = %d,y = %d\n\n”,x,y);

printf(“max = %d,min = %d\n”,*cl,*c2);

}

运行情况如下:

5,9

x = 5,y = 9

max = 9,min = 5

当输入x=5,b=9时,由于x

指针运算符“*”可以加在指针或指针变量的前面,其意义是指针或指针变量所指向的内存单元。

8.2.4 指针变量的引用

指针变量中只能存放地址(指针).不要将一个整型量(或任何其他非地址类型的数据)赋给一个指针变量。

a_1= 100;(a_1为指针变量,100为整数)

有两个有关的运算符:

1、&:取地址运算符。

2、*:指针运算符(或称“间接访问”运算符)。

&x为变量x的地址,*c为指针变量c所指向的存储单元。

例如:通过指针变量访问整型变量。

main ( )

{int x,y;

int *a_1,*a_2;

x = 100;y = 10;

a_1 = &x;

a_2 = &y;

printf(“%d,%d\n”,x,y);

printf(“%d,%d\n”,*a_1,*a_2);}

运行结果为:

100,10

100,10

【说明】

- 95 -

《C语言程序设计》

1、在开头处虽然定义了两个指针变量a_l和a_2,但它们并未指向任何一个整型变量。只是提供两个指针变量,规定它们可以指向整型变量。

2、最后一行的*a_1和*a_2就是变量x和y。

3、程序中有两处出现*a_1和*a_2,它们有不同的含义。程序第3行的*a_l和*a_2表示定义两个指针变量a_1、a_2。它们前面的“*”只是表示该变量是指针变量。程序最后—行printf函数中的*a_1和*a_2则代表变量。

4、第

5、6行“a_1=&x;”和“a_2=&y;”是将x和y的地址分别赋给a_1和a_2。注意不应写成:“*a_1= &x;”和“a_2 = &y;”。

8.2.5 将指针变量作为参数时的传递

函数的参数不仅可以是整型、实型、字符型等数据,还可以是指针类型。它的作用是将一个变量的地址传送到另一个函数中。

【例8.2】输入a和b两个整数,按先大后小的顺序输出a和b。

swap(int *cl,int *c2)

{ int temp;

temp = *c1;

*cl = *c2;

*c2 = t;

}

main ( )

{

int x,y;

int *a_1,*a_2;

scanf(“%d,%d”,&x,&y);

a_1 = &x;a_2 =&y;

if(x

printf(“\n%d,%d\n”,x,y);

)

运行结果:

5,9

9,5

对程序的说明:swap是用户定义的函数,它的作用是交换两个变量(x和y)的值。swap函数的两个形参c1、c2是指针变量。程序运行时,先执行main函数,输入x和y的值(今输入5和9)。然后将x和y的地址分别赋给指针变量a_1和a_2,使a_1指向x,a_2指向y。接着执行if语句,由于x < y,因此执行swap函数。在函数调用时,将实参变量的值传送给形参变量。采取的依然是“值传递”方式。因此虚实结合后形参c1的值为&x,c2

请注意交换*cl和*c2的值是如何实现的。如果写成以下这样就有问题了:

swap(int *c1,int *c2)

{int *temp;

*temp = *c1;

*c1 =*c2;

*c2=*temp;

}

- 96 -

第八章指针

*c1就是x,是整型变量。而*temp是指针变量temp所指向的变量。但temp中并无确定的地址值,它的值是不可预见的。*temp所指向的单元也是不可预见的。因此,对*temp赋值可能会破坏系统的正常工作状况。可以看到,在执行swap函数后,变量x和y的值改变了。

swap(int a,int b)

{int temp;

temp = a;

a = b;

b = temp;

}

在函数调用时,x的值传送给a,y的值传送给b。执行完swap函数后,a和b的值是互换了,但main函数中的x和y并未互换。也就是说由于“单向传送”的“值传递”方式,形参值的改变无法传给实参。

如果想通过函数调用得到n个要改变的值,可以:

(1)在主调函数中设n个变量,用n个指针变量指向它们;

(2)然后将指针变量作实参,将这n个变量的地址传给所调用的函数的形参;

(3)通过形参指针变量,改变该n个变量的值;

(4)主调函数中就可以使用这些改变了值的变量。

请注意,不能企图通过改变指针形参的值而使指针实参的值改变。

swap(int *cl,int *c2)

{int *c;

c = cl;

c1= c2;

c2= c;

}

main( )

{

int x,y;

int *a_1,*a_2;

scanf(“%d,%d”,&x,&y);

a_1 = &x;

a_2 = &y;

if(x

printf(“\n %d,%d\n”,*a_l,*a_2);

}

此程序的意图是:交换a_1和a_2的值,使a_1指向值大的变量。但是这是办不到的,程序实际输出为“5,9”。C语言中实参变量和形参变量之间的数据传递是单向的“值传递”方式。指针变量作函数参数也要遵循这—规则。调用函数不可能改变实参指针变量的值,但可以改变实参指针变量所指变量的值。

【例8.3】输入a、b、c3个整数,按大小顺序输出。

swap(int *pc1,int *pc2)

{ int temp;

temp =* pcl;

*pt1 =*pc2;

*pc2 = temp;

- 97 -

《C语言程序设计》

- 98 -

}

exchange(int *al,int *a2,int *a3)

{ if(*al<*a2)swap(al,a2);

if(*al<*a3)swap(al,a3);

if(*a2<*a3)swap(a2,a3);

}

main ( )

{

int x,y,z,*p1,*p2,*p3;

scanf(“%d,%d,%d”,&x,&y,&z);

pl = &a

;p2=&y;p3 = &z;

exchange(p1,p2,p3);

printf(“\n%d,%d,%d\n”,x,y,z);

}

运行结果:

9,0,10

10,9,0

8.3 数组与指针

一个变量有地址,—个数组包含若干元素,每个数组元素都在内存中占用存储单元,它们都有相应的地址。指针变量既然可以指向变量,当然也可以指向数组和数组元素。所谓数组的指针是指数组的起始地址,数组元素的指针是数组元素的地址。

引用数组元素可以用下标法(如a[3]),也可以用指针法,即通过指向数组元素的指针找到所需的元素。使用指针法能使目标程序质量高。

8.3.1 指向数组元素的指针

定义一个指向数组元素的指针变量的方法,与指向变量的指针变量相同。

例如:

int x[10];

int *a;

a =&x[0];

把a[0]元素的地址赋给指针变量a。也就是说,a指向x数组的第0号元素。

C语言规定数组名代表数组的首地址,也就是第0号元素的地址。因此,下面两个语句等价:

a = &x[0];

a = x;

a = x的作用是“把x数组的首地址赋给指针变量a”,而不是“把数组x各元素的值赋给p”。

在定义指针变量时可以赋给初值:

int *a = &x[0];

它等效于

int *a;

第八章指针

a = &x[0];

当然定义时也可以写成

int *a = x;

它的作用是将x的首地址(即x[0]的地址)赋给指针变量a(而不是赋给*a)。

8.3.2 通过指针引用数组元素

按C的规定:如果指针变量a已指向数组中的一个元素,则a+l指向同一数组中的下一个元素(而不是将a值简单地加1)。

如果a的初值为&x[0],则:

1、a+i和x+i就是x[i]的地址,或者说,它们指向x数组的第i个元素。

2、*(a+i)或*(x+i)是a+i或x+i所指向的数组元素,即x[i]。

3、指向数组的指针变量也可以带下标,如a[i]与*(a+i)等价。

引用—个数组元素,可以用:

(1)下标法,如x[i]形式;

(2)指针法,如*(x+i)或*(a+i)。其中a是数组名,a是指向数组的指针变量,其初值a = x。

【例8.4】输出数组中的全部元素。假没有—个x数组,整型,有10个元素。要输出各元素的值有三种方法:

(一)下标法。

main ( )

{

int x[10];

int i;

for(i = 0;i<10;i++)

scanf(“%d”,&x[i]);

printf(“\n”);

for(i = 0:i<10;i++)

printf(“%d”,x[i]);

}

(二)通过数组名计算数组元素地址,找出元素的值。

main ( )

{

int x[10];

int i;

for(i = 0;i<10;i++)

scanf(“%d”,&x[i]);

printf(“\n”);

for(i = 0:i<10;i++)

printf(“%d”,*(x+i));

}

(三)用指针变量指向数组元素。

main ( )

{

- 99 -

《C语言程序设计》

- 100 - int x[10];

int a,i;

for(i = 0;i<10;i++)

scanf(“%d”,&x[i]);

printf(“\n”);

for(a = x:a<(x+10);a++)printf(“%d”,*a);

}

以上3个程序的运行情况均如下:1 2 3 4 5 6 7 8 9 0(输入)

1 2 3 4 5 6 7 8 9 0

对三种方法的比较:

1、第(一)和(二)种方法执行效率是相同的。

2、第(三)种方法比(一)(二)法快,用指针变量直接指向元素,不必每次都重新计算地址,像a++这样的自加操作是比较快的。

3、用下标法比较直观,能直接知道是第几个元素。

在使用指针变量时,有以下几个问题要注意:

1、指针变量可以实现使本身的值改变。

2、要注意指针变量的当前值。

【例8.5】通过指针变量输出x组的10个元素。

main ( )

{

int *a,i,x10];

a = x

for(i=0;i<10;i++)

scanf(“%d”,a++);

printf(“\n”);

for(i=0;i

printf(“%d”,*a);

}

显然这个程序输出的数值并不是x数组中各元素的值。原因是指针变量的初始值为x数组首地址。

解决这个问题的办法,只要在第二个for循环之前加一个赋值语句:

a=x;

main ( )

{

int *a,i,x[10];

a = x;

for(i=0;i<10;i++)

scanf(“%d”,a++);

printf(“\n”);

a = x;

for(i=0;i

第八章指针

printf(“%d”,*a);}

3、从上例可以看到,虽然定义数组时指定它包含10个元素,用a指向数组元素,但指针变量可以指到数组似后的内存单元。

4、注意指针变量的运算。如果先使a指向数组x(即a=x),则:

(1)a++(或a+ = 1),使a指向下一元素,即x[i]。若再执行*a,取出下一个元素x[1]值。

(2)a++,由于x++和*同优先级,结合方向为自右而左,因此它等价于*(a++)。作用是先得到a指向的变量的值(即‘x),然后再使a+1=>a。

for(i=0;i

printf(“%d”,*a);

可以改写为

for(i=0;i

printf(“%d”,*a++);

(3)*(a++)与*(++a)作用不同。前者是先取*a值,后使a加1。后者是先使a加l,再取*a。

(4)(*a)++表示a所指向的元素值加1,即(x[0])++,如果x[0]=3,则(x[0])++的值为4。注意:是元素值加l,而不是指针值加1。

(5)如果a当前指向x数组中第i个元素,则:

*(a++)相当于x[i--],先对a进行“*”运算,再使a自减。

*(++a)相当于x[++i],先使a自加,再作*运算。

*(--a)相当于x[- -i],先使a自减,再作*运算。

8.3.3 数组名作函数参数

数组名可以用作函数的形参和实参。如:

main( ) f(int arr[ ],in(n)

{int array[10];{

……

f(array,10);}

)

array为实参数组名,arr为形参数组名。当用数组名作参数时,如果形参数组中各元素的值发生变化,实参数组元素的值随之变化。

用数组元素作实参的情况与用变量作实参时一样,是“值传递”方式,单向传递数据。如果用数组名作实参,在调用函数时是把数组的首地址传送给形参(注意:不是把数组的值传给形参)。以接受实参传过来的数组首地址。这样实参数组与形参数组共占同一段内存。

需要说明的是:C语言调用函数时虚实结合的方法都是采用“值传递”方式,当用变量名作为函数参数时传递的是变量的值,当用数组名作为函数参数时,由于数组名代表的是数组起始地址,因此传递的值是数组首地址,所以要求形参为指针变量。不要错认为用数组名作函数参数时不采用“值传递”方式。

【例8.6】将数组a中n个整数按相反顺序存放。

void inv(int a[ ],int n)

{

int temp,i,j,m = (n一1)/2;

- 101 -

《C语言程序设计》

- 102 -

for (i =0;i<=m;i++)

{j = n – 1- i;

temp=a[i];a[i]=a[j];a[j]=temp;}

return;

}

main ( )

{int i,x[10]={3,7,9,11,0,6,7,5,4,2};printf(”The original array:\n”);

for(i=0;i<10;i++)

printf(“%d,”,x[i]);

printf (”\n”);

inv(a,10);

printf(“the array has been inverted:\n”);

for(i=0;i<10;i++)

printf(“%d,”,x[i]);

}

对这个程序可以作一些改动。将函数inv中的形参a改成指针变量。实参为数组名x,即数组a的首地址,将它传给形参指针变量a,这时a指向x[0]。

void inv(int x,int n)

{

int *c1,temp,*a,*b,m = (n - 1)/2;

a = x;

b = x+n-1;c1 = x+m;

for(;a<=c1;a++,b--)

{temp = *a;*a=*b;*b=temp;}

return;

}

main ( )

{int i,x[10]={3,7,9,11,0,6,7,5,4,2};

printf(”The original array:\n”);

for(i=0;i<10;i++)

printf(“%d,”,x[i]);

printf (”\n”);

inv(x,10);

printf(“the array has been inverted:\n”);

for(i=0;i<10;i++)

printf(“%d,”,x[i]);

}

【例8.7】从10个数中找出其中最大值和最小值。

int max,min;

void max_min_value(int array[ ],int n)

{int *p,*array_end;

array_end = array + n;

max=min=*array;

for(p=array+1;p

第八章指针

if (*p>max) max=*p;

else if(*p

return;

}

main ( )

{int i,number[10];

printf(“enter 10 integer numbers:\n”);

for(i=0;i

scanf(“%d”,&number[i]);

max_min_value(number,10);

printf(“\nmax—%d,min=%d\n”,max,min);}

实参也可以不用数组名,而用指针变量传递地址,形参仍用指针变量。程序可改为:int max,min;

void max_min_value(int *array,int n)

{int *c,*array_end;

array_end = array + n;

max=min=*array;

for(p=array+1;c

if (*c>max) max=*c;

else if(*c

return;

}

main ( )

{int i,number[10],*c;

c = number;

printf(“enter 10 integer numbers:\n”);

for(i =0;i<10;i++,c++)

scanf (“%d”,c);

printf(“the 10 integer numbers:\n”);

for(c = number,i =0;i<10;i++,p++)

printf(“%d”,*c);

c = number;

max_min_value(c,10);

printf(“\n max = %d,rain = %d\n”,max,min);

}

如果有一个实参数组,想在函数中改变此数组的元素的值,实参与形参的对应关系有以下4种情况:

(1)形参和实参都用数组名,如:

main ( ) f(int x[ ],int n)

{int a[10];{

……

f ( a,10 );}

}

- 103 -

《C语言程序设计》

程序中的实参a和形参x都已定义为数组。如前所述,传递的是a数组首地址。

(2)实参用数组名,形参用指针变量。

main ( ) f (int * x,int n)

{int a[10];{

……

f (a,10);}

}

(3)实参形参都用指针变量。例如:

main ( ) f (int *x,int n)

{int a[10],*c1;{

c1 = a;…

…}

f (c1,10);

}

(4)实参为指针变量,形参为数组名。如:

main ( ) f (int x [ ],int n)

{ int a[10],*c1;{…}

c1 = a;

f(c1,10);

}

【例8.8】将数组a中n个整数按相反顺序存放。

void inv (int *x,int n)

{ int *c1,m,temp,*a,*b;

m = (n - 1) / 2;

a = x;

b = x + n -1;c1 = x + m;

for(;a<= c1;a++,b--)

{temp = *a,*a =*b;*b = temp;}

return;

}

main ( )

{int i,arr[10],*p1 = arr;

printf(“The original array:\n”);

for(i =0;i<10;i++,p++)

scanf(“%d”,p1);

printf(“\n”);

p1 = arr;

inv (p1,10);

printf(“The array has been inverted:\n”);

for(p1 =arr;p1

printf(“%d”,*p1 );

printf(“\n”);

- 104 -

第八章指针

}

注意,main函数中的指针变量p1是有确定值的。如果在main函数中不设数组,只设指针变量,程序如下:

main ( )

{ int i,*art;

printf(“The original array:\n”);

for ( i =0;i<=10;i++)

scanf(“%d”,arr+i);

printf(“\n”);

inv(arr,10);

printf(“The array has been inverted:\n”);

for (i=0;i

printf(“%d”,*(arr+i));

printf(“\n”);

}

【例8.9】用选择法对10个整数排序。

main ( )

{ int *p1,i,x[10];

p1 = x;

for(i =0;i

scanf(“%d”,p1++);

p1=x;

sort(p1,10);

for( p1 = x,i=0;i

{printf(“%d”,*p1);p1++;}

}

sort ( int a[ ],int n)

{int x,y,k,t;

for (x=0;x

{k = x;

for(y = x+1;y

if (a [x]>a[x]) k = y;

if ( k! = y )

{t = a[x];a[x] = a[k];a[k]=t;}

}

}

8.3.4 指针与字符串

一、字符串的表示形式

在C程序中,可以用两种方法访问一个字符串。

(一)用字符数组存放一个字符串,然后输出该字符串。

例如:

main ( )

- 105 -

《C语言程序设计》

- 106 -

{char string[ ] = “I lovc China!”;

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

运行时输出:

I love China!

(二)用字符指针指向一个字符串。

可以不定义字符数组,而定义一个字符指针。用指针指向字符串中的字符。

例如:

main ( )

{char *string =“I love China!”;

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

}

其中

char *string =“I love China!”;

等价于下面两行:

char *string;

string =“I love China!”;

而不等价于

char *string;

*string =“I love China!”;

打印时用

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

通过字符数组名或字符指针变量可以输出一个字符串。而对一个数值型数组,是不能企图用数组名输出它的全部元素的。如:

int a[ 10];

printf (“%d\n”,a);

是不行的。

对字符串中字符的存取,可以用下标方法,也可以用指针方法。

【例8.10】将字符串x复制为字符串y。

main ( )

{char x[ ]=“I am a boy.”,y[20];

int i;

for(i =0;*(x+i)!=‘\0 ’;i++)

*(y+i)=*(x+i);

*(y+i)=‘\0’;

printf("string a is;%s\n”,x);

printf("string b is:”);

for(i=0;y[i]!=‘\0’;i++)

printf(“%c”,y[i]);

printf(“\n”);

}

也可以设指针变量,用它的值的改变来指向字符串中的不同的字符。

【例8.11】用指针变量来处理将字符串x复制为字符串y。

main ( )

第八章指针

{char x[ ]=“I am a boy。”,y[20],*zl,*z2;

int i;

zl=x;z2=y;

for(;*zl!=‘\0’;zl++,z2++)

*z2=*zl;

*z2=‘\0’;

printf("string a is:%s\n”,x);

printf(“string b is:”);

for(i=0;y[i]!=’\0’;i++)

printf(“%c”,y[i]);

printf(“\n”);

}

二、字符串指针作函数参数

将一个字符串从一个函数传递到另一个函数,可以用地址传递的办法,即用字符数组名作参数或用指向字符串的指针变量作参数。在被调用的函数中可以改变字符串的内容,在主调函数中可以得到改变了的字符串。

【例8.12】用函数调用实现字符串的复制。

(一)用字符数组作参数。

void copy_string(char from[ ],char to[ ])

{ int i=0;

while(from[i]!=‘\0’)

{ to[i]=from[i];i++;}

to[i]=‘\0’;

}

main ( )

{char x[ ]=“I am a teacher.”;

char y[]=“you are a student.”;

printf(“string a=%s\n string b=%s\n”,x,y);

copy_string(x,y);

printf(“\n string x=%s\n string y=%s\n”,x,y);

}

在main函数中也可以不定义字符数组,而用字符型指针变量。main函数可改写如下:main ( )

{char *x=“I am a teacher.”;

char *y=“you are a student.”;

printf(“string x=%s\n string y=%s\n”,x,y);

copy_string(x,y);

printf(“\n string x=%s\n string y=%s\n”,x,y);

}

与上面程序运行结果相同。

(二)形参用字符指针变量。

void copy_strmg(char *from,char *to)

{ for(;*from!=‘\0’;from++,to++)

*to = *from;

- 107 -

《C语言程序设计》

- 108 -

*to =‘\0’;

}

main ( )

{ char a =“I am a teacher.”;

char b =“you are a student.”;

printf(“\nstring a = %s\n string b = %s\n”,a,b);

copy_string(a,b);

printf(“\n string a = %s\n string b=%s\n”,a,b);}

(三)对copy_string函数还可作简化。

(1)将copy_string函数改写为

void copy_string(char *from,char *to)

{ while((*to = *from)!=‘\0’)

{to++;from++;}

}

(2)copy_string函数的函数体还可改为

{

while((*to++ = *from++)!=‘\0’);

}

(3)函数体还可写成

{

while(*from!=‘\0’)

*to++ = *from++;

*to =‘\0’;

}

函数体还可简化为

{

while(*from)

*to++ = *from++;

*to =‘\0’;

}

(四)上面的while语句还可以进一步简化为下面的while语句:

while(*to++ = *from++);

它与下面语句等价;

while((*to++ = *from++)!=‘\0’);

(五)函数体中while语句也可以改用for语句:

for(;(* to++ =*from++)!=0;);

for(;*to++ = *from++;);

(六)也可用指针变量,函数copy_string可写为

void copy_string(char from[ ],char to[ ])

{char *p1,*p2;

p1 = from;p2=to;

while((*p2++=*pl++)!=‘\0’);

第八章指针

}

归纳起来,作为函数参数,有以下几种情况:

实参形参

数组名数组名

数组名字符指针变量

字符指针变量字符指针变量

字符指针变量数组名

8.4 函数的指针

8.4.1 用函数指针变量调用函数

可以用指针变量指向整型变量、字符串、数组,也可以指向一个函数。一个函数在编译时被分配给—个入口地址。这个入口地址就称为函数的指针。可以用一个指针变量指向函数,然后通过该指针变量调用此函数。

【例8.13】求d和6中的大者。先列出按一般方法的程序。

main ( )

{int max(int,int);

int x,y,z;

scanf(“%d,%d”,&x,&y);

z =max(x,y);

printf(“x=%d,y=%d,max=%d”,x,y,z);

}

max(int a,int a)

{int c;

if(a>b)c = a;

else c = b;

return(c);

}

可以用一个指针变量指向一个函数,通过指针变量来访问它指向的函数。

将main函数改写为:

main ( )

{int max(int,int);

int(*p1)();

int x,y,z;

p1 = max;

scanf(“%d,%d”,&x,&y);

z=(*p1)(x,y);

printf(“x = %d,y = %d,max = %d”,x,y,z);

}

在main函数中有一个赋值语句

z=(*p1)(x,y);

它包括函数的调用,和“z=max(x,y);”等价。这就是用指针形式实现函数的调用。以上用

- 109 -

《C语言程序设计》

两种方法实现函数的调用,结果是一样的。

【说明】

1、指向函数的指针变量的一般定义形式为

数据类型(*指针变量名)();

这里的“数据类型”是指函数返回值的类型。

2、函数的调用可以通过函数名调用,也可以通过函数指针调用(即用指向函数的指针变量调用)。

3、(*p)( )表示定义一个指向函数的指针变量,它不是固定指向哪一个函数的,而只是表示定义了这样一个类型的变量,它是专门用来存放函数的入口地址的。在程序中把哪一个函数的地址赋给它,它就指向哪一个函数。在一个程序中,一个指针变量可以先后指向不同的函数。

4、在给函数指针变量赋值时,只需给出函数名而不必给出参数,如:

P1 = max;

5、用函数指针变量调用函数时,只需将(*p1)代替函数名即可(p1为指针变量名),在(*p1)之后的括弧中根据需要写上实参。

6、对指向函数的指针变量,像p1+n、p1++、p1--等运算是无意义的。

8.4.2用指向函数的指针作函数参数

函数指针变量常用的用途之一是把指针作为参数传递到其他函数。指向函数的指针也可以作为参数,以便实现函数地址的传递,也就是将函数名传给形参。

它的原理可以简述如下:有一个函数(假设函数名为sub),它有两个形参(x1和x2),定义x1和x2为指向函数的指针变量。在调用函数sub时,实参用两个函数名f1和f2给形参传递函数地址。这样在函数sub中就可以调用f1和f2函数了。

【例8.14】设一个函数process,在调用它的时候,每次实现不同功能。输入a和b两个数,第一次调用process时找出a和b中大者,第二次找出其中小者,第三次求a与b之和。

main ( )

{ int max(int,int);

int min(int,int);

int add(int,int);

int a,b;

printf(“enter a and b:”);

scanf(“%d,%d”,&a,&b);

printf(“max = ”);

process(a,b,max);

printf(“min = ”);

process(a,b,min);

printf(“sum = ”);

process(a,b,add);

}

max(int x,int y)

{ int z;

if(x>y)z = x;

else z = y;

rerurn(z);

- 110 -

第八章指针

}

min(int x,int y)

{ int z;

if(x

else z = y;

return(z);

}

add(int x,int y)

{int z;

z = x + y;

return(z);

}

process(int x,int y,int(*fun)(int,int))

{int result;

result =(*fun)(x,y);

printf(“%d\n”,result);

}

8.4.3 返回指针值的函数

一个函数可以带回一个整型值、字符值、实型值等,也可以带回指针型的数据,即地址。其概念与以前类似,只是带回的值的类型是指针类型而已。

这种带回指针值的函数,一般定义形式为:

类型名*函数名(参数表);

例如:

int *a(int x,int y);

【例8.15】有若干个学生的成绩(每个学生有4门课程),要求在用户输入学生序号以后,能输出该学生的全部成绩。用指针函数来实现。

main ( )

{float score[ ][4]={{60,70,80,90},{56,89,67,88},{34,78,90,66}};

float *search(float(*pointer)[4],int n);

float *p;

int i,m;

printf(“enter the number of student:”);

scanf(“%d”,&m);

printf(The scores of No.%d are:\n”,m);

p = search(score,m);

for(i=0;i<4;i++)

printf(“%5.2f\t”,*(p+i));

}

float *search(float(*pointer)[4],int n)

{ float *pt;

pt = *(pointer+n);

return(pt);

- 111 -

《C语言程序设计》

- 112 - }

【例8.16】对上例中的学生,找出其中有不及格课程的学生及其学生号。

main()

{ float score[ ][4] ={{60,70,80,90},{50,89,67,88},{34,78,90,66}};float *search(float(*pointer)[4]);

float *p1;

int i,j;

for(i=0;i<3;i++)

{p1 = search(score+i);

if(p1 = =*(score+i))

{printf(“No.%d scores;”,i);

for(j = 0;j<4;j++)

printf(“%5.2f”,*(p1+j));

printf(“\n”);}

}

}

float *search(f1oat(*pomter)[4])

{ int i;

float *pt1;

pt1 = *(pointer+1);

for(i=0;i<4;i++)

if(*(*pointer+i)<60)pt1 = *pointer;

return(pt1);

}

C++程序设计 第八章 指针和引用

C++程序设计 第8章指针和引用 在程序运行时变量和函数都存放在内存中,通过变量名来访问数据、通过函数名来调用函数都是直接访问方式。还有另一种间接访问方式就是用指针。指针的本质是内存地址。指针往往用于说明函数的形参,使实参能通过指针传递,以提高函数调用的效率。利用指针能动态地使用内存,以提高内存使用效率。指针也能用来表示数据关联,以构成复杂的数据结构。指针是C程序中最常见的类型。引用是C++扩展的新概念,主要用于函数形参和返回类型。本章将详细介绍指针和引用的概念及应用。 8.1 指针及指针变量 指针(pointer)的本质是内存地址。指针变量就是专门存储地址的一种变量。通过指针变量所存储的地址来访问数据是一种间接寻址方式。由于处理器的机器语言能支持间接寻址,所以使用指针可以达到较高的计算性能。 8.1.1 地址的概念 C++编译器对不同对象或变量按其数据类型分配合适大小的存储空间。例如为char或bool型变量分配1个字节(bytes)的存储空间,short分配2字节,int和float分配4个字节,为double型变量分配8个字节的存储空间。当程序执行时,代码和变量都加载到内存中。计算机内存被分成若干个存储单元,存储单元以字节为单位。每个存储单元都有一个固定的编号,这个编号就是内存地址。尽管一个变量可能占用多个字节空间,但都通过第一个字节的地址来访问。存放某个变量的第一个字节的地址就是该数据的首地址。 指针即内存单元的地址,而数据是内存单元中的内容(或值)。 假设在程序中说明了1个int型的变量a,其值为68。系统为变量a分配4字节的存储空间,设首地址为0X0065FDF4。通过地址0X0065FDF4就能找到变量a在内存中的存储单元,从而对变量a进行访问。0X0065FDF4就是变量a的指针。知道一个变量的地址和变量的类型就能对变量进行访问,就如同知道房间号就能找到房间,从而找到房间里的主人。 指针是一种特殊的数据类型。所有类型的变量,无论是基本类型、用户定义类型、还是这些类型的数组,在一次运行时都有确定的地址,因此它们都有指针。对于32位计算机,地址长度就是32位,因此一个指针需要4个字节,与整型int、浮点型float具有相同大小的长度。一个指针不仅有值,而且还要确定其类型,表示它能指向什么类型的数据,决定了通过它要取用多少字节作为该变量的值。

第8章指针1练习答案

指针1 选择题 1.如下程序段: int *p ,a=10 ,b=1 ; p=&a ;a=*p+b ; 执行该程序段后,a 的值为。 A. 12 B. 11 C. 10 D. 编译出错 2.若有以下定义和语句: double r=99 ,*p=&r ; *p=r ; 则以下正确的叙述是。 A. 以下两处的*p 含义相同,都说明给指针变量p 赋值 B. 在"double r=99,*p=&r;"中,把r 的地址赋值给了p 所指的存储单元 C. 语句"*p=r;"把变量r 的值赋给指针变量p D. 语句"*p=r;"取变量r 的值放回r 中 3.若有说明int *p,a;则能通过scanf语句正确给a存入数据的程序段是()。 A.p=&a; scanf(“%d”,p); B.scanf(“%d”,a); C.p=&a; scanf(“%d”,*p); D.*p=&a; scanf(“%d”,p); 4.若int x ,*pb;,则正确的赋值表达式是。 A. pb=&x B. pb=x; C. *pb=&x; D. *pb=*x 5.若有说明:int i, j=2,*p=&i;,则能完成i=j 赋值功能的语句是。 A. i=*p; B. *p=*&j; C. i=&j; D. *p=i; 6.若已定义:int a[9] ,*p=a;并在以后的语句中未改变p 的值,不能表示a[1]地 址的表达式是()。 A. p+1 B. a+1 C. a++ D. ++p 7.若有以下说明:int a[10]={1,2,3,4,5,6,7,8,9,10} ,*p=a ; 则数值为6 的表达式是( )。 A. *p+6 B. *(p+6) C. *p+=5 D. p+5 8.以下程序段的运行结果是()。 int a[10]={1,2,3,4,5,6,7,8,9,10}; int *p=&a[3],*q; q=p+2; printf(“%d”,*p+*q); A.16 B.10 C.8 D.6

C语言第八章地址与指针

1文档来源为:从网络收集整理.word 版本可编辑. 第八章 地址和指针 第一节 变量的地址和指针 1、计算机的内存是以字节为单位的一片连续的存储空间,每一个字节都有一个编号,这个编号就成为内存地址。 2、程序中定义了一个变量,c 编译系统就会根据定义中变量的类型,为其分配一定字节数的内存空间: Short int 2 Int float 4 Double 8 char 1 指针 4 图8.1 变量在内存中所占字节的地址示意图 每个变量的地址就是指该变量所占存储单元的第一个字节的地址。 3、直接存取:程序中我们对变量进行存取操作,实际上也就是对某个地址的存储单元进行操作。这种直接按变量的地址存取变量值的方式。 4、在c 语言中,还可以定义一种特殊的变量,这种变量只 a 2001 p 3001 a b x 1012 1013 1015 1016 1201 1202 1203 1204 a

1文档来源为:从网络收集整理.word 版本可编辑. 是用来存放内存地址的。 图8.2 存放地址的指针变量示意图 通过变量p 间接得到变量a 的地址,然后再存取变量a 的值的方式称为“间接存取”方式,通常变量p 指向了变量a ,变量a 是变量p 所指向的对象。 5、用来存放指针地址的变量就称作“指针变量”。 6、“变量p 指向变量a ”的含义就是指针变量p 中存放了变量a 的地址。 7、在某些场合,指针是使运算得以进行的唯一途径。 第二节 指针的定义赋值 一、 指针变量的定义和指针变量的基本类型 1、 定义指针变量的一般形式如下: 类型名 *指针变量名1,*指针变量名2…… 说明:1)类型名是基本类型。 2)*是说明符。(而在调用的时候,代表的是存储单元中的值) 3)指针变量名是用户标识符。 例:1)int *pi,*pj; pi pj 只能存放整型变量的地址 int I,*pi;double *pj; 2)p 为一个指向指针的指针变量 2002 2002 1012 1013 p p

第八章 二级c语言

第八章变量的地址和指针 变量:整 int 4B 单精度 float 4B 双精度 double 8B 存储空间:随机存放 short int a,b; float c,d; a 2B b 2B c 4B d 4B 1012 1013 1018 1019 2010 2011 2012 2013 3033 3034 3035 3036 变量的地址:该变量所占存储单元的第一个字节的 地址 &a=1012 p a *定义一个指针变量用于存放地址 4039 1012 地址就是指针 1.指针变量:存放(指向)不同地址的指针 定义:类型说明 *变量名; int *p; (指向一个整型变量) float *f;

2.给指针变量赋值 (1)int a,*p; p=&a; /*将a变量的地址赋给指针p*/ (2)初始化赋值 int a,*p=&a; 3.赋值形式: (1)赋值运算 int a,*p; p=&a; 注意:p=1000; (错误) (2)初始化赋值 int a,*p=&a; (3)把一个指针变量的值送给相同类型的另一个指针变量 int a,*pa,*pb; pa=&a; pb=pa; /*两个指针同时指向a*/ (4)把数组的首地址,送给指针变量

(数组名就表示数组的首地址) int b[5],*p; p=b; 或者 p=&b[0] (也可以指在数组中间 p=&b[2]) (5)把字符串的首地址送给字符型的指针变量 char *p; p="abcdef"; (把字符串的首地址送给p) 4.指针变量的运算 &:取地址符号 *:取内容运算符(把指针所指变量内容取出来) 优先级相同 main() {int a,*p=&a; a=5; printf("%d\n",*p); printf("%d\n",p); printf("%d\n",&p);}

计算机二级c语言第八章 指针习题

第八章指针 一、选择题 1、设有定义:int n1=0,n2,*p=&n2,*q=&n1;,以下赋值语句中与n2=n1;语句等价的是 A)*p=*q; B)p=q; C)*p=&n1; D)p=*q; 2、若有定义:int x=0, *p=&x;,则语句printf("%d\n",*p);的输出结果是 A)随机值 B)0 C)x的地址 D)p的地址 3、以下定义语句中正确的是 A)char a='A'b='B'; B)float a=b=10.0; C)int a=10,*b=&a; D)float *a,b=&a; 4、有以下程序 main() { int a=7,b=8,*p,*q,*r; p=&a;q=&b; r=p; p=q;q=r; printf("%d,%d,%d,%d\n",*p,*q,a,b); } 程序运行后的输出结果是 A)8,7,8,7 B)7,8,7,8 C)8,7,7,8 D)7,8,8,7 5、设有定义:int a,*pa=&a;以下scanf语句中能正确为变量a读入数据的是 A)scanf("%d",pa) ; B)scanf("%d",a) ; C)scanf("%d",&pa) ; D)scanf("%d",*pa) ; 6、设有定义:int n=0,*p=&n,**q=&p;则以下选项中,正确的赋值语句是 A)p=1; B)*q=2; C)q=p; D)*p=5; 7、有以下程序 void fun(char *a,char *b) { a=b; (*a)++; } main () { char c1='A', c2='a', *p1, *p2; p1=&c1; p2=&c2; fun(p1,p2); printf("%c%c\n",c1,c2); }程序运行后的输出结果是 A)Ab B)aa C)Aa D)Bb 8、有以下程序 #include main() { printf("%d\n", NULL); } 程序运行后的输出结果是 A)0 B)1 C)-1 D)NULL没定义,出错 9、已定义以下函数 fun(int *p) { return *p; } 该函数的返回值是 A)不确定的值 B)形参p中存放的值

第八章地址和指针

第八章地址和指针 8.1变量的地址和指针 在程序中变量实际上代表了内存中的某个存储单元。那么C是怎样存取这些单元的数据内容的呢? 我们知道计算机的内存是以字节为单位的一片连续的存储空间,每个内存单元都有一个唯一的编号,我们将其称为“内存地址”。计算机对数据的存取操作都是依赖于内存地址进行的。因为计算机的内存空间是连续的,所以内存中的地址空间也是连续的,并且用二进制数据来表示,为了方便和直观,我们将用十进制数据进行描述。 若在程序中定义了一个变量,C编译系统就会自动根据变量的类型,为其分配一定字节数量的存储空间。如int型2个字节,float型4个字节,double型8个字节,char型1个字节等。此后,这个变量的内存地址也就唯一的确定了。 一般情况下,我们在程序中只要给出变量名,不需要知道每个变量在内存中的具体地址,变量与地址之间的联系由C编译系统来完成。程序中我们对变量进行存取操作,实际上就是对变量地址的存储单元进行操作。这种直接按照变量地址进行存取的操作方式称为“直接存取”方式。 在C语言中我们还可以定义一种特殊的变量,这种变量只是用于存放内存变量地址的。如:p93 图8.2 这种通过变量p间接得到变量a的地址,然后再存取变量a的值的方式称为“间接存取”的方式。这种用来存放地址的变量称为“指针变

量”或“指针”。 由此我们可以知道,在C语言中,地址是指变量在内存中的存放的位置,即存放该变量的内存单元的名字。而指针是指一个变量,在该变量中存放的是其指向的那个变量在内存存储单元的地址。也就是说,变量的地址就可以理解为指针。 在C语言中,指针被广泛使用,他可以使程序简洁并高效运行,但使用不当就会产生意料不到的严重后果。因此,正确使用和掌握指针是十分必要的。 8.2 指针变量的定义和基本类型 定义指针变量的形式: 类型名*指针变量名1,*指针变量名2,……; 例如: int *pi,*pj; float *i,*j,*k; double *l,*m,*n; char *c,*s; 在每个变量前面的星号*是一个指针说明符,用来说明该变量是指针类型。变量前面的星号*不可以省略。指针变量名前面的类型定义是说明指针指向的数据类型。 另外,我们还可以定义一个指向指针的指针变量。定义形式为: 类型名**指针变量名1,**指针变量名2,……;

第8章 善于利用指针(1)

内存管理指针的基本概念指针应用实例指针作函数参数第8章指针(1)

复习回顾 上次课的内容: ◆局部变量和全局变量 ◆变量的作用域 ◆变量的生存期 ◆声明与定义 ◆内部函数 ◆外部函数◆你开始习惯写函数了吗? 2012是如何实现的?假定造成世界末日的上帝是一个程序员,作为一名合格的程序员,他绝不应该写出类似于“摧毁地球”这样的程序,而应该写一个“摧毁(行星)”的函数,然后把地球作为参数传进去!

C语言新手的晋级之路 第一步:萧规曹随 ◆在这一步要求按照教材或讲义上的程序实例进行原样 输入,运行一下程序看是否正确。 ◆在这一步,掌握C语言编程软件的使用方法(包括新 建、打开、熟练输入、编辑、保存、关闭C程序); 初步记忆新学章节的知识点;养成良好的编程风格( 是讲义提倡的而不是教材上的) ◆难点:小心数字1和字母l,字母o和数字0,中英文标 点符号的区别

C语言新手的晋级之路 第二步:移花接木 ◆在第一步输入的C程序的基础上进行试验性的修改, 运行一下程序看一看结果发生了什么变化,分析结果变化的原因,加深新学知识点的理解。 ◆可与第一步同步进行,“输入”可加深记忆,“修改 ”可加深理解,二者相辅相成,互相促进。 ◆友提,一次进行一处修改即可,免得把自己改晕了。

C语言新手的晋级之路 第三步:无中生有 ◆面对教材的例子题目,不参考教材,自己从头开始编 写程序。看能否写出正确运行的代码。 ◆初学者易犯的错误:scanf格式控制和输入不匹配或把变量 名当地址作参数,使用未定义的变量、漏掉或多写“;”、“{” 与“}”、“(”与“)”不匹配,控制语句(选择、分支、循环)的格式不正确,调用库函数没有包含相应头文件,调用未声明 的函数、调用函数时实参和形参不匹配、数组边界越界等等 ◆要学会看编程工具的错误信息提示:双击错误提示光标可 跳转到发生错误的行,如果该行没有错误就往前查找。错误要一 个一个修改,每改完一次编译一下程序。

第8章-指针练习题

指针思考题 一、填空题 【1】下面函数要求用来求出两个整数之和,并通过形参传回两数相加之和值,请填空。 int add( int x, int y, ) { =x+y;} 【2】若有定义: char ch; (1) 使指针p 可以指向变量ch的定义语句是。 (2) 使指针p指向变量ch的赋值语句是。 (3) 通过指针p给变量ch读入字符的scanf函数调用语句是。 (4) 通过指针p 给变量ch赋字符A的语句是。 (5) 通过指针p输出ch中字符的语句是。 (6) 在16位微机上,指针变量p在内存中所占字节数是,变量ch在内在所占字 节数是。 二、选择题 【3】若有说明:int i,j=7,*p=&i;则与i=j;等价的语句是()。 A.i=*p; B.*p=*&j; C.i=&j; D.i=**p; 【4】若有定义:int x,*pb;则正确的赋值表达式是()。 A.pb=&x B.pb=x C. *pb=&x D.*pb=*x 【5】对于类型相同的指针变量,不能进行的运算是()。 A.< B. = C. + D. – 【6】以下程序的输出结果是()。 A.23 B. 24 C. 25 D. 26 Void fun ( int *x) { printf(%d\n”,++*x); } main( ) { int a=25; fun (&a); } 【7】以下程序的输出结果是()。 A.6 B. 7 C. 8 D. 9 main() { int k=2,m=4,n=6; int *pk=&k,*pm=&m,*p; *(p=&n)=*pk*(*pm); printf("%d\n",n); } 【8】以下程序的输出结果是()。 A.100 B. 50 C. 101 D.200 main() { int *v,b; v=&b; b=100;

指针1

指针 一、指针概述 1. 地址 C++程序中每一个实体,如变量、数组和函数等,都要在内存中占有一个可标识的存储区域。每一个存储区域由若干个字节组成,在内存中,每一个字节都有一个“地址”,一个存储区的“地址”指的是该存储区中第一个字节的地址。 2.指针 指针就是存储区域的地址。一个地址指向一个程序实体的存储空间。 直接访问:通过变量名或地址访问程序中一个实体的存储空间的方式(其实通过变量名访问也就是通过地址访问)。 间接访问:把一个变量的地址放在另一个变量中。 3.指针变量 专门用来存放地址的变量就叫指针变量,需要专门加以定义。 二、指针的类型与指针的定义 指针也是具有类型的。指针的类型就是它所指向的变量的类型。例如,一个指向int型的指针,一个指向一维数组的指针。 在使用一个指针变量之前,先要用声明语句对其进行定义。例如:int *p; 定义了一个指向整型数据的指针变量p。即p是一个存放整型变量地址的变量。 应当特别注意的是,定义一个指针变量必须用符号“*”,它表示其后的变量为指针变量,指针变量为p,而不是*p。 要想使一个指针变量指向一个变量,必须将变量的地址赋给指针变量。例如:

int *p, i=3; p=&i; 指针变量也可以定义为指向实型、字符型以及其它类型的变量。如: float *p ; char *q ; 三、指针运算符 在C++语言中,有两个有关指针的运算符: &:为取地址运算符,&x的值为x的地址。 * :指针运算符,或称指向运算符,也称间接运算符,*p代表p 所指向的变量。如: int a=15, *p; p=&a; cout<

第8章 指针

第8章指针 1. 单项选择题 (1)指针 pstr所指字符串的长度为D。char *pstr="\t\"1234\\abcd\n" A.15 B.14 C.13 D.12 (2)若有定义int a[4][6];则能正确表示a数组中任一元素a[i][j](i,j 均在有效范围内)地址的表达式A。 A.&a[0][0]+6*i+j B.&a[0][0]+4*j+i C.&a[0][0]+4*i+j D.&a[0][0]+6*j+i (3)以下程序段的输出结果为D。 char astr[5]="1234"; char *pstr=astr; printf("%c",pstr[1]-'0'); A.1 B. 2 C. ASCII码值为 1 的字符 D. ASCII 码值为 2 的字符 (4)下述程序段的输出结果为D。 char astr[]="abcde"; char *pstr=&astr[5]; while(--pstr>=astr) putchar(*pstr); putchar('\n'); A. abc B. cba C. abcde D. edcba (5)若有定义 int a=1,*b,c;,以下不正确的是 A 。 A. b=a B. b=&a C. b=&a,c=*b D. c=a (6)以下程序段的运行结果为 C 。 intnum[]={1,2,3,4,5,6,7,8,9},*pnum=&num[2]; pnum++; ++pnum; printf("%d\n",*pnum); A. 3 B. 4 C. 5 D. 6 (7)以下程序段的运行结果为 B 。 char *pstr="My name is Tom"; int n=0;

C二级 第8章 指针

1.以下定义语句中正确的是 A) int a=b=0; B) char A=65+1,b='b'; C) float a=1,*b=&a,*c=&b; D) double a=0.0; b=1.1; 参考答案:B 【解析】A选项语句中b变量还没有定义不能直接用于给a变量赋值?C选项语句中*b?*c表示的是一个实型变量的地址,不能再将&b赋值给指针型变量c?D选项语句中a=0.0后面应该为逗号,不能是分号? 2.有以下程序 #include void f(int *p,int *q); main() { int m=1,n=2,*r=&m; f(r, &n); printf("%d,%d",m,n); } void f(int *p,int *q) { p=p+1; *q=*q+1; } 程序运行后的输出结果是 A) 2,3 B) 1,3 C) 1,4 D) 1,2 参考答案:B 【解析】在f(int *p,int*q)函数中,执行p=p+1是将p所对应的地址加1,而*q=*q+1是将q所指向的n的地址所对应的值加1,所以m的得知所对应的值没有变,而n的值则为3了。因此B选项正确。 3.以下叙述中正确的是 A) 如果p是指针变量,则&p是不合法的表达式 B) 如果p是指针变量,则*p表示变量p的地址值 C) 在对指针进行加、减算术运算时,数字1表示1个存储单元的长度 D) 如果p是指针变量,则*p+1和*(p+1)的效果是一样的 参考答案:C 【解析】B选项中,如果p是指针变量,则*p表示变量p所指向的地址的值;A选项中,如果p是指针变量,则&p表示变量p的地址;D选项中,如果p是指针变量,*p+1表示将p所指的值加上1,而*(p+1)表示的是先将指针右移一位再取所指向变量的值。因此C选项正确。 4.以下叙述中正确的是 A) 基类型不同的指针变量可以相互混用 B) 函数的类型不能是指针类型 C) 函数的形参类型不能是指针类型 D) 设有指针变量为double *p,则p+1 将指针p移动8个字节 参考答案:D 【解析】B选项中,所谓函数类型是指函数返回值的类型。在C语言中允许一个函数的返回值是一个指针(即地址),这种返回指针值的函数称为指针型函数;C选项中,函数的参数不仅可以是整型、实型、字符型等数据,还可以是指针类型;A选项中,虽然不同基类型的指针变量占用字节数是相同的,但是不能混用。因此D选项正确。 5.如果定义 float a[10], x; 则以下叙述中正确的是

第8章-指针

第八章 一、选择题。 8.1若有定义:int x,*pb;则正确的赋值表达式是()。 A) pb=&x B)pb=x C)*pb=&x D)*pb=*x 8.2 若有以下程序: #include main() { printf(“%d\n”,NUUL); } 程序的输出结果是()。 A)因变量无定义输出不定值B)0 C)-1 D)1 8.3若有以下程序: #include void sub(int x,int y,int *z) { *z = y-x;} main() { int a,b,c; sub(10,5,&a); sub(7,a,&b); sub(a,b,&c) printf(“%d,%d,%d\n”,a,b,c); } 程序的输出结果是()。 A)5,2,3 B)-5,-12,-7 C)-5,-12,-17 D)5,-2,-7 8.4若有以下程序: #include main() { int k=2,m=4,n=6,*pk=&k,*pm=&m,*p; *(p=&n) =*pk*(*pm); printf(“%d\n”,n); } 程序的输出结果是()。 A)4 B) 6 C) 8 D) 10 8.5若指针p已正确定义并指向如图8.8所示储存单元: a[0] a[1] a[2] a[3] a[4] p↑ 图8.8 指针p指向示意图 则执行语句*p++;后,*p的值是()。 A)20 B)30 C)21 D)31 8.6若指针p已正确定义并指向如图8.8所示存储单元,则表达式*++p的值是()。 A)20 B)30 C)21 D)31 8.7若指针p已正确定义并指向如图8.8所示存储单元,则表达式++*p的值是()。 A)20 B)30 C)21 D)31 8.8若有以下程序: #include void prtv(int *x)

C语言第八章 地址和指针

第八章 地址和指针 第一节 变量的地址和指针 1、计算机的内存是以字节为单位的一片连续的存储空间,每一个字节都有一个编号,这个编号就成为内存地址。 2、程序中定义了一个变量,c 编译系统就会根据定义中变量的类型,为其分配一定字节数的内存空间: Short int 2 Int float 4 Double 8 char 1 指针 4 图8.1 变量在内存中所占字节的地址示意图 每个变量的地址就是指该变量所占存储单元的第一个字节的地址。 3、直接存取:程序中我们对变量进行存取操作,实际上也 a 2001 p 3001 a b x 1012 1013 1015 1016 1201 1202 1203 1204

就是对某个地址的存储单元进行操作。这种直接按变量的地址存取变量值的方式。 4、在c 语言中,还可以定义一种特殊的变量,这种变量只是用来存放内存地址的。 图8.2 存放地址的指针变量示意图 通过变量p 间接得到变量a 的地址,然后再存取变量a 的值的方式称为“间接存取”方式,通常变量p 指向了变量a ,变量a 是变量p 所指向的对象。 5、用来存放指针地址的变量就称作“指针变量”。 6、“变量p 指向变量a ”的含义就是指针变量p 中存放了变量a 的地址。 7、在某些场合,指针是使运算得以进行的唯一途径。 第二节 指针的定义赋值 一、 指针变量的定义和指针变量的基本类型 1、 定义指针变量的一般形式如下: 类型名 *指针变量名1,*指针变量名2…… 说明:1)类型名是基本类型。 2)*是说明符。(而在调用的时候,代表的是存储单元中的值) 3)指针变量名是用户标识符。 2002 2002 1012 1013 p a p

C语言知识第8章1-王厚财

复习: 1.数值型数组与字符型数组的定义 2.数值型数组的赋初值与字符型数组的赋初值以及字符串的赋值 3.对于数值型数组的操作 4.对于字符串的操作及函数 5.排序 讲授新课: 第8章 指 针 指针是C语言中广泛使用的一种数据类型。 8.1 地址与指针 8.1.1数据在内存中的存储 计算机的内存是以字节为单位的一片连续的存储空间,每一个字节都有一个确定的编号,这个编号就是内存地址。 a x

见图8.1所示,内存的编号从0开始,连续进行编号。在实际处理中,地址通常采用十六进制数形式。 8.1.2 变量的地址 在C程序中定义了一个变量,C编译系统就会根据定义中变量的类型,为其分配一定字节数的内存空间,所分配存储空间的首地址称为此变量的地址。所分配存储空间中的数据就是这个变量的值,也就是存储单元的内容。 8.1.3 变量的存取方式 1.直接存取 一般情况下,我们在C程序中只需指出变量名就可以对变量进行存取操作,实际上也是对某个地址的存储单元进行操作。这种直接按变量的地址存取变量值的方式称为“直接存取”方式。 2.间接存取 与“直接存取”方式相对应的是“间接存取”方式。在C语言中,我们通过定义一种特殊的变量(即指针变量,一会我们将详细叙述;同时,为了叙述方便,我们将前面章节中定义的变量称为普通变量。)用于存放内存单元的地址,然后根据这种特殊的变量的内容(里面存放的是地址值)去访问相应的存储单元。这种方式称为“间接存取”方式。 “--- ”只是一种示意,形似“指针”。用来存放地址值的变量称为指针变量,“变量p指向了变量a”的含义是指针变量p中存放了变量a的地址。 8.1.4 指针变量 如果一个变量中存放是地址值,那么称这个变量为指针变量。常把指针变量简称为指针。定义指针的目的是为了通过指针去访问内存单元。

C语言程序设计(第3版)何钦铭 颜 晖 第8章 指针

第8章指针 【练习8-1】如果有定义”int m, n = 5, *p = &m;”与m = n等价的语句是 B 。A.m = *p; B. *p = *&n; C. m = &n; D. m = **p; 解答: A:p是指向m的指针变量,所以*p等价于m。即m=m。 B:&n是n的地址,*&n是n的值,即把n的值赋给p指向的值m。即m=n。 C:&n是n的地址。即把n的地址赋给m。 D:**p是指p指向的指针所指向的值,在此无意义。 故选B。 【练习8-2】调用函数求两个数的和与差:计算输入的两个数的和与差,要求自定义一个函数sum_diff(float op1,float op2, float *psum, float *pdiff),其中op1和op2是输入的两个数,*psum 和*pdiff 是计算得出的和与差。 解答: #include<> void sum_diff(float op1,float op2,float *psum,float *pdiff); int main(void) { float op1,op2,sum,diff; printf("Input op1 and op2: "); scanf("%f%f",&op1,&op2); sum_diff(op1,op2,&sum,&diff); printf("%f+%f=%f;%f-%f=%f \n",op1,op2,sum,op1,op2,diff); return 0; } void sum_diff(float op1,float op2,float *psum,float *pdiff) { *psum=op1+op2; *pdiff=op1-op2; } 【练习8-3】两个相同类型的指针变量能不能相加为什么 解答: 不能。因为指针变量是一种特殊的变量,指针变量的值存放的是所指向变量的地址,两个地址相加并不能保证结果为一个有效的地址值,因而在 C 语言中指针变量相加是非法的。 【练习8-4】根据表所示,这组数据的冒泡排序其实循环到第 6 遍(即n-2)时就已经排好序了,说明有时候并不一定需要n-1 次循环。请思考如何改进冒泡排序算法并编程实现(提示:当发现一遍循环后没有数据发生交换,说明已经排好序了)。 解答:

第八章 文 件

第八章文件 一、单项选择题 1.C语言中,文件由(A)。 A.字符(字节)序列组成B.记录组成 C.数据行组成D.数据块组成 2.若文件型指针fp中指向某文件的末尾,则函数feof(fp)的返回值是(C)。 A.0 B.-1 C.非零值D.NULL 3. 下列语句将输出(B) #include printf(“%d %d %d”, NULL,’\0’,EOF); A. 0 0 1 B. 0 0 –1 C. NULL EOF D. 1 0 EOF 4.下列语句中,将fp定义为文件型指针的是(B)。 A.FILE fp; B.FILE *fp;C.file fp; D.file *fp; 5. 定义FILE *fp; 则文件指针fp指向的是(D)。 A. 文件在磁盘上的读写位置 B. 文件在缓冲区上的读写位置 C. 整个磁盘文件 D. 文件类型结构体 6. 缓冲文件系统的缓冲区位于(C )。 A. 磁盘缓冲区中 B. 磁盘文件中 C. 内存数据区中 D. 程序中 7.以“只读”方式打开文本文件a:\aa.dat,下列语句中哪一个是正确的( D)。 A、fp=fopen(”a:\aa.dat”,”ab”); B、fp=fopen(”a:\aa.dat”,”a”); C、fp=fopen(”a:\aa.dat”,”wb”); D、fp=fopen(”a:\aa.dat”,”r”); 8. 以“追加”方式打开文本文件a:\aa.dat,下列语句中哪一个是正确的( B)。 A、fp=fopen(”a:\aa.dat”,”ab”); B、fp=fopen(”a:\aa.dat”,”a”); C、fp=fopen(”a:\aa.dat”,”r+”); D、fp=fopen(”a:\aa.dat”,”w”); 9. 如果二进制文件a.dat已存在,现要求写入全新的数据,应以什么方式打开(A)。 A. “w” B. “wb” C. “w+” D. “wb+” 10. 为读写建立一个新的文本文件a:\aa.dat,下列语句中哪一个是正确的( B)。 A、fp=fopen(”a:\aa.dat”,”ab”); B、fp=fopen(”a:\aa.dat”,”w+”); C、fp=fopen(”a:\aa.dat”,”wb”); D、fp=fopen(”a:\aa.dat”,”rb+”); 11.以读写方式打开一个已有的二进制文件filel,并且定义FILE *fp,下面fopen函数正确的调用方式是(B )。 A.fp=fopen (“file1”, ”r”) B.fp=fopen (“file1”, ”rb+”) C.fp=fopen (“file1”, ”rb”) D.fp=fopen (“file1”, ”w b+”) 12.标准库函数fputs (p1,p2)的功能是(C)。 A.从p1指向的文件中读一个字符串存入p2指向的内存 B.从p2指向的文件中读一个字符串存入p1指向的内存 C.从p1指向的内存中读一个字符串写到p2指向的文件中 D.从p2指向的内存中读一个字符串写到p1指向的文件中

第八章 指针

第八章指针 【本章要求】 1、指针的声明、定义方法以及通过指针变量引用存储单元中的内容 2、指针作为函数参数,地址传递情况下,函数实参的变化 3、用指针指向函数,并通过指针调用该函数 4、一维数组和字符串中元素地址的计算方法,以及通过指针引用这些元素 5、二维数组中元素的计算方法,以及通过指针数组引用其中元素的方法 6、通过命令行方式调用main函数 7、内存的动态分配和释放 8.1 指针的基本概念 如果在程序中定义了一个变量,在编译时就给这个变量分配内存单元。系统根据程序中定义的变量类型,分配一定长度的空间。内存区的每一个字节有—个编号,这就是“地址”,它相当于旅馆中的房间号。 在程序中一般是通过变量名来对内存单元进行存取操作的。程序经过编译以后己经将变量名转换为变量的地址,对变量值的存取都是通过地址进行的。 按变量地址存取变量值的方式称为“直接访问”方式。 还可以采用另一种称之为“间接访问”的方式,将变量i的地址存放在另一个变量中。按C 语言的规定,可以在程序中定义整型变量、实型变量、字符变量等,也可以定义这样一种特殊的变量,它是存放地址的。 假设我们定义了一个变量i_pointer,用来存放整型变量的地址,它被分配为3010、3011字节。可以通过下面语句将i的地址(2000)存放到i_pointer中。 i_pointer = &i; 这时,i_pointer的值就是2000,即变量i所占用单元的起始地址。要存取变量i的值,也可以采用间接方式;先找到存放“i的地址”的变量,从中取出i的地址(2000),然后到2000、2001字节取出i的值(3)。 所谓“指向”就是通过地址来体现的。i_pointer中的值为2000,它是变量i的地址,这样就在i_pointer和变量i之间建立起一种联系,即通过i_pointer能知道i的地址,从而找到变量i的内存单元。 在C语言中,将地址形象化地称为“指针”。意思是通过它能找到以它为地址的内存单元(例如根据地址2000就能找到变量i的存储单元,从而读取其中的值)。一个变量的地址称为该变量的“指针”。例如,地址2000是变量i的指针。如果有一个变量专门用来存放另一变量的地址(即指针),则它称为“指针变量”。指针变量的值(即指针变量中存放的值)是指针(地址)。 8.2 指针变量 变量的指针就是变量的地址。存放变量地址的变量是指针变量,用来指向另一个变量。为了表示指针变量和它所指向的变量之间的联系,在程序中用“*”符号表示“指向”。 - 93 -

第八章:善于利用指针

南京信息工程大学滨江学院实验(实习)报告 实验(实习)名称指针实验(实习)日期 2011.12 指导教师宣文霞 专业实验班年级大一班次4 班姓名王雅婷学号 20112335052 Eg8-1: 输入两个整数,并使其从大到小输出,用指针变量实现数的比较。 (1)源程序: #include void main() { int *p1,*p2,*p,a,b; scanf("%d,%d",&a,&b); p1=&a; p2=&b; if(a void swap(int *p1, int *p2) { int p; p=*p1; *p1=*p2; *p2=p; } void main() { int a,b; int *p,*q; scanf("%d,%d",&a,&b); p=&a; q=&b;31 if(a

(3)结果输出: (4)如果将swap 函数修改为如下形式,分析如何调试和修改? void swap(int *p1, int *p2) { int *p; *p=*p1; *p1=*p2; *p2=*p; } Eg8-3:用指针法输入12 个数,然后按每行4 个数输出。 (1)算法分析:定义一个整型数组和一个整型指针,这样通过数组就可以静态分配内存空间,存储数据;然后将指针与数组相关,使指针指向与数组相同的首地址处,这样就可以通过指针或者数组都可以对存储空间加以操作。 (2)源程序: #include void main() { int j,k,a[12],*p ; p=a; //使指针p 指向与数组a 相同的首地址处 for(j=0;j<12;j++) scanf("%d",p++); //移动P 的位置,输入数据 p=a; //指针重定位 for(j=0;j<12;j++) { if(j%4==0) printf("\n"); //按每行4 个数输出 printf("%4d",*p++); } printf("\n"); } (3)输入数据:0 1 2 3 4 5 6 7 8 9 10 11

操作系统第八章课后习题

1.目前常用的外存有哪几种组织方式? 答;(1)连续组织方式。为每一个文件分配- -组位置相邻接的盘块,由此形成的文件物理结构是顺序式的文件结构。 (2)链接组织方式。为每个文件分配一组位置离散的盘块,通过给每个盘块设置一个指针,将属于同-一个文件的盘块链接在一起,链接的顺序和文件的逻辑页的顺序一致。由此形成的文件物理结构是链接文件。 (3)索引组织方式。为每个文件分配- -组位置离散的盘块,为每个文件建立一个物理结构的索引表,记录分配给该文件的物理盘块,以及这些盘块和文件逻辑页顺序的对应关系。由此形成的文件物理结构是索引文件。 2.由连续组织方式所形成的顺序文件的主要优缺点是什么?它主要应用于何种 场合? (1)连续组织方式所形成的顺序文件的主要优点①顺序访问容易②顺序访问速度快 (2)连续组织方式所形成的顺序文件的主要缺点①要求为一个文件分配连续的存储空间 ②必须事先知道文件的长度;③不能灵活地删除和插入记录 ④对于那些动态增长的文件,由于事先很难知道文件的最终大小,因而很难为分配空间,而即使事先知道文件的最终大小,在采用预分配存储空间的方法时也会使大量的存储空间长期空闲。 (3)主要适用场合:连续组织方式所形成的顺序文件是一种最简单、最常用的文件组织方法,它适用于许多资料处理的场合,如磁带文件,打印文件都是常用的顺序文件。 3.在链接式文件中常用哪种链接方式?为什么? 答:链接方式分为隐式链接和显式链接两种形式。隐式链接是在文件目录的每目录项中,都含有指向链接文件第一个盘块和最后一个盘块的指针。显式链接贝把用于链接文件各物理块的指针,显式地存放在内存的一张链接表中。 4.在文件分配表中为什么要引入“簇”的概念?以“簇”为基本的分配单位有什么好处? (1)引入“簇”的原因:为了适应磁盘容量不断增大的需要,在进行盘块分配时不再以盘块而是以簇(Cluster)为基本单位。一个簇应包含扇区的数量与磁盘量的大小直接有关。 (2)以簇作为基本分配单位的好处:能应磁盘容量不断增大的情况,还可以减少FAT 表中的项数(在相同的磁盘容量下,FAT表的项数是与簇的大小成反比),使FAT 表占用更少的存储空间,并减少访问FAT表的存取开销。 5.简要说明为什么要从FAT12发展为FAT16?又进一步要发展为FAT32? 答:(1)从FAT12发展为FAT16的原因:FAT12 表中的表项有限制,亦即最多只允许4096个。这样,随着磁盘容量的增加。必定会引起簇的大小和簇内碎片也随之增加。要想增加FAT 表中的表项数,就必须增加FAT 表的位数(宽度)如果我们将FAT表项位数增至16位,最大表项数将增至65536 216 )个,此时便能将一个磁盘分区分为65536 (216 )个簇。 (2)从FAT16发展为FAT32的原因:由于FAT16 表的长度只有65535项,随着磁盘容量的增加,簇的大小也必然会随之增加,为了减少簇内零,也就应当增加FAT 表的长度,为此需要再增加FAT 表的宽度,这样也就由FAT16演变为FAT32

相关主题
文本预览
相关文档 最新文档