第八章地址和指针
- 格式:doc
- 大小:61.50 KB
- 文档页数:11
《C语言程序设计》基本知识点第一章C语言基本知识1.C源程序的框架尽管各个C源程序的功能千变万化,但框架是不变的,主要有:编译预处理、主函数()、函数n()等,主函数的位置不一定在最前面,可以在程序的中部或后面,主函数的名字固定为main。
2.C语言源程序的书写规则:(1)C源程序是由一个主函数和若干个其它函数组成的。
(2)函数名后必须有小括号,函数体放在大括号内。
(3)C程序必须用小写字母书写。
(4)每句的末尾加分号。
(5)可以一行多句。
(6)可以一句多行。
(7)可以在程序的任何位置加注释。
3.语句种类语句是程序的基本成分,程序的执行就是通过一条条语句的执行而得以实现的,根据表现形式及功能的不同,C语言的基本语句可以分为五大类。
(1)流程控制语句流程控制语句的功能是控制程序的走向,程序的流程有三种基本结构:顺序结构、分支结构和循环结构,任何复杂的程序都可以由这三种基本结构复合而成。
其中后两种结构要用特定的流程控制语句实现。
(2)表达式语句表达式语句的形式是:表达式;,即表达式后跟一分号“;”,分号是语句结束符,是一个语句必不可少的成分。
表达式和表达式语句的区别在于表达式代表的是一个数值,而表达式语句则代表一种动作。
最常见的表达式语句是赋值语句。
(3)函数调用语句函数调用语句实际上也是一种表达式语句,形式为:在一次函数调用的小括号后面加上一个分号。
(4)空语句空语句的形式就是一个分号,它不代表任何动作,常常作为一个意义转折点使用。
(5)复合语句复合语句从形式上看是多个语句的组合,但在语法意义上它只相当于一个语句,在任何单一语句存在的地方都可以是复合语句。
注意复合语句中最后一个语句末尾的分号不能少。
复合语句右大括号后面没有分号。
4.运算符用来表示数据各种操作的符号称为运算符。
运算符实际上代表了一种类型数据的运算规则。
不同的运算符具有不同的运算规则,其操作的数据类型必须符合该运算符的要求,运算结果的数据类型也是固定的。
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 <stdio.h>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语言程序设计是计算机科学与技术领域中非常重要的基础课程之一。
谭浩强教授所著的《C语言程序设计》自问世以来,以其通俗易懂的语言和丰富的实例,深受广大学生和编程爱好者的喜爱。
第四版在继承前三版优点的基础上,对内容进行了更新和完善,更加符合现代编程教育的需求。
第一章:C语言概述本章主要介绍了C语言的发展历程、特点以及C语言在计算机编程领域中的应用。
C语言以其高效、灵活和可移植性,成为系统编程、嵌入式开发等领域的首选语言。
第二章:C语言的基本概念本章详细讲解了C语言的基本组成元素,包括数据类型、变量、常量、运算符和表达式等。
这些是编写C程序的基础,也是理解程序逻辑的关键。
第三章:顺序结构程序设计顺序结构是最简单的程序结构,本章通过实例讲解了如何使用顺序结构编写程序,以及如何通过输入输出函数实现数据的交互。
第四章:选择结构程序设计本章介绍了条件语句if、switch等选择结构的使用,通过这些结构可以实现程序的分支逻辑,使程序能够根据不同的条件执行不同的代码块。
第五章:循环结构程序设计循环结构是程序设计中不可或缺的部分,本章详细讲解了for、while、do-while等循环语句的用法,以及如何使用循环结构实现重复操作。
第六章:数组数组是存储多个同类型数据的集合,本章介绍了一维数组和二维数组的定义、初始化和使用,以及如何通过数组实现数据的批量处理。
第七章:函数函数是程序模块化的基础,本章讲解了函数的定义、声明、调用以及参数传递机制,包括值传递和地址传递的区别和应用。
第八章:指针指针是C语言中非常强大的特性之一,本章详细介绍了指针的基本概念、指针与数组的关系、指针的运算以及指针在函数中的应用。
第九章:结构体与联合体本章介绍了如何使用结构体和联合体来定义复杂的数据类型,以及如何通过这些复合数据类型实现数据的组织和管理。
第十章:预处理命令预处理命令是C语言编译过程中的特殊指令,本章讲解了宏定义、文件包含、条件编译等预处理命令的用法。
第八章磁盘存储器的管理第一节文件的物理结构和外存的分配方式一、概述磁盘是一种可直接存取的随机存储器(这一点与内存相似),一个逻辑盘可以看作一片连续的存储空间。
确定外存空间的分配方式(组织文件的物理结构)主要考虑:提高文件的访问速度、有效地利用外存空间。
常用的外存分配方法有:连续分配、链接分配、索引分配。
二、磁盘存储空间的结构磁盘说明图1盘块(扇区)是磁盘上的最小存储分配单位,每个盘块有唯一编号;地址是:磁道(柱面)号+扇区号+盘面号;从盘块编号到地址的转换由硬件完成,在OS中一个盘块的地址就是盘块编号。
一般一个盘块的大小与内存分页中页(内存块)的大小一致,一页存放到一个盘块中。
三、连续分配1、思想方法为每个文件分配一组位置相邻接的盘块(磁盘上的地址连续/盘块编号连续的盘块),文件中的逻辑页被顺序地存放到邻接的各物理盘块中。
这保证了文件中的逻辑顺序与文件占用盘块顺序的一致性。
这样物理结构的文件称为顺序文件;每个文件都从分配给它的一个盘块的第一个字节开始存放。
文件地址:在文件的目录中,存放该文件的第一个记录所在的盘块号和文件的长度(共占多少块)。
1230567491011813141512171819162122232025262724list29303128mailcountfile start length coun t 02tr 143mail 196list 284f62????tr f图 8-1 磁盘空间的连续分配2、优缺点◆存取容易,存取速度较快;◆必须事先知道文件的长度,不利于文件的动态增长; ◆存放一个文件要求足够大的连续存储空间; ◆存储空间的管理存在“碎片”问题,须定时整理。
四、链接分配1、思想方法:为每个文件分配一组位置离散的盘块,每个盘块中存放文件的一个逻辑页;通过给每个盘块设置一个指针,将属于同一个文件的盘块链接在一起,链接的顺序和文件的逻辑页的顺序一致。
这样物理结构的文件称为链接文件。
C语言笔记第一章程序设计基本概念1.C语言是一种结构化的程序设计语言。
2.C语言中没有子程序的概念,它提供的函数可以完成子程序的所有功能。
3.C语言允许对函数进行单独编译,从而可以实现模块化。
第二章 C语言设计的初步知识1.C语言的模块化主要是通过函数实现的。
2.C语言有高级语言和低级语言的功能,技能编写系统软件,又能编写应用软件3.程序中main()是主函数的起始行,也是C程序执行的起始行。
4.一个C程序总是从主函数开始执。
5.分号是C语句的一部分,不是语句之间的分隔符。
6.程序中“﹟include 〈stdio.h〉”通常称为命令行,命令行必须用“﹟”号开头,行尾不能有“;”号,它不是C程序中的语句。
7.标识符必须由字母、数字和下划线组成,,并且第一个字符必须是字母或下划线。
8.在C语言中,大写字母和小写字母被认为是两个不同的字符。
9.C语言标识符分为三类:关键字、预定义标识符和用户标识符。
10.常量分为数值型常量(整型常量(短整型、基本整型、长整型、无符号型)和实行常量)、字符型常量和字符串常量。
11.一个变量实际上代表了内存上的某个存储单元。
12.对变量的定义通常放在函数体内的前部,但是也可以放在函数的外部和复合语句的开头。
13.十六进制中的a、b、d、e、f既可以是小写也可以是大写。
14.在C语言中,只有十进制可以是负数,八进制和十六进制只能是整数。
15.整型变量只能存放整型数值。
16.C语言规定,可以在定义变量的同时给变量赋初值,也称变量初始化。
17.无符号常量不能表示成小于0的负数。
-200u是不合法的。
18.如果一台计算机以两个字节(16个二进制位)来存放一条计算机命令,则称此计算机的字长是16位。
19.通常把一个字节中的最右边一位称为最低位,最左边一位称为最高位。
对于一个有符号整数,其中最高位(最左边一位)用来存放整数的符号,称为符号位。
正整数最高位放0,负整数最高位放1.20.负整数在内存中是以“补码”的形式存在的。
第八章指针的使用【学习目标】本章将详细介绍在C语言中如何使用指针。
学习要点包括如下几点:(1)掌握指针和指针变量的概念,了解指针变量的特点以及直接访问数据和间接访问数据的原理。
(2)掌握指针变量的定义、赋值方法及指针运算符的使用,熟练运用指针访问简单变量。
(3)熟悉指针和一维数组的关系,掌握指向一维数组的指针变量的定义方法,熟练使用指针变量访问一维数组元素。
(4)了解指针与字符串的关系,能熟练使用指针处理字符串。
(5)熟练掌握用指针变量作函数的参数时函数的定义和调用方法、数组名作函数的参数用法。
(6)指向指针的指针的运用。
【学习导航】本章的在整个课程中的位置如图5-1所示。
图8-1 本章学习导航在本书的第一章介绍C语言有一个灵活性的特点,那么它的灵活性具体体现在哪里呢?其实就是指针。
指针是C语言的精华部分,通过利用指针,我们能很好地利用内存资源,使其发挥最大的效率。
有了指针技术,我们可以描述复杂的数据结构,对字符串的处理可以更灵活,对数组的处理更方便,使程序的书写简洁,高效。
8.1 地址和指针指针是C语言的一种数据类型,类似于整型、字符型等。
既然指针也是一种类型,那么也可以定义该类型的变量,称为指针变量。
指针变量和其他类型的变量的区别是:指针变量存储的是地址。
所以要学好指针,就一定要明白数据在内存中是如何存储的。
计算机所有数据都是存储在存储器里,系统的内存可看作编了号的小房间,如果要取房间的东西(读取数据)就需要得到房间编号。
地址就是内存区中对每个字节的编号。
下面通过两个整型变量来说明。
整型变量x、y(基本整型需4个字节)在内存中的存储如图8-2所示(假设内存编号是从2000开始)。
把变量所占用的存储单元首字节的地址作为变量的地址。
C语言中利用取地址运算符“&”获取变量的存储地址。
例如,&c将返回c的首地址;&x将返回x的首地址。
2000H2004H2008H2012H...图8-2 变量x和y在内存中的存储图8-2中2000H和2004H就是内存单元的地址。
第八章指针与引用习题答案一、选择题CBCBCC二、简答题(1)&运算符:取地址运算符,用来得到一个普通变量的地址。
*运算符:间接引用运算符,用来获取指针变量所指向变量的值。
(2)指针:一个变量在内存中所占存储单元的首地址称为该变量的指针,也就是指向该变量的指针。
指针中存储的地址是其所指向的变量的地址,指针中存储的地址里的值就是其所指向变量的值。
(3)引用与指针的区别是,通过某个指针变量指向一个对象后,对它所指向的变量通过*运算符进行间接操作,程序中使用指针,程序的可读性差;而引用本身就是目标变量的别名,对引用的操作就是对目标变量的操作。
可以建立数组的指针,但不能建立数组的引用,因为数组是一个由若干个元素所组成的,所以就无法建立一个数组的别名。
(4)const int *p1 表示p1所指向的int变量为常量,int *const p1 表示p1为常量三、改错题(1)int a;b; 改成int a, b;pointer_1=a; 改成pointer_1=&a;cout<<*a<<" "<<*b<<endl; 改成cout<<a<<" "<<b<<endl;cout<<pointer_2*a<<endl; 改成cout<<(*pointer_2)*a<<endl;(2)有int *p,a=9;p=&a;cout<<”the value of p is ”<<*p;四、阅读程序写结果(1)ABCDEFG(2)x=1.5 y=2.5z=4(3)20 50 50 41(4)m-n=15五、编程题(1)实现字符串逆序输出。
#include <iostream.h>#include <string.h>const char *fun( const char *p1 ){while (*p1++);p1--;return p1;}int main(void){char s1[100];const char *q,*p1;cout<<"输入一个字符串:";cin.getline( s1,100);cout<<"逆向输出串:";q=s1;p1=fun(s1);do{cout<<*p1;p1--;}while(q<=p1);return 0;}(2)输入任意一个字符串,将其中的大写字母转换成小写字母。
第八章地址和指针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,……;例如:int * * p,*s,k=90;s=&k; p=&s;其中&符号表示取变量的内存单元地址运算,后面介绍。
为什么指针变量要有类型之分呢?如前面所述,指针变量中存放的是一个内存单元的地址,这里“一个内存单元”中的“一”所代表的字节数是不同的。
如int型2个字节,float型4个字节,double型8个字节,char型1个字节等。
在后面的指针运算中我们经常要对指针进行加、减、移动等操作,此时指针操作的单位是一个存储单元,而不是一个字节,因此对于不同类型的指针变量来说,其操作时所跨越的内存字节数是不同的。
如:定义一个指针变量i(存放的初始地址为2060H),当我们执行i++操作时,不同类型的指针变量所移动的字节数是不同的。
8.3 指针变量赋值一、给指针变量赋地址值一个指针变量可以通过不同的方式获得一个确定的地址值,从而指向一个具体的操作对象。
1、通过取地址运算符(&)获得地址值单目运算符“&”的作用是用来获取变量的内存单元地址。
其使用格式为:&变量名。
如:int k=80, h=100, *p, *q; 则赋值语句为p=&k; q=&h;其指向关系见书p94图8.3我们可以说:指针p指向了整型变量k,和指针q指向了整型变量h。
即:指针变量p中存放了整型变量k所在的存储单元地址,和指针变量q中存放了整型变量h所在的存储单元地址。
取地址运算符(&)只能够用于变量和以后将要介绍的数组元素,不能够应用于表达式、常量或者被说明为register的变量(第12章介绍)。
另外,&符号必须要放在运算对象的左边,而且运算对象的类型必须与指针变量的基本类型相同。
在调用scanf函数时,我们输入的各变量之前必须要加&符号。
如:scanf (“%d%c%f”, &a, &b, &c );2、通过指针变量获得地址值我们可以通过赋值,把一个指针变量中地址赋给另一个指针变量,从而使两个指针变量指向同一个地址。
如:int k=80, *p, *q;p=&k; q=p;此时,指针变量p 和q都同时指向了整型变量k 所在的内存单元地址。
但是要注意,进行赋值运算时,赋值号两边指针变量的基本类型必须要相同。
二、给指针变量赋“空”值有时我们还需要给指针变量赋“空”值,形如:p=NULL;NULL是在”stdio.h”头文件中定义的预定义符号,因此在使用NULL时,应在程序的前面出现预定义行:# include “stdio.h”。
NULL的ASCII代码值为0,当执行了以上的赋值语句后,称指针p为空指针。
因此上述语句也可以书写为:p=’\0’;或p=0;这时p并不指向地址为0的存储单元,而是具有一个确定的值——“空”。
8.4 对指针变量的应用一、通过指针来引用一个存储单元C语言提供了一个可以间接访问地址的单目运算符:星号“*”。
当指针变量中存放了一个确定的地址值时,就可以使用指针访问运算符对存储单元中的数据进行访问。
如:int *p, i=10, j;p=&i;则以下赋值语句:j=*p;的作用是将变量i 的值赋予变量j,这里*p 代表指针p 所指向的变量i。
等价于j=i;间接地址访问运算符是一个单目运算符,必须出现在运算对象的左边,其运算对象或者是存放地址的指针变量或者是内存单元地址。
例如:j=*(&i);由于运算符*和&的优先级别相同,且结合方向为自右至左,因此表达式中的括号可以省略。
写成:j=*&i;又例如:j=*p+1;由于*的运算优先级高于+,因此语句功能为:取指针变量p所指向的存储单元中的内容并加1后送给变量j。
有例如:int *p, k=0;p=&k;则语句*p=100;的作用是将整数100送给变量k。
等价于k=100。
此后若有语句*p=*p+1;则功能为:取指针变量p中所指存储单元中的数据,加1后再存放到指针变量p 所指的存储单元中。
相当于k++或k=k+1;以上语句还可以书写成:*p+=1;或++*p;或(*p)++;注意:在表达式+ + * p中,++和*两个运算符的优先级相同,但按照自右至左的方向结合,因此++*p等价于++(*p)。
而在表达式(*p)++中,一对括号不可以缺少,(*p)++表示先取指针变量p所指向的存储单元中的值,然后加1作为表达式的值。
不可以写成*p++,否则将先计算*p作为表达式的值(在此为100),然后使指针变量p自身增1,所以*p++并不使p所指内存单元的数据加1,而是将指针向后移动了一个存储单元。
例如:用指针指向两个变量,通过指针运算选出值大的那个数据。
# include “stdio.h”main ( ){ int a, b,max, *pa, *pb, *pmax;pa=&a; pb=&b; pmax=&max;printf (“input a and b:”);scanf (“%d%d”, &a,&b); // scanf (“%d%d”, pa,pb);printf ( “a=%d b=%d\n”, a, b);*pmax=*pa;if ( *pa<*pb ) *pmax=*pb;printf ( “max=%d\n”, max );//printf ( "max=%d\n", *pmax );}二、移动指针所谓移动指针就是对指针变量加上或减去一个整数,或通过运算使指针变量指向其他存储单元。
因此,只有当指针指向一个连续的存储单元时,指针的移动才有意义。
当指针指向一个连续的存储单元时,即可以对指针变量进行加减运输,也可以对指针进行逻辑和其它C语言支持的运算。
例如:假定在内存中开辟了下列6个int型存储单元,如下表所示编号a[0] a[1] a[2] a[3] a[4] a[5]数据地址2001H 2003H 2005H 2007H 2009H 200BH 指针p↑q↑则分别执行下列语句后,运行结果分别是什么?(1)p++; (2)q++; (3)q=p+2; (4)a=q-p;(5)a=*p; (6)a=*q; (7)a=*(p+2) (8)a=*p++;(9)a=*p+2; (10)a=p<=q;用下列程序进行演示# include “stdio.h”main ( ){ int a[6], a,, *p, *q;a[0]=11; a[1]=22; a[2]=33; a[3]=44; a[4]=55; a[5]=66;p=&a[1]; q=&a[4];带入上面语句printf ( 根据情况进行打印操作); }通过上面例子我们可以知道,指针的运算是以存储单元为基本单位的,而不是以字节为基本单位的,因此,不同类型的数据(int、char、float、double)存储单元是不一样的。
且当指针进行比较运算时,是以其所指向的地址值的大小作为依据的。
8.5 函数之间地址值的传递一、形参为指针变量时实参和形参之间的数据传递若函数的形参为指针变量,在调用该函数时,对应的实参也必须是基本类型相同的地址值或是已经指向某个存储单元的指针变量。
例如:从键盘输入两个数据,在子函数中完成数据交换,主函数与子函数之间的数据传递以地址的形式进行。
# include “stdio.h”main( ){ void swap(int * ,int * ); /* 函数声明,参数是指针类型*/ int a,b;printf("Please input two integer numbers(a,b):");scanf("%d,%d",&a,&b);swap(&a,&b); /* 引用调用 */printf("a=%d\tb=%d\n",a,b); /* 调用swap( )后a 与b 的值 */ }void swap(int *x,int *y){ int temp;temp=*x;*x=*y;*y=temp; /* 数据值交换,而不是地址交换*/ printf("x=%d\ty=%d\n",*x,*y);}在程序执行过程中,主函数调用swap 函数时,系统自动为swap 函数的形参x 和y 开辟了两个类型为int 型的指针变量,并通过实参&a 和&b 将变量a 和b 的地址传递给它们,如下图所示,这时,指针x 指向变量a ,指针y 指向变量b 。