目錄
第4章 選擇結(jié)構(gòu)程序設(shè)計(jì)
第5章 循環(huán)結(jié)構(gòu)程序設(shè)計(jì)
內(nèi)部函數(shù)
外部函數(shù)
8.3.5 指向函數(shù)的指針(函數(shù)指針變量)
8.3.8 動(dòng)態(tài)內(nèi)存分配與指向它的指針變量
第10章 對(duì)文件的輸入輸出(主要討論數(shù)據(jù)文件)
第1章 什么是C語(yǔ)言
C語(yǔ)言的先祖是BCPL語(yǔ)言。它是由美國(guó)貝爾實(shí)驗(yàn)室的D.M.Ritchie在1972-1973年間設(shè)計(jì)出來(lái)的計(jì)算機(jī)編程語(yǔ)言。C語(yǔ)言還是目前使用最為廣泛的計(jì)算機(jī)編程語(yǔ)言之一,由于它學(xué)習(xí)起來(lái)簡(jiǎn)單、使用方便、功能強(qiáng)大和容易上手等特點(diǎn),普遍被廣大程序設(shè)計(jì)者使用。
第2章 算法
算法需要有以下特性:(1)有窮性:有限的操作步驟;(2)確定性:每個(gè)步驟都是確定的,不能含糊;(3)有零個(gè)或多個(gè)輸入:從外界獲取必要輸入信息;(4)有一個(gè)或多個(gè)輸出:一個(gè)沒(méi)輸出的算法沒(méi)有意義;(5)有效性:每個(gè)步驟都能有效執(zhí)行;
第3章 最簡(jiǎn)單的C程序設(shè)計(jì)
3.1 數(shù)據(jù)類(lèi)型
3.1.1 常量
常量包括以下幾種:整形常量、實(shí)型常量、字符常量、字符串常量和符號(hào)常量。整形常量如100等;實(shí)型常量有兩種形式,一種是十進(jìn)制小數(shù)形式如10.21,另一種是指數(shù)形式如12.34e3(代表12.34×10*3);字符常量包括普通字符如‘a(chǎn)’,和轉(zhuǎn)義字符‘\n’。字符串常量是使用雙撇號(hào)把若干個(gè)字符括起來(lái),如“boy123”。符號(hào)常量是指使用#define指令,指定一個(gè)符號(hào)代表一個(gè)常量,如#define P1 3.12,這時(shí)P1代表3.12。
3.1.2 變量
變量代表一個(gè)有名字的、具有特定屬性的一個(gè)存儲(chǔ)單元,存儲(chǔ)單元里的值是可以改變的,所以變量的值可以改變。在使用變量時(shí)必須先定義,后使用。在有些情況下我們不希望變量的值被改變,這時(shí)可以將變量定義為常變量。使用const可以將變量定為常變量,如const int P1=12,之后P1的值將不會(huì)被改變。
3.1.3 數(shù)據(jù)類(lèi)型
在定義變量和函數(shù)時(shí),需要指定相應(yīng)的數(shù)據(jù)類(lèi)型,數(shù)據(jù)類(lèi)型包括:整型類(lèi)型、浮點(diǎn)類(lèi)型、枚舉類(lèi)型(enum)、空類(lèi)型(void)和派生類(lèi)型。
整型類(lèi)型:注意整型中,區(qū)分有無(wú)符號(hào)的整型,無(wú)符號(hào)需要加上unsigned,如unsigned int a;
類(lèi)型 | 字節(jié) |
基本整形(int) | 2或4 |
短整型(short) | 2 |
長(zhǎng)整型(long int) | 4 |
雙長(zhǎng)整型(long long int) | 8 |
字符型(char) | 1 |
布爾型(bool)值true 和 false | 1 |
浮點(diǎn)類(lèi)型:
類(lèi)型 | 字節(jié) |
單精度浮點(diǎn)型(float) (有效6位) | 4 |
雙精度浮點(diǎn)型(double) (有效8位) | 8 |
長(zhǎng)雙精度浮點(diǎn)型(long double) 有效(16位) | 16 |
復(fù)數(shù)浮點(diǎn)型 (不常用) |
派生類(lèi)型:
指針類(lèi)型(*) | 數(shù)組類(lèi)型([ ]) | 結(jié)構(gòu)體類(lèi)型(struct) | 共用體類(lèi)型(union) | 函數(shù)類(lèi)型 |
數(shù)據(jù)以補(bǔ)碼的形式存儲(chǔ)再存儲(chǔ)空間中。
補(bǔ)碼求法:正·數(shù)的補(bǔ)碼就是其二進(jìn)制碼如5的補(bǔ)碼是0000 0000 0000 0101,負(fù)數(shù)的補(bǔ)碼是其正數(shù)的二進(jìn)制碼取反,再加1,如-5,它的正數(shù)是5,5的二進(jìn)制碼是0000 0000 0000 0101,取反為1111 1111 1111 1010,再加1,得-5的補(bǔ)碼是1111 1111 1111 1011。
3.2 運(yùn)算符和表達(dá)式
經(jīng);祀鹊倪\(yùn)算符有:/(除法運(yùn)算符)、%(求余運(yùn)算符)、++和--(自增和自減運(yùn)算符),例如++i(--i),它們?cè)谑褂胕之前,先使i的值加(減)1;i++(i--),它們?cè)谑褂胕之后,使i的值加(減)1。
強(qiáng)制類(lèi)型轉(zhuǎn)換符:使用強(qiáng)制類(lèi)型轉(zhuǎn)換符可以使一個(gè)表達(dá)式轉(zhuǎn)換成所需的類(lèi)型,一般形式如:(類(lèi)型名)(表達(dá)式),例如(double)a,(float)(5%3)將5%3的值轉(zhuǎn)換為float類(lèi)型。
需要注意的運(yùn)算符:= 賦值運(yùn)算符、== 等于運(yùn)算符、?:條件運(yùn)算符、(sizeof)求字節(jié)數(shù)運(yùn)算符、,->成員運(yùn)算符、<<左移運(yùn)算符、復(fù)合的賦值運(yùn)算符,例如j×=y+8,等價(jià)于j=j×(y+8)等。
左移運(yùn)算符(<<)
將一個(gè)運(yùn)算對(duì)象的各二進(jìn)制位全部左移若干位(左邊的二進(jìn)制位丟棄,右邊補(bǔ)0)。
例:a = a << 2 將a的二進(jìn)制位左移2位,右補(bǔ)0,
左移1位后a = a * 2;
若左移時(shí)舍棄的高位不包含1,則每左移一位,相當(dāng)于該數(shù)乘以2。
右移運(yùn)算符(>>)
將一個(gè)數(shù)的各二進(jìn)制位全部右移若干位,正數(shù)左補(bǔ)0,負(fù)數(shù)左補(bǔ)1,右邊丟棄。
操作數(shù)每右移一位,相當(dāng)于該數(shù)除以2。
例如:a = a >> 2 將a的二進(jìn)制位右移2位,
左補(bǔ)0 or 補(bǔ)1 得看被移數(shù)是正還是負(fù)。
注意: 當(dāng)一個(gè)占多字節(jié)的整型數(shù)據(jù),給一個(gè)占少字節(jié)的整型變量或字符變量賦值時(shí),只能將它的低字節(jié)原封不動(dòng)的送到被賦值變量,例如:a占4個(gè)字節(jié),b占2個(gè)字節(jié),當(dāng)b=a時(shí),只能把a(bǔ)的2位低字節(jié)賦給b。
3.3 數(shù)據(jù)的輸入輸出
3.3.1數(shù)據(jù)的輸入
通過(guò)標(biāo)準(zhǔn)的輸入函數(shù)完成,系統(tǒng)函數(shù)庫(kù)中標(biāo)準(zhǔn)的輸入函數(shù)有:scanf(格式輸入)、gets(輸入字符串)、getchar(輸入字符)。
scanf函數(shù)的一般形式:scanf(格式控制,地址列表),如scanf(“a=%f,b=%f”,&a,&b);
gets函數(shù)的一般形式:gets(地址),如int a[10],gets(a),從鍵盤(pán)輸入字符串,送到數(shù)組a中。
getchar函數(shù)的一般形式:a=getchar(),從鍵盤(pán)輸入一個(gè)字符,送到字符變量a。
3.3.2數(shù)據(jù)的輸出
標(biāo)準(zhǔn)輸出函數(shù)有:printf(格式輸出)、puts(輸出字符串)、putchar(輸出字符)
printf函數(shù)的一般格式:printf(格式控制,輸出列表),如printf(“a=%d,ch[]=%s”,a,ch);a是變量名,ch是數(shù)組ch[]的數(shù)組名。
puts函數(shù)的一般格式:puts(地址),如int a[10],puts(a),這地址是指要輸出數(shù)組的地址。
putchar函數(shù)的一般格式:putchar(字符),如char c=‘a(chǎn)’,putchar(c),輸出字符變量c的值。
printf 的格式字符(scanf的格式基本一樣)
d,i | o | x,X | u | c | s | f | e,E | g,G |
十進(jìn)制輸出整數(shù) | 八進(jìn)制 | 十六進(jìn)制 | 無(wú)符號(hào)十進(jìn)制輸出整數(shù) | 字符輸出 | 字符串輸出 | 小數(shù)形式輸出單、雙精度數(shù) | 指數(shù)形式輸出實(shí)數(shù) | 選用%f或%e中輸出寬度較短的一種格式 |
printf 和scanf 的格式附加字符
printf | printf | printf | scanf | scanf |
l | m(代表一個(gè)正整數(shù)) | n(代表一個(gè)正整數(shù)) | l | h |
用于長(zhǎng)整型整數(shù),可加于d,0,x,u前面 | 數(shù)據(jù)最小寬度 | 對(duì)實(shí)數(shù)時(shí),表示輸出n個(gè)小數(shù),字符串時(shí),表示截取字符個(gè)數(shù) | 用于輸入長(zhǎng)整型數(shù)據(jù),如%ld,%lx,%lo | 用于輸入短整型數(shù)據(jù),如%hd,%ho,%hx |
第4章 選擇結(jié)構(gòu)程序設(shè)計(jì)
4.1 if條件選擇
if語(yǔ)句的一般形式是:if(表達(dá)式)語(yǔ)句1,如if(a+b>10) printf("yes");表達(dá)的意思是,如果a+b的值大于10,則執(zhí)行printf函數(shù)輸出yes。通過(guò)判斷if表達(dá)式的真假,來(lái)判斷是否執(zhí)行語(yǔ)句1。
if語(yǔ)句一般與else語(yǔ)句一起使用,以實(shí)現(xiàn)更多功能,例如
if(表達(dá)式) 語(yǔ)句1;
else 語(yǔ)句;
例如 if(a>b) a=b;
else b=a;
這里表示如果a>b,則a=b,否則b=a;
if和else還可以嵌套使用,例如
if(number>50) a=1; else if(number>40) a=2; else if(number>30) a=3; else if(number>20) a=4; else a=5;
注意 : 關(guān)系運(yùn)算符的優(yōu)先級(jí)低于算術(shù)運(yùn)算符
關(guān)系運(yùn)算符的優(yōu)先級(jí)高于賦值運(yùn)算符
! | && | || |
邏輯非 | 邏輯與 | 邏輯或 |
。ㄟ壿嫹牵,如果a為真,則!a為假,如果a為假,則!a為真。
優(yōu)先級(jí):。ǚ牵>&&(與)>||(或)
優(yōu)先級(jí):。ǚ牵>算術(shù)運(yùn)算符>關(guān)系運(yùn)算符>&&(與)>||(或)>賦值運(yùn)算符
4.2 switch多分枝選擇
switch語(yǔ)句是多分枝選擇語(yǔ)句,switch的一般形式如下:
switch(表達(dá)式) { case 常量1 :語(yǔ)句1 case 常量2 :語(yǔ)句2 case 常量n :語(yǔ)句n default :語(yǔ)句n+1 }
注意:switch后面括號(hào)內(nèi)的“表達(dá)式”,其值的類(lèi)型應(yīng)為整數(shù)類(lèi)型(字符型)
在執(zhí)行switch語(yǔ)句時(shí),根據(jù)switch表達(dá)式的值找到相應(yīng)的入口標(biāo)號(hào),然后從相應(yīng)的case中執(zhí)行語(yǔ)句,在執(zhí)行完入口標(biāo)號(hào)的case語(yǔ)句后,程序會(huì)繼續(xù)往下執(zhí)行下面的case標(biāo)號(hào)的語(yǔ)句,直到switch程序結(jié)束,所以一般情況下需要在case子句后面,應(yīng)用break語(yǔ)句,使程序跳出switch結(jié)構(gòu)。如果沒(méi)有與switch表達(dá)式相匹配的case常量,流程會(huì)轉(zhuǎn)去執(zhí)行default標(biāo)號(hào)后面的語(yǔ)句。
switch語(yǔ)句使用例子:
#include<stdio.h> int mian() { char ch; int a=0; ch=getchar(); switch(ch) { case 'a' : printf("a");break; case 'b' : printf("b");break; case 'c' : printf("c");break; default : printf("d"); } return 0; }
第5章 循環(huán)結(jié)構(gòu)程序設(shè)計(jì)
5.1 for循環(huán)結(jié)構(gòu)
for循環(huán)的一般形式: for(表達(dá)式1;表達(dá)式2;表達(dá)式3) 語(yǔ)句,例如
for(i=1;i<10;i++)
sum=sum+i;
其中表達(dá)式1可以省略,如for(;i<10;i++),但分號(hào)不能省。但是當(dāng)表達(dá)式2省略時(shí),表示無(wú)限循環(huán)。
for循環(huán)實(shí)現(xiàn)冒泡算法:
void xunhuan(int r[],int n) { int i,j,temp=0; for(i=1;i<n;i++) for(j=1;j<=n-i;j++) if(r[j]>r[j+1]) { temp=r[j]; r[j]=r[j+1]; r[j+1]=temp; } }
5.2 while循環(huán)結(jié)構(gòu)
while實(shí)現(xiàn)循環(huán)有兩種方式,一種是使用do.....while結(jié)構(gòu),另一種是使用while結(jié)構(gòu)。
do.....while語(yǔ)句的一般形式為:
do
{語(yǔ)句}
while(表達(dá)式);
例如:
#include<stdio.h> int main() { int i=1,sum=0; do { sum=sum+i; i++; }while(i<=100); printf("sum=%d\n",sum); return 0; }
while語(yǔ)句的一般形式為:
while(表達(dá)式)語(yǔ)句;
例如,使用while和for語(yǔ)句實(shí)現(xiàn)的冒泡算法
#include<stdio.h> int main() { int i=0,j=0,flag=1,temp=0; int a[5]={10,2,57,7,98}; while((i<4)&&flag) { flag=0 for(j=0;j<4-i;j++) if(a[j]>a[j+1]) { temp=a[j]; a[j]=a[j+1]; a[j+1]=temp; flag=1; } i++; } for{i=0;i<4;i++} printf("%d ",a[i]); return 0; }
注意:break語(yǔ)句和continue語(yǔ)句的區(qū)別是,在執(zhí)行for或while循環(huán)語(yǔ)句時(shí),通過(guò)break語(yǔ)句可以提前終止循環(huán),跳出循環(huán)體。而continue語(yǔ)句只是提前結(jié)束本次循環(huán),而不是終止整個(gè)循環(huán),然后繼續(xù)執(zhí)行下一次循環(huán)。
第6章 數(shù)組
6.1 一維數(shù)組
數(shù)組是一組有序數(shù)據(jù)的集合,數(shù)組中的每個(gè)元素都是同一種類(lèi)型。通過(guò)數(shù)組可以存儲(chǔ)一組數(shù)據(jù)或多組數(shù)據(jù)。定義一維數(shù)組的一般形式為:類(lèi)型符 數(shù)組名 [常量表達(dá)式];例如int a[10],定義了一個(gè)名為a的數(shù)組,它包含10個(gè)元素,它第一個(gè)元素是a[0]。當(dāng)數(shù)組常量表達(dá)式為空時(shí),數(shù)組的長(zhǎng)度由初始化列表中元素的個(gè)數(shù)決定,例如int a[ ]={1,2},這時(shí)a數(shù)組的長(zhǎng)度為2。
數(shù)組的常量表達(dá)式可以是常量和符號(hào)常量(#define P1 3.12,其中P1代表符號(hào)常量),但不能是變量。如果數(shù)組是在被調(diào)用的函數(shù)里面(不包括主函數(shù))定義的數(shù)組,其長(zhǎng)度可以是變量或非常量表達(dá)式。例如:
void fun(int n) { int a[2*n];//合法,n的值從實(shí)參傳來(lái) . . . }
這種情況稱(chēng)為“可變長(zhǎng)數(shù)組”,允許每次調(diào)用fun函數(shù)時(shí),n有不同的值,但在執(zhí)行fun函數(shù)時(shí),n的值是不變的。如果指定fun函數(shù)中的a數(shù)組為靜態(tài)(static)存儲(chǔ)方式,則不能用“可變長(zhǎng)數(shù)組”,例如:static int a[2*n];這是不合法的,即可變長(zhǎng)數(shù)組不能定義為靜態(tài)存儲(chǔ)方式。
一維數(shù)組的數(shù)組名代表數(shù)組的起始地址。一維數(shù)組的初始化可以用“初始化列表”或給數(shù)組元素逐個(gè)賦值,其中“初始化列表”的方式,如:int a[10]={0,1,2,3,4};,把初始化列表的數(shù)值,逐個(gè)賦給a數(shù)組的前5個(gè)元素,系統(tǒng)會(huì)自動(dòng)給后面5個(gè)元素賦初值為0。給數(shù)組元素賦值,如a[0]=1;
數(shù)組中的元素引用,可以通過(guò)數(shù)組名加下標(biāo)的方式,一般形式為:數(shù)組名[下標(biāo)],下標(biāo)可以是整型常量、整型的符號(hào)常量、整型表達(dá)式或者是整型變量,如int i=1; b=a[i]。
數(shù)組實(shí)現(xiàn)的冒泡算法
#include<stdio.h> int main() { int a[10]; int i,j,t; printf("input 10 numbers :\n"); for(i=0;i<10;i++) scanf("%d",&a[i]); printf("\n"); for(i=0;i<9:i++) for(j=0;j<9-i;j++) if(a[j]>a[j+1]) {t=a[j];a[j]=a[j+1];a[j+1]=t;} printf("the sorted numbers :\n"); for(j=0;j<10;j++) { printf("%d",a[j]); } printf("\n"); return 0; }
6.2 二維數(shù)組
二維數(shù)組定義的一般形式:類(lèi)型符 數(shù)組名[常量表達(dá)式1][常量表達(dá)式2];
例如:float a[3][4],定義一個(gè)3×4(3行4列)的數(shù)組a,常量表達(dá)式1表示數(shù)組的行數(shù),常量表達(dá)式2表示數(shù)組的列數(shù)。
二維數(shù)組可以看成一個(gè)特殊的一維數(shù)組,它的元素又是一個(gè)一維數(shù)組,例如,把a(bǔ)看為一維數(shù)組,它有3個(gè)元素:a[0],a[1],a[2],每個(gè)元素又是一個(gè)包含4個(gè)元素的一維數(shù)組,如a[0]包含:a[0][0],a[0][1],a[0][2],a[0][3]。a[0]、a[1]、a[2]可以看作三個(gè)一維數(shù)組名。二維數(shù)組元素的存放是按行存放的,先放第一行,再放第二行。在內(nèi)存中二維數(shù)組的各元素是連續(xù)存放的,不是二維的,是線性的。
二維數(shù)組初始化和引用數(shù)組元素
二維數(shù)組的初始化形式:
1、給二維數(shù)組部分元素賦初值:如
int a[3][4]={ {1,2},[5],{9}}; 表示給第一行的1、2列分別賦值1和2,給第二、三行的第1列,分別賦值5和9,其余元素值自動(dòng)為0;
2、把所有數(shù)據(jù)寫(xiě)在一個(gè)花括號(hào)中,按數(shù)組元素在內(nèi)存中的排列順序?qū)Ω髟刭x初值。
如int a[2][2]={1,2,3,4};
3、分行給二維數(shù)組賦初值。
例如:int a[2][2]={ {1,2},{3,4}};
4、如果給數(shù)組全部元素賦初值(即提供全部初始化數(shù)據(jù)),定義二維數(shù)組時(shí),第1維(行)的長(zhǎng)度可以不指定,但第2維(列)的長(zhǎng)度不能省略。
如:a[ ][2]={1,2,3,4}; 定義一個(gè)2×2的數(shù)組a
二維數(shù)組元素的引用:二維數(shù)組元素表示形式,數(shù)組名[下標(biāo)1][下標(biāo)2],下標(biāo)應(yīng)是整型表達(dá)式,如 a[0][1]=1;b=a[0][1]; 把數(shù)組a的第0行,第1列的元素賦值給b,b=1。
6.3 字符數(shù)組
字符數(shù)組的一般形式與一維數(shù)組和二維數(shù)組的一樣的,只是數(shù)據(jù)類(lèi)型不同,例如,char a[2]={'I','k'};char a[ ]={I','k'};,這兩個(gè)數(shù)組的長(zhǎng)度都是一樣的。char a[2][2]={ {'b','a'},{'c','d'}}; char a[][2]={ {'b','a'},{'d'}};,當(dāng)字符數(shù)組初值的個(gè)數(shù)小于數(shù)組長(zhǎng)度時(shí),只將這些字符賦給數(shù)組中前面的元素,其余的元素自動(dòng)定為空字符(即‘\0’)。
在C系統(tǒng)中,使用字符數(shù)組存儲(chǔ)字符串常量時(shí)會(huì)自動(dòng)加一個(gè)'\0'作為結(jié)束符,C語(yǔ)言規(guī)定了'\0'作為字符串結(jié)束標(biāo)志,'\0'代表ASCII碼為0的字符。例如char c[ ]={"C program"},字符串是存放在一維數(shù)組中的,在數(shù)組中它占10個(gè)字節(jié),最后一個(gè)字節(jié)'\0'是由系統(tǒng)自動(dòng)加上的。
注意:char c[ ]={"Cab"};不等于char c[3]={‘C’,'a','b'};前式長(zhǎng)度為4,后式長(zhǎng)度為3。
字符串的輸入輸出
字符串輸入 char c[10]; 方式1 使用格式輸入函數(shù)scanf() scanf("%s",c) ; //c是數(shù)組名,代表數(shù)組c的地址 方式2 使用gets()輸入字符串函數(shù) gets(c); //c是數(shù)組名,代表數(shù)組c的地址 字符串輸出 char c[10]; 方式1 使用格式輸出函數(shù)printf() printf("%s",c) ; //c是數(shù)組名,代表數(shù)組c的地址 方式2 使用puts()輸出字符串函數(shù) puts(c); //c是數(shù)組名,代表數(shù)組c的地址
字符串處理函數(shù),使用時(shí)需要加頭文件#include<string.h>
1、gets(字符數(shù)組) 輸入字符串函數(shù) gets(c); //c是數(shù)組名,代表數(shù)組c的地址
2、puts(字符數(shù)組) 輸出字符串函數(shù) puts(c); //c是數(shù)組名,代表數(shù)組c的地址
3、strcat函數(shù)——字符串鏈接函數(shù) strcat(字符數(shù)組1,字符數(shù)組2)
char str1[30]={"ABC"}; char str2[]={"DE"}; printf("%s",strcat(str1,str2)); 輸出:ABCDE (1)字符數(shù)組1必須足夠大,以便容納連接后的新字符串。如果字符數(shù)組1不夠大,會(huì)出現(xiàn)問(wèn)題。 (2)連接前兩個(gè)字符串的后面都有'\0',連接時(shí)將字符串1后面的'\0'取消,只在新字符串最后保留'\0'。 (3)連接的新串放在字符數(shù)組1中,函數(shù)最后返回的是字符數(shù)組1的地址。
4、strcpy和strncpy函數(shù)——字符串復(fù)制函數(shù) strcpy(字符數(shù)組1,字符串2)
char str1[10],str2[ ]={"china"}; strcpy(str1,str2);
執(zhí)行后str1的狀態(tài)如下:
c | h | i | n | a | \0 | \0 | \0 | \0 | \0 |
說(shuō)明:
(1)、字符數(shù)組1的長(zhǎng)度不應(yīng)小于字符串2。
(2)、字符數(shù)組1必須寫(xiě)成數(shù)組形式,字符串2可以是字符數(shù)組名,也可以是字符串常量。
(3)、如果字符數(shù)組1沒(méi)被賦初值,它各字節(jié)中的內(nèi)容是未知的,復(fù)制時(shí)將str2中的字符串和其后的‘\0’一起復(fù)制到字符數(shù)組1中,取代其前6個(gè)字符,str1的最后4個(gè)字符并不一定為'\0',而是其原有的最后4個(gè)字節(jié)的內(nèi)容。
(4)、不能使用賦值語(yǔ)句直接把字符串常量或字符數(shù)組給一個(gè)字符數(shù)組。
(5)、可以使用strncpy函數(shù)將字符串2中的前n個(gè)字符復(fù)制到字符數(shù)組1中,但n不應(yīng)多于str1中原有的字符(不包括'\0')。
5、strcmp函數(shù)——字符串比較函數(shù) strcmp(字符串1,字符串2)
strcmp(str1,str2); strcmp(str1,"Beijing"); strcmp("China","Korea");
說(shuō)明
(1)比較規(guī)則,兩個(gè)字符串自左至右逐個(gè)字符相比較(按ASCII碼值大小比較),直至出現(xiàn)不同字符或遇到'\0'為止。
(2)全部字符相同,則兩個(gè)字符串相等;
(3)若出現(xiàn)不同的字符,則以第1對(duì)不相同的字符的比較結(jié)果為準(zhǔn)。
(4)字符串1=字符串2,則函數(shù)值為0;字符串1>字符串2,則函數(shù)值為一個(gè)正整數(shù);字符串1<字符串2,則函數(shù)值為一個(gè)負(fù)整數(shù)。
6、 strlen函數(shù)——測(cè)字符串長(zhǎng)度的函數(shù) strlen(字符數(shù)組)
函數(shù)的值為字符串中的實(shí)際長(zhǎng)度(不包括'\0'在內(nèi)),例如
char str[10]={"china"}; printf("%d",strlen(str)); 輸出:5
7、strlwr函數(shù)——轉(zhuǎn)換為小寫(xiě)函數(shù) strlwr(字符串)
8、strupr函數(shù)——轉(zhuǎn)換為大寫(xiě)函數(shù) strupr(字符串)
第7章 函數(shù)的使用
7.1 為什么使用函數(shù)
在編寫(xiě)一個(gè)程序時(shí),往往不是只實(shí)現(xiàn)一個(gè)或兩個(gè)功能,當(dāng)程序功能多且復(fù)雜時(shí),如果還是把功能的實(shí)現(xiàn)放在主函數(shù)里,會(huì)使得主程序變得復(fù)雜,使思路變得復(fù)雜,不利于查看和檢查,而且有時(shí)一個(gè)程序需要多人一起完成,如果把系統(tǒng)功能實(shí)現(xiàn)放在主程序中,這樣會(huì)不利于團(tuán)隊(duì)的合作。通過(guò)函數(shù)可以把程序的各功能分別在子函數(shù)中實(shí)現(xiàn),然后通過(guò)主函數(shù)調(diào)用各子函數(shù)就可以實(shí)現(xiàn)系統(tǒng)的功能,在團(tuán)隊(duì)合作中,每個(gè)人只需把他需要完成的功能寫(xiě)在子函數(shù)中,最后通過(guò)主函數(shù)調(diào)用就能實(shí)現(xiàn)系統(tǒng)功能。使用函數(shù)可以大大簡(jiǎn)化程序功能的實(shí)現(xiàn),有助理清思路,各功能可以互不干預(yù)。
7.2 函數(shù)的定義
定義無(wú)參函數(shù):
類(lèi)型名 函數(shù)名() 或 類(lèi)型名 函數(shù)名(void)
{ {
函數(shù)體 函數(shù)體
} }
定義有參函數(shù):
類(lèi)型名 函數(shù)名(形式參數(shù)列表)
{
函數(shù)體
}
int max(int x,int y) { int z; //聲明部分 z=x>y?x:y; //執(zhí)行語(yǔ)句部分 return(z); }
函數(shù)體包括聲明部分和語(yǔ)句部分。定義函數(shù)時(shí)的類(lèi)型名是指定函數(shù)返回值的類(lèi)型。
定義空函數(shù):類(lèi)型名 函數(shù)名() { } 例如void fun() { }
7.3 函數(shù)的調(diào)用方式
如果函數(shù)在主函數(shù)后定義,在函數(shù)調(diào)用前,需要對(duì)函數(shù)進(jìn)行聲明,聲明方式是:類(lèi)型名 函數(shù)名();例如:int max(int x,int y);,根據(jù)函數(shù)在程序中的位置和形式,函數(shù)調(diào)用分三種形式:
(1)函數(shù)調(diào)用語(yǔ)句 例如:fun();
(2)函數(shù)表達(dá)式 例如:c=2*max(a,b);
(3)函數(shù)參數(shù) 例如:m=max(a,max(b,c));
函數(shù)調(diào)用時(shí),用到的實(shí)參和形參是直傳遞的,即形參的改變不會(huì)影響到實(shí)參。當(dāng)形參類(lèi)型是指針、數(shù)組、或變量的&引用時(shí),形參的改變才會(huì)影響到實(shí)參。
函數(shù)的嵌套調(diào)用:
函數(shù)的嵌套調(diào)用是指,在主函數(shù)中調(diào)用a函數(shù)(子函數(shù)),然后在a函數(shù)中調(diào)用b函數(shù)(別的子函數(shù)),函數(shù)的執(zhí)行流程是:在主程序中遇到a函數(shù)調(diào)用,則跳到a函數(shù)執(zhí)行,在a函數(shù)遇到b函數(shù)調(diào)用,下一步跳到b函數(shù)執(zhí)行,在b函數(shù)執(zhí)行完后,程序返回a函數(shù)繼續(xù)執(zhí)行,a函數(shù)執(zhí)行完后,程序返回主函數(shù)繼續(xù)執(zhí)行,直到整個(gè)主函數(shù)執(zhí)行完畢。
函數(shù)的遞歸調(diào)用:
在調(diào)用一個(gè)函數(shù)的過(guò)程中又出現(xiàn)直接或間接地調(diào)用本函數(shù)本身,稱(chēng)為函數(shù)的遞歸調(diào)用。
int age(int n) { int c; if(n==1) c=10; else c=age(n-1)+2; return(c); }
7.4 數(shù)組作為函數(shù)參數(shù)
函數(shù)的實(shí)參可以是常量、變量或表達(dá)式,數(shù)組元素當(dāng)實(shí)參與變量相當(dāng),向形參傳遞數(shù)組元素的值,從實(shí)參傳到形參,單向傳遞(值傳遞)。此外,數(shù)組名也可以當(dāng)實(shí)參和形參,傳遞的是數(shù)組第一個(gè)元素的地址(首地址),即實(shí)參和形參數(shù)組的地址相同,它們操作同一片存儲(chǔ)空間,所以當(dāng)形參改變時(shí),實(shí)參也會(huì)跟著改變。
7.5 內(nèi)部函數(shù)和外部函數(shù)
7.5.1 局部變量
局部變量包括:在函數(shù)內(nèi)部定義的變量(包括主函數(shù))、在復(fù)合語(yǔ)句內(nèi)定義的變量、形參也是局部變量。它的作用域是定義函數(shù)內(nèi)部、定義復(fù)合語(yǔ)句內(nèi)部,例如在fun函數(shù)內(nèi)定義的變量,它的作用域是fun函數(shù)。在for循環(huán)里定義的變量,它的作用域是for循環(huán)里面。
7.5.2 全局變量
在函數(shù)之外定義的變量稱(chēng)為外部變量,外部變量是全局變量,它的作用域是從定義變量的位置開(kāi)始到本源文件結(jié)束,全局變量可以為本文件中其他函數(shù)所共用。
當(dāng)定義的全局變量和局部變量同名時(shí),在局部變量的作用域內(nèi),同名的全局變量會(huì)被同名的局部變量所屏蔽。例如在全局變量a=10,局部變量a=5,在局部變量a的作用域內(nèi),b=a,則b的值為5。
變量的存儲(chǔ)方式:動(dòng)態(tài)存儲(chǔ)方式與靜態(tài)存儲(chǔ)方式
靜態(tài)存儲(chǔ)方式:指在程序運(yùn)行期間由系統(tǒng)分配固定的存儲(chǔ)空間的方式。
動(dòng)態(tài)存儲(chǔ)方式:指在程序運(yùn)行期間根據(jù)需要進(jìn)行動(dòng)態(tài)的分配存儲(chǔ)空間的方式。
供用戶(hù)使用的存儲(chǔ)空間分3部分:(1)程序區(qū);(2)靜態(tài)存儲(chǔ)區(qū);(3)動(dòng)態(tài)存儲(chǔ)區(qū)。數(shù)據(jù)分別存儲(chǔ)在靜態(tài)存儲(chǔ)區(qū)和動(dòng)態(tài)存儲(chǔ)區(qū)中,全局變量全部存放在靜態(tài)存儲(chǔ)區(qū),在程序開(kāi)始執(zhí)行時(shí)給全局變量分配存儲(chǔ)區(qū),程序執(zhí)行完畢就釋放。在程序執(zhí)行過(guò)程中它們占據(jù)固定的存儲(chǔ)單元,而不是動(dòng)態(tài)地進(jìn)行分配和釋放。
在動(dòng)態(tài)存儲(chǔ)區(qū)中存放以下數(shù)據(jù):
(1)函數(shù)形式參數(shù)。在調(diào)用函數(shù)時(shí)給形參分配存儲(chǔ)空間。
(2)函數(shù)中定義的沒(méi)有用關(guān)鍵字static聲明的變量,即自動(dòng)變量(auto變量)。
(3)函數(shù)調(diào)用時(shí)的現(xiàn)場(chǎng)保護(hù)和返回地址。
以上這些數(shù)據(jù),在函數(shù)調(diào)用開(kāi)始時(shí)分配動(dòng)態(tài)存儲(chǔ)空間,函數(shù)結(jié)束時(shí)釋放這些空間。在程序執(zhí)行過(guò)程中,這種分配和釋放是動(dòng)態(tài)的。
在c語(yǔ)言中,每個(gè)變量和函數(shù)都有兩個(gè)屬性:數(shù)據(jù)類(lèi)型和數(shù)據(jù)的存儲(chǔ)類(lèi)別。在定義和聲明變量和函數(shù)時(shí),一般應(yīng)同時(shí)指定其數(shù)據(jù)類(lèi)型和存儲(chǔ)類(lèi)別,也可以采用默認(rèn)方式指定(系統(tǒng)自動(dòng)指定為某一種存儲(chǔ)類(lèi)別)。數(shù)據(jù)類(lèi)別指的是:數(shù)據(jù)在內(nèi)存中的存儲(chǔ)方式(靜態(tài)存儲(chǔ)和動(dòng)態(tài)存儲(chǔ))。
C的存儲(chǔ)類(lèi)別包括4種,自動(dòng)的(auto),靜態(tài)的(statis)、寄存器的(register)、外部的(extern)。
1、自動(dòng)變量(auto變量)
函數(shù)中的局部變量,如果不專(zhuān)門(mén)聲明為static(靜態(tài))存儲(chǔ)類(lèi)別,都是動(dòng)態(tài)地分配存儲(chǔ)空間的,數(shù)據(jù)存放在動(dòng)態(tài)存儲(chǔ)區(qū)中。函數(shù)中的形參和函數(shù)中定義的局部變量(包括復(fù)合語(yǔ)句中定義的局部變量)都是自動(dòng)變量(auto變量)。
int fun(int a) { int b=3; //省略auto時(shí),系統(tǒng)隱含指定為“自動(dòng)存儲(chǔ)類(lèi)別(auto)”,b為自動(dòng)變量 auto int c=2; //定義c為自動(dòng)變量 . . }
當(dāng)定義的自動(dòng)變量不賦初值時(shí),它的值是未知的。
2、靜態(tài)局部變量(static)
靜態(tài)局部變量屬于靜態(tài)存儲(chǔ)類(lèi)別,存放在靜態(tài)存儲(chǔ)區(qū)內(nèi)分配的單元。對(duì)靜態(tài)局部變量賦初值是在編譯時(shí)完成的(即只賦初值一次),在以后函數(shù)調(diào)用時(shí),不再重新賦初值,而是保留上一次調(diào)用函數(shù)結(jié)束時(shí)的值。例如
int a() { static int i=1; printf{"%d",i}; i=i+1; }
第一次調(diào)用a函數(shù)時(shí),i的初值為1,輸出i為1;第二次調(diào)用a函數(shù)輸出的i為2,保留上一次函數(shù)結(jié)束時(shí)的值。
當(dāng)定義的靜態(tài)局部變量不賦初值時(shí),編譯時(shí)自動(dòng)賦初值為0(對(duì)數(shù)值型變量)或'\0'(對(duì)字符變量)
3、寄存器變量(register變量)
寄存器變量存放在CPU中的寄存器中,它不是存放在內(nèi)存中的。由于寄存器變量存放在cpu中的寄存器中,所以數(shù)據(jù)的存取速度遠(yuǎn)高于存放在內(nèi)存中的數(shù)據(jù)的存取。使用寄存器變量可以提高執(zhí)行效率。定義寄存器變量的一般形式:register int f;
4、全局變量(外部變量)
全局變量都是存放在靜態(tài)存儲(chǔ)區(qū)中的。它的作用域一般是從定義全局變量處開(kāi)始,到本程序文件的末尾。當(dāng)定義外部變量的位置,不是位于文件開(kāi)頭時(shí),在外部變量定義處之前的程序是不能引用外部變量的,如果要引用外部變量,需要在引用之前使用關(guān)鍵字extern對(duì)該變量進(jìn)行“外部變量聲明”
把外部變量的作用域擴(kuò)展到其他文件的方式,可以在其他文件中使用extern對(duì)外部變量進(jìn)行聲明。例如
文件file1.c #include<stdio.h> int a; //定義外部變量 int b; //定義外部變量 int main() { . . . } 文件file2.c extern int a; //把文件file1.c中的外部變量a的作用域擴(kuò)展到file2.c中 extern b; //把文件file1.c中的外部變量b的作用域擴(kuò)展到file2.c中 int fun() { . . . }
把外部變量的作用域限定在本文件中,只能被本文件引用,而不能被其他文件引用,可以通過(guò),在定義外部變量時(shí)加一個(gè)statis聲明來(lái)實(shí)現(xiàn)。通過(guò)statis定義的靜態(tài)外部變量只能作用于本文件,當(dāng)其他文件也定義了相同名字的外部變量時(shí),它們之間的互不干預(yù)的。例如
文件file1.c #include<stdio.h> static int a; //定義靜態(tài)外部變量 int main() { . . . }
5、小結(jié)
(1)從作用域角度分,有局部變量和全局變量。它們的存儲(chǔ)類(lèi)別如下:
局部變量 | 自動(dòng)變量,即動(dòng)態(tài)局部變量(離開(kāi)函數(shù),值就消失) |
靜態(tài)局部變量(離開(kāi)函數(shù),值仍然保留) | |
寄存器變量(離開(kāi)函數(shù),值就消失) | |
形式參數(shù)可以定義為自動(dòng)變量或寄存器變量 | |
全局變量 | 靜態(tài)外部變量(只限本文件引用) |
外部變量(即非靜態(tài)的外部變量,允許其他文件引用) |
(2)從變量生存時(shí)間(生存期)來(lái)區(qū)分,有動(dòng)態(tài)存儲(chǔ)和靜態(tài)存儲(chǔ)兩種類(lèi)型。
動(dòng)態(tài)存儲(chǔ) | 自動(dòng)變量(本函數(shù)內(nèi)有效) |
寄存器變量(本函數(shù)內(nèi)有效) | |
形式參數(shù)(本函數(shù)內(nèi)有效) | |
靜態(tài)存儲(chǔ) | 靜態(tài)局部變量(函數(shù)內(nèi)有效) |
靜態(tài)外部變量(本文件內(nèi)有效) | |
外部變量(用extern聲明后,其他文件可引用) |
(3)從變量值存放的位置來(lái)區(qū)分。
內(nèi)存中靜態(tài)存儲(chǔ)區(qū) | 靜態(tài)局部變量 |
靜態(tài)外部變量(函數(shù)外部靜態(tài)變量) | |
外部變量(可為其他文件引用) | |
內(nèi)存中動(dòng)態(tài)存儲(chǔ)區(qū) | 自動(dòng)變量和形式參數(shù) |
CPU中寄存器 | 寄存器變量 |
內(nèi)部函數(shù)
如果一個(gè)函數(shù)只能被本文件中其他函數(shù)所調(diào)用,它稱(chēng)為內(nèi)部函數(shù)(又稱(chēng)靜態(tài)函數(shù),因?yàn)樗褂胹tatic聲明的),它的作用域只局限于所在文件。這樣,在不同文件中即使有同名的內(nèi)部函數(shù),也互不干擾。一般形式:static 類(lèi)型名 函數(shù)名(形參列表),例如static int a(int a){...}
外部函數(shù)
如果在定義函數(shù)時(shí),在函數(shù)首部的最左端加關(guān)鍵字extern,則此函數(shù)是外部函數(shù),可供其他文件調(diào)用。函數(shù)首部可以為:extern int fun(int a,int b)。C語(yǔ)言規(guī)定,如果在定義函數(shù)時(shí)省略extern,則默認(rèn)為外部函數(shù)。
第8章 指針
8.1 什么是指針
指針指的是地址,一個(gè)變量的地址稱(chēng)為該變量的指針。一個(gè)變量專(zhuān)門(mén)用來(lái)存放另一個(gè)變量的地址,稱(chēng)為指針變量。指針變量的值是地址。
8.2 指針變量
存放地址的變量是指針變量,它用來(lái)指向另一個(gè)對(duì)象(如變量、數(shù)組、函數(shù)等)。定義指針變量的一般形式:類(lèi)型名 *指針變量名;如int *a;char *b;定義了指向整型變量的指針變量a和定義了指向字符變量的指針變量b;
指針變量的初始化,可以在定義的同時(shí)初始化,也可以在定義后初始化,例如:
int a=0; int *b=a; //定義指針變量時(shí)初始化 int *c; c=&a; //定義指針變量后初始化,意思是把a(bǔ)的地址賦值給指針變量c,指針變量c指向變量a 錯(cuò)誤賦值方式:int *d=&a; //錯(cuò)誤,*d不是指針變量,d才是指針變量, 所以應(yīng)該改為int *d=a;
一個(gè)變量的指針的含義包括兩方面:一是以存儲(chǔ)單元編號(hào)表示的地址,一是它指向的存儲(chǔ)單元的數(shù)據(jù)類(lèi)型。
8.3 指針的使用方式
8.3.1指針變量的使用
當(dāng)指針變量指向一個(gè)變量時(shí),那么指針變量就存儲(chǔ)著所指向變量的地址,通過(guò)對(duì)指針變量的使用可以實(shí)現(xiàn)它所指向變量的功能。例如
int a=12; int *put=a; //定義指向變量a的指針變量put printf("a=%d ",a); printf("a=%d",*put); 輸出指針變量put所指向的變量的值 結(jié)果:a=12 a=12
指針變量的使用例子:
輸入兩個(gè)數(shù),按先大后小輸出 #include<stdio.h> int main() { int *p1,*p2,*p,a,b; printf("please enter two integer numbers:"); scanf("%d,%d",&a,&b); p1=&a; p2=&b; if(a<b) {p=p1;p1=p2;p2=p;} printf("a=%d,b=%d\n",a,b); printf("max=%d,min=%d\n",*p1,*p2); return 0; } 結(jié)果:please enter two integer numbers:5,9 a=9,b=5 max=9,min=5
8.3.2 指針變量作為函數(shù)參數(shù)
指針變量作為函數(shù)參數(shù),例如:
#include<stdio.h> int mian() { int fun(int *a); //聲明函數(shù)fun int a=8; int *b=a; fun(&a); fun(b); return 0; } int fun(int *a); { printf("%d ",*a); } 運(yùn)行結(jié)果:8 8
當(dāng)指針變量作為形參時(shí),因?yàn)樾螀⒑蛯?shí)參所操作的存儲(chǔ)單元是同一個(gè)的(它們指向同一個(gè)存儲(chǔ)單元),所以形參值的修改也會(huì)導(dǎo)致實(shí)參值的修改。
8.3.3 通過(guò)指針引用數(shù)組
所謂數(shù)組元素的指針就是數(shù)組元素的地址,可以用一個(gè)指針變量指向一個(gè)數(shù)組元素,例如:
int a[5]={1,2,3,4,5}; int *p; p=&a[0]; 使指針變量p指向a數(shù)組的第0號(hào)元素。
在引用數(shù)組元素時(shí)指針的運(yùn)算。因?yàn)橹羔樀闹凳菙?shù)組元素的地址,當(dāng)指針p指向數(shù)組中的一個(gè)元素時(shí),則p+1指向同一數(shù)組中下一個(gè)元素,p-1指向同一數(shù)組中的上一個(gè)元素。注意:執(zhí)行p+1時(shí),并不是將p的值(地址)簡(jiǎn)單的加1,而是加上一個(gè)數(shù)組元素所占用的字節(jié)數(shù)。例如,數(shù)組元素是float型,每個(gè)元素占4個(gè)字節(jié),則p+1意味著是p的值(地址)加4個(gè)字節(jié)。
通過(guò)指針引用數(shù)組元素
指針?lè)ǎ喝?*(a+i)或*(p+i),其中a是數(shù)組名,p是指向數(shù)組元素的指針變量,其初值p=a。
通過(guò)數(shù)組名計(jì)算數(shù)組元素地址,找出元素的值。例如:
#include<stdio.h> int main() { int a[10]; int i; printf("please enter 10 integer numbers:"); for(i=0;i<10;i++) scanf("%d",&a[i]); for(i=0;i<10;i++) printf("%d ",*(a+i)); //通過(guò)數(shù)組名和元素序號(hào)計(jì)算元素地址,再找到該元素 printf("\n"); return 0; } 第10行中(a+i)是a數(shù)組中序號(hào)為i的元素的地址,*(a+i)是該元素的值。
用指針變量指向數(shù)組元素
#include<stdio.h> int main() { int a[10]; int i,*p; printf("please enter 10 integer numbers:"); for(i=0;i<10;i++) scanf("%d",&a[i]); for(p=a;p<(a+10);p++) printf("%d ",*p); //通過(guò)數(shù)組名和元素序號(hào)計(jì)算元素地址,再找到該元素 printf("\n"); return 0; }
注意:*p++,由于++和*同優(yōu)先級(jí),結(jié)合方向?yàn)樽杂蚁蜃?/SPAN>,因此它等價(jià)于*(p++),先引用p的值,實(shí)現(xiàn)*p的運(yùn)算,然后再使p自增1(p+1).
數(shù)組名作為函數(shù)參數(shù):
int main() { void fun(int arr[],int n); //聲明fun函數(shù) int array[10]; . . . fun(array,10); return 0; } void fun(int arr[],int n) { . . . }
變量名和數(shù)組名作為函數(shù)參數(shù)比較:
實(shí)參類(lèi)型 | 變量名 | 數(shù)組名 |
要求形參的類(lèi)型 | 變量名 | 數(shù)組名或指針變量 |
傳遞的信息 | 變量值 | 實(shí)參數(shù)組首元素的地址 |
通過(guò)函數(shù)調(diào)用能否改變實(shí)參的值 | 不能改變實(shí)參變量的值 | 能改變實(shí)參數(shù)組的值 |
通過(guò)指針引用多維數(shù)組,以int a[3][4]為例,a代表首行的首地址,a+1代表序號(hào)為1的行的首地址,a+1指向a[1](代表a數(shù)組的元素,但它又是一維數(shù)組),或者說(shuō)a+1的值是a[1]的首地址。a[0],a[1],a[2]代表一維數(shù)組名,因此a[0]代表一維數(shù)組a[0]的第0列的地址(即&a[0][0])。
a[0]+3代表a[0][3]的地址(&a[0][3]),“a[0]+3中的a[0]代表數(shù)組名(地址)”。
a[0](代表一維數(shù)組a的元素,但它又是一維數(shù)組)和*(a+0)等價(jià),a[ i ]和*(a+i)等價(jià)。因此a[0]+1和*(a+1)+1等價(jià),都是&a[0][1]。進(jìn)一步分析,a[0][1]的值,使用地址法為:*(*(a+0)+1)或*(*a+1)和*(a[0]+1)。
二維數(shù)組名(如a)指向行的。在指向行的指針前加一個(gè)*,就轉(zhuǎn)換為指向列的指針,例如a+1(行指針),第一行的指針;*(a+1)為列指針,第一行第0列的指針。反之在列的指針前加&,就成為指向行的指針,例如&a[0],由于a[0]和*(a+0)等價(jià),因此&a[0]和&*a等價(jià),它是指向第0行的指針。
指向多維數(shù)組元素的指針變量
#include<stdio.h> int main() { int a[3][4]={....}; int *p; for(p=a[0];p<a[0]+12;p++) //a[0]是a[0][0]的地址,指針p指向a[0][0]元素 printf("%4d",*p); //輸出p指的數(shù)組元素的指 return 0; }
定義指向“由n個(gè)元素組成的一維數(shù)組”的指針變量
#include<stdio.h> int main() { int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23}; int (*p)[4],j,i; p=a; printf("please enter row and colum :"); scanf("%d,%d",&i,&j); printf("[%d,%d]=%d\n",i,j,*(*(p+i)+j)); return 0; } 結(jié)果:please enter row and colum:1,2 a[1,2]=13
用指向數(shù)組的指針作函數(shù)參數(shù)
#include<stdio.h> int main() { void a(int *a); void b(int (*b)[4]); int c[3][4]={...}; a(*c); //*c是數(shù)組c的第0行第0列的地址 b(c); //c是數(shù)組c的第0行的地址 return 0 }
8.3.4 通過(guò)指針引用字符串
例子:
#include<stdio.h> int main() { char *string="I love china!"; printf("%s",string); return 0; } 輸出:I love china!
注意:char *string="I love china!"; 等價(jià)于char *string; string="I love china!",把字符串第一個(gè)元素的地址賦值給字符指針變量string。
字符指針作函數(shù)參數(shù),例如: void fun(char *p),調(diào)用時(shí),實(shí)參可以是字符指針變量、字符數(shù)組名。
void fun(char a[ ]),調(diào)用時(shí),實(shí)參可以是字符指針變量、字符數(shù)組名。
用字符指針作函數(shù)參數(shù)時(shí),實(shí)參和形參的類(lèi)型對(duì)應(yīng)關(guān)系如下
實(shí)參 | 形參 | 實(shí)參 | 形參 |
字符數(shù)組名 | 字符數(shù)組名 | 字符指針變量 | 字符指針變量 |
字符數(shù)組名 | 字符指針變量 | 字符指針變量 | 字符數(shù)組名 |
用字符指針變量指向一個(gè)格式字符串,可以用它代替printf函數(shù)中的格式字符串,例如:
char *format; format="a=%d,b=%f\n"; printf(format,a,b); 它相當(dāng)于 printf("a=%d,b=%f\n",a,b); 因此只要改變指針變量format所指的字符串,就可以改變輸入輸出的格式。 這種printf函數(shù)稱(chēng)為“可變格式輸出函數(shù)”
8.3.5 指向函數(shù)的指針(函數(shù)指針變量)
函數(shù)代碼也有存儲(chǔ)空間,這段存儲(chǔ)空間的起始地址稱(chēng)為這個(gè)函數(shù)的指針。定義一個(gè)指針變量指向函數(shù),存放某一函數(shù)的起始地址,因?yàn)榇酥羔樧兞恐赶蛟摵瘮?shù)。這就是指向函數(shù)的指針(函數(shù)指針變量)。函數(shù)指針變量定義方式:類(lèi)型名 (*指針變量名)(函數(shù)參數(shù)列表);例如:int (*p)(int ,int);,定義一個(gè)指向函數(shù)的指針變量p,它可以指向函數(shù)的類(lèi)型為整型且有兩個(gè)整型參數(shù)的函數(shù)。
可以通過(guò)指向函數(shù)的指針(函數(shù)指針變量)調(diào)用函數(shù),例如
int max(int a,int b) {...} int (*p)(int ,int); p=max; 這時(shí)調(diào)用函數(shù):max(1,2);等價(jià)于(*p)(1,2);
指向函數(shù)的指針變量可以作為函數(shù)參數(shù)。例如
void fun(int (*a)(int)) {...} int flie1(int a) {...} int (*b)(int); b=flie1; //指向flie1函數(shù) fun(b); //指向函數(shù)的指針變量作實(shí)參 fun(flie1); //函數(shù)名作實(shí)參,函數(shù)名代表該函數(shù)存儲(chǔ)空間的起始地址
8.3.6返回指針值的函數(shù)
定義返回指針值的函數(shù)的一般形式:類(lèi)型名 *函數(shù)名(參數(shù)列表),
例如 int *fun(int n){...},
int *fun(int n) { int *p; n=n+1; p=n; return(p); //返回指針變量p所指的地址 }
8.3.7 指針數(shù)組
定義一維指針數(shù)組的一般形式:類(lèi)型名 *數(shù)組名[數(shù)組長(zhǎng)度],例如int *p[5],char *name[ ]={"abc","bcd"};
指向指針數(shù)據(jù)的指針變量的定義為 :類(lèi)型名 **指針名,如char **p,p=name,其中name是指針數(shù)組的數(shù)組名,*p代表指針數(shù)組中存儲(chǔ)的指針,**p代表指針數(shù)組中存儲(chǔ)的指針?biāo)傅膯卧闹怠?/P>
指針數(shù)組作main函數(shù)的形參:int main(int argc,char *argv[ ]),其中argc,argv,它們是程序的命令行參數(shù)(這是在系統(tǒng)操作命令下完成),argc是參數(shù)的個(gè)數(shù)。命令行的一般形式:命令名 參數(shù)1 參數(shù)2 ....參數(shù)n,其中命令名是可執(zhí)行文件名,如,可執(zhí)行文件flie1.exe,現(xiàn)想將兩個(gè)字符串“china”,“beijing”作為傳送給mian函數(shù)的參數(shù),命令行可寫(xiě)為 flie1 china beijing,這時(shí)argc的值為3,參數(shù)的個(gè)數(shù)為3,argv[0]指向flie1字符串。
8.3.8 動(dòng)態(tài)內(nèi)存分配與指向它的指針變量
內(nèi)存中的動(dòng)態(tài)存儲(chǔ)區(qū)也稱(chēng)之為"棧區(qū)"。在C語(yǔ)言中還允許建立內(nèi)存動(dòng)態(tài)分配區(qū)域,以存放一些臨時(shí)用的數(shù)據(jù),這些數(shù)據(jù)不必在程序的聲明部分定義,可以隨時(shí)開(kāi)辟和關(guān)閉,這些數(shù)據(jù)是臨時(shí)存放在一個(gè)特別的自由存儲(chǔ)區(qū),稱(chēng)之為“堆(heap)區(qū)”
對(duì)內(nèi)存的動(dòng)態(tài)分配是通過(guò)系統(tǒng)提供的庫(kù)函數(shù)來(lái)實(shí)現(xiàn)的,主要有malloc,calloc,free,realloc這4個(gè)函數(shù),在使用這些函數(shù)時(shí),需要添加頭文件stdlib.h。
malloc函數(shù),其函數(shù)原型為:void *malloc(unsigned int size),其作用是在內(nèi)存的動(dòng)態(tài)存儲(chǔ)區(qū)中分配一個(gè)長(zhǎng)度為size的連續(xù)空間,形參size是無(wú)符號(hào)整型,不允許有負(fù)數(shù),該函數(shù)的返回值是所分配的第一個(gè)字節(jié)的地址。注意,指針的基類(lèi)型為void,即不指向任何類(lèi)型的數(shù)據(jù),只提供地址。如果該函數(shù)未能成功執(zhí)行(例如內(nèi)存空間不足),則返回空指針(NULL)。
calloc函數(shù),其函數(shù)原型為:void *calloc(unsigned n,unsigned size),其作用是在內(nèi)存的動(dòng)態(tài)存儲(chǔ)區(qū)中分配n個(gè)長(zhǎng)度為size的連續(xù)空間,這空間一般比較大,足可以保存一個(gè)數(shù)組?梢允褂胏alloc為一維數(shù)組開(kāi)辟動(dòng)態(tài)存儲(chǔ)空間,n代表數(shù)組元素個(gè)數(shù),每個(gè)元素的長(zhǎng)度為size。這是動(dòng)態(tài)數(shù)組,該函數(shù)返回的是所分配域的起始位置的指針,如果分配不成功,則返回NULL。
free函數(shù)(無(wú)返回值),其函數(shù)原型為:void free(void *p),其作用是釋放指針變量p所指向的動(dòng)態(tài)空間,使這部分空間能重新被其他變量使用。p應(yīng)是最近一次調(diào)用calloc和malloc函數(shù)時(shí)得到的函數(shù)返回值。例如free(p)。
realloc函數(shù),其函數(shù)原型為:void *realloc(void *p,unsigned int size);其作用是改變通過(guò)malloc和calloc函數(shù)獲得的動(dòng)態(tài)空間的大小,通過(guò)realloc函數(shù)重新分配。用法說(shuō)明:用realloc函數(shù)將p所指向的動(dòng)態(tài)空間的大小改變?yōu)閟ize,p的值不變。如果重新分配不成功,返回NULL。例如:realloc(p,50);
void 指針類(lèi)型,定義一個(gè)void類(lèi)型的指針變量,它不指向任何類(lèi)型的數(shù)據(jù),它是空類(lèi)型或不指向確定類(lèi)型,例如void *p; p=&a, printf("%d",*p),錯(cuò)誤,因?yàn)閜是無(wú)指向,不能指向a。
指針變量可以有空值,即不指向任何變量,例如p=NULL。
#include<stdio.h> #include<stdlib.h> int main() { void check(int *p); int *p1,i; p1=(int *)malloc(5*sizeof(int)); for(i=0;i<5;i++) scanf("%d",p1+i); check(p1); free(p1); return 0 } void check(int *p) { int i; printf("They are fail:"); for(i=0;i<5;i++) if(p[i]<60) printf("%d",p[i]); printf("\n"); } 結(jié)果: 67 98 59 78 57 They are fail:59 57
有關(guān)指針變量的歸納:
變量定義 | 類(lèi)型表示 | 含義 |
int i; | int | 定義整型變量 |
int *p; | int * | 定義p為指向整型數(shù)據(jù)的指針變量 |
int a[5 ]; | int [5] | 定義整型數(shù)組a,它有5個(gè)元素 |
int *p[4]; | int *[4] | 定義指針數(shù)組p,它由4個(gè)指向整型數(shù)據(jù)的指針元素組成 |
int (*p)[4]; | int (*)[4] | p為指向包含4個(gè)元素的的一維數(shù)組的指針變量 |
int f(); | int () | f為返回整型函數(shù)值的函數(shù) |
int *p(); | int *() | p為返回一個(gè)指針的函數(shù),該指針指向整型數(shù)據(jù) |
int (*p)(); | int (*) | p為指向函數(shù)的的指針變量,該函數(shù)返回一個(gè)整型值 |
int **p; | int ** | p是一個(gè)指針變量,它指向一個(gè)指向整型數(shù)據(jù)的指針變量 |
void *p | void * | p是一個(gè)指針變量,基類(lèi)型為void(空類(lèi)型),不指向具體的對(duì)象 |
第9章 自定義數(shù)據(jù)類(lèi)型
9.1 結(jié)構(gòu)體類(lèi)型
結(jié)構(gòu)體類(lèi)型,是由用戶(hù)根據(jù)自己的需要建立的數(shù)據(jù)類(lèi)型。聲明一個(gè)結(jié)構(gòu)體類(lèi)型的一般形式:struct 結(jié)構(gòu)體名 {成員列表};例如:
struct student { int num; char name[20]; char sex; int ahe; float score; char addr[30]; struct Date birthday; //該成員的數(shù)據(jù)類(lèi)型為Date結(jié)構(gòu)類(lèi)型 };
花括號(hào)內(nèi)是該結(jié)構(gòu)體的成員,成員列表也稱(chēng)為“域表”,每個(gè)成員是結(jié)構(gòu)體中的一個(gè)域。成員名命名規(guī)則與變量名相同。它的成員可以是另一個(gè)結(jié)構(gòu)體類(lèi)型。
定義結(jié)構(gòu)體類(lèi)型變量
在建立結(jié)構(gòu)體類(lèi)型時(shí),它只相當(dāng)于一個(gè)模型,并沒(méi)有定義變量,其中并無(wú)具體數(shù)據(jù),系統(tǒng)不會(huì)對(duì)其分配存儲(chǔ)單元。定義結(jié)構(gòu)體類(lèi)型變量的三種方式:
1、先聲明結(jié)構(gòu)體類(lèi)型,再定義該類(lèi)型的變量 例如:struct student student1;
2、在聲明類(lèi)型的同時(shí)定義變量:例如
struct student { 成員列表 }student1,student2; //定義結(jié)構(gòu)體變量student1和student2
3、不指定類(lèi)型名而直接定義結(jié)構(gòu)體類(lèi)型變量
其一般形式為 struct { 成員列表 }變量名列表;
初始化結(jié)構(gòu)體變量
#include<stdi.h> int main() { struct student { long int num; char name[20]; char sex; }a={10101,"xiaoming",'m'}; //定義結(jié)構(gòu)體變量a并初始化 return 0; } struct student a={10101,"xiaoming",'m'}; //定義結(jié)構(gòu)體變量a并初始化 struct student a={.name="xiaoming"}; //定義結(jié)構(gòu)體變量a,并對(duì)其成員a初始化,其他未被 指定初始化的數(shù)值型成員被系統(tǒng)初始化為0,字符型成員被系統(tǒng)初始化為'\0',指針型成員被系統(tǒng)初始化 為NULL。
引用結(jié)構(gòu)體變量的成員:結(jié)構(gòu)體變量名.成員名 例如studen1.num=10101;
如果成員本身又是結(jié)構(gòu)體類(lèi)型,則要使用若干個(gè)成員運(yùn)算符,一級(jí)一級(jí)地找到最低的一級(jí)的成員。例如,student1.birthday.month(結(jié)構(gòu)體變量student1中的成員birthday中的成員month)
同類(lèi)的結(jié)構(gòu)體變量可以互相賦值,如student1=student2;
可以引用結(jié)構(gòu)體變量成員的地址,也可以引用結(jié)構(gòu)體變量的地址。例如
scanf("%d",&student1.num); printf("%o",&student1); (輸出結(jié)構(gòu)體變量student1的首地址)
結(jié)構(gòu)體數(shù)組
定義結(jié)構(gòu)體數(shù)組和定義一般數(shù)組的方式類(lèi)似,它的一般形式為:結(jié)構(gòu)體類(lèi)型 數(shù)組名[數(shù)組長(zhǎng)度],或struct 結(jié)構(gòu)體名 { 成員列表 } 數(shù)組名[數(shù)組長(zhǎng)度];,它的每個(gè)成員都是結(jié)構(gòu)體類(lèi)型。
對(duì)結(jié)構(gòu)體數(shù)組初始化的形式是在定義數(shù)組后面加上:={ 初值列表 };
例如:struct person leader[3]={ {“Li”,0},{"Zhang",0},{"Sun",0}};
結(jié)構(gòu)體指針
指向結(jié)構(gòu)體變量的指針,稱(chēng)為結(jié)構(gòu)體指針,一個(gè)結(jié)構(gòu)體變量的起始地址就是該結(jié)構(gòu)體變量的指針。指向結(jié)構(gòu)體變量的指針變量既可指向結(jié)構(gòu)體變量,也可指向結(jié)構(gòu)體數(shù)組中的元素。
如果p指向一個(gè)結(jié)構(gòu)體變量stu,以下3種用法等價(jià):
(1) stu.成員名(如stu.num)
(2) (*p).成員名(如(*p).num) //*p表示p指向的結(jié)構(gòu)體變量
(3) p->成員名(如p->num)
(++p)->num //先使p自加1,然后得到p指向的數(shù)組元素中的num成員的值。
結(jié)構(gòu)體變量和結(jié)構(gòu)體變量的指針作函數(shù)參數(shù)
(1) 結(jié)構(gòu)體變量的成員作實(shí)參,用法和普通的變量作實(shí)參一樣。(值傳遞)
(2)結(jié)構(gòu)體變量作實(shí)參。(值傳遞)
(3)用指向結(jié)構(gòu)體變量(或數(shù)組元素)的指針作實(shí)參,將結(jié)構(gòu)體變量的地址傳給形參。
用指針處理鏈表
鏈表是一種常見(jiàn)的重要的數(shù)據(jù)結(jié)構(gòu)。它是動(dòng)態(tài)地進(jìn)行存儲(chǔ)分配的一種結(jié)構(gòu)。鏈表可以根據(jù)需要開(kāi)辟內(nèi)存單元。鏈表有一個(gè)“頭指針”變量head,它存放一個(gè)地址,該地址指向一個(gè)元素。鏈表中每一個(gè)元素稱(chēng)為“結(jié)點(diǎn)”,每個(gè)結(jié)點(diǎn)都應(yīng)包含兩個(gè)部分:(1)用戶(hù)需要用的實(shí)際數(shù)據(jù);(2)下一個(gè)結(jié)點(diǎn)的地址。
鏈表中各元素在內(nèi)存中的地址可以不連續(xù),要找某一元素,可以通過(guò)它的上一個(gè)元素中的地址尋找。如果不提供頭指針(head),則整個(gè)鏈表都無(wú)法訪問(wèn)。通過(guò)結(jié)構(gòu)體變量建立鏈表最合適。例如:
struct student
{int num;
float score;
struct student *next; //next是指針變量,指向結(jié)構(gòu)體變量,鏈表中用來(lái)指向下一個(gè)結(jié)點(diǎn)
};
建立簡(jiǎn)單的靜態(tài)鏈表:
#include<stdio.h> struct student { int num; struct student *next; }; int main() {struct student a,b,c,*head,*p; a.num=1; b.num=2; c.num=3; head=&a; a.next=&b; b.next=&c; c.next=NULL; p=head; do { printf("%d\n",p->num) p=p->next; }while(p!=NULL) } 結(jié)果: 1 2 3
所有結(jié)點(diǎn)都是在程序中定義的,不是臨時(shí)開(kāi)辟的,也不能用完后釋放,這種鏈表稱(chēng)為“靜態(tài)鏈表”。
建立動(dòng)態(tài)鏈表
動(dòng)態(tài)鏈表是指在程序執(zhí)行過(guò)程中從無(wú)到有地建立起一個(gè)鏈表,即一個(gè)一個(gè)地開(kāi)辟結(jié)點(diǎn)和輸入各結(jié)點(diǎn)數(shù)據(jù),并建立起前后相鏈的關(guān)系。
#include<stdio.h> #include<stdlib.h> #define LEN sizeof(struct student) //設(shè)置LEN的長(zhǎng)度 struct student { long num; float score; struct student *next; }; int n; struct student *creat(void) //定義函數(shù),此函數(shù)返回一個(gè)指向鏈表頭的指針 { struct student *head,p1,p2; n=0; p1=p2=(struct student *)malloc(LEN); //開(kāi)辟動(dòng)態(tài)存儲(chǔ)區(qū),把起始地址賦給p1 scanf("%ld,%f",&p1->num,&p1->score); head=NULL; while(p1->num!=0) { n=n+1; if(n==1) head=p1; else p2->next=p1; p2=p1; p1=(struct student *)malloc(LEN); //開(kāi)辟動(dòng)態(tài)存儲(chǔ)區(qū),把起始地址賦給p1 scanf("%ld,%f",&p1->num,&p1->score); } p2-next=NULL; return(head); } int main() { struct student *pt; pt=creat(); //函數(shù)返回鏈表第一個(gè)結(jié)點(diǎn)的地址 printf("\nnum:%ld\nscore:%5.f\n",pt->num,pt->score); //輸出第一個(gè)結(jié)點(diǎn)的成員值 return 0; } 結(jié)果: 1 65 2 50 3 34 0 0 num:1 score:65
9.2 共用體類(lèi)型
共用體結(jié)構(gòu),用同一段內(nèi)存單元存放不同類(lèi)型的變量(存放共用體的成員,但同時(shí)只能放一個(gè),保留最一個(gè)存放的變量)。
定義共用體類(lèi)型變量的一般形式:
union 共用體名 例如 union Data
{成員表列 { int i;
}變量表列 ; char ch;
float f;
}a,b,c;
也可以類(lèi)型聲明和變量定義分開(kāi):例如:
union Data {int i; char ch; float f; }; union Data a,b,c;
共用體類(lèi)型數(shù)據(jù)的特點(diǎn),同一段內(nèi)存可以幾種不同的類(lèi)型成員,但每一瞬間只能存放其中一個(gè)成員,而不是同時(shí)存放幾個(gè)成員。
union Data {int i; char ch; float f; }; union Data a; a.ch='a'; a.f=100.2; a.i=97; //內(nèi)存中最終存儲(chǔ)97 printf("%d",a.i); //輸出97 printf("%c",a.ch); //輸出字符'a',ASCII碼是97 printf("%f",a.f); //輸出實(shí)數(shù)0.0000
9.3 枚舉類(lèi)型
聲明枚舉類(lèi)型的一般形式為:enum[枚舉名] {枚舉元素列表};
定義枚舉類(lèi)型變量:例如:(1)先聲明枚舉類(lèi)型enum Weekdat: enum Weekdat {sun,mon,tue,wed,thu,fir,sat};(2)在定義變量:enum Weekdat workday; workday變量的值只能是枚舉元素列表中的枚舉元素(也稱(chēng)枚舉常量)。枚舉元素列表中的枚舉元素按順序系統(tǒng)默認(rèn)它們的值是0,1,2,3....。即workday=mon;相當(dāng)于workday=1;
用typedef聲明新類(lèi)型名
簡(jiǎn)單地用一個(gè)新的類(lèi)型名代替原有的類(lèi)型名
例如: typedef int Integer;指定用Integer代表int類(lèi)型。這樣 int i;等價(jià)于 Integer i;
通過(guò)typedef可以命名一個(gè)簡(jiǎn)單的類(lèi)型名代替復(fù)雜的類(lèi)型表示方法,例如
sypedef struct { long int num; char name[20]; char sex; }student1; 聲明了一個(gè)新類(lèi)型名student1,代表上面的結(jié)構(gòu)體類(lèi)型。 定義結(jié)構(gòu)體變量: student1 xisi;
命名一個(gè)新的類(lèi)型名代表數(shù)組類(lèi)型,例如typedef int Num[100];//聲明Num為整型數(shù)組類(lèi)型名
Num a;定義a為整型數(shù)組名,它有100個(gè)元素。
命名一個(gè)新的類(lèi)型名代表指針類(lèi)型,例如typedef char *String;//聲明String 為字符指針類(lèi)型
String p,s[10];//定義p為字符指針變量,s為字符指針數(shù)組。一般typedef聲明新的類(lèi)型名的開(kāi)頭用大寫(xiě)。
命名一個(gè)新的類(lèi)型名代表指向函數(shù)的指針類(lèi)型,typedef int (*Pointer)(); //聲明Pointer為指向函數(shù)的指針類(lèi)型,該函數(shù)的返回整型。Pointer p1,p2; //p1,p2為Pointer類(lèi)型的指針變量。
第10章 對(duì)文件的輸入輸出(主要討論數(shù)據(jù)文件)
10.1 什么是文件
文件有不同的類(lèi)型,在程序設(shè)計(jì)中,主要用到兩種文件:程序文件和數(shù)據(jù)文件。程序文件:包括源程序文件(后綴.c)、目標(biāo)文件(后綴.obj)、可執(zhí)行文件(后綴.exe)等,這些文件的內(nèi)容是程序代碼。數(shù)據(jù)文件,文件的內(nèi)容不是程序,而是程序運(yùn)行時(shí)讀寫(xiě)的數(shù)據(jù),如在程序運(yùn)行過(guò)程中輸出到磁盤(pán)(或其他設(shè)備)的數(shù)據(jù),或在程序運(yùn)行過(guò)程中供讀入的數(shù)據(jù),如:一批學(xué)生的成績(jī)數(shù)據(jù)。
為了簡(jiǎn)化用戶(hù)對(duì)輸入輸出設(shè)備的操作,使用戶(hù)不必去區(qū)分各種輸入輸出設(shè)備之間的區(qū)別,操作系統(tǒng)把各種設(shè)備都統(tǒng)一作為文件處理。(例如鍵盤(pán)是輸入文件、顯示屏和打印機(jī)是輸出文件)。所謂”文件“一般指存儲(chǔ)在外部介質(zhì)上數(shù)據(jù)的集合(一批數(shù)據(jù)是以文件的形式存放在外部介質(zhì)(如磁盤(pán))上的)。
流,輸入輸出是數(shù)據(jù)傳送的過(guò)程,數(shù)據(jù)如流水一樣從一處流向另一處,因此常將輸入輸出形象地稱(chēng)為流,即數(shù)據(jù)流。
10.2 文件分類(lèi)
一個(gè)文件要有一個(gè)唯一的文件標(biāo)識(shí):包括(1)文件路徑;(2)文件名主干;(3)文件后綴。如:D: \CC \temp \file1.dat
文件的分類(lèi):根據(jù)數(shù)據(jù)的組織形式,數(shù)據(jù)文件可分為:ASCII文件和二進(jìn)制文件。數(shù)據(jù)在內(nèi)存中以二進(jìn)制的形式存儲(chǔ)的,如果不加轉(zhuǎn)換地輸出到外存,就是二進(jìn)制文件,可以認(rèn)為它就是存儲(chǔ)在內(nèi)存的數(shù)據(jù)的映像,所以也稱(chēng)為映像文件。ASCII文件又稱(chēng)為文本文件(text file),每一個(gè)字節(jié)放一個(gè)字符的ASCII代碼。
在磁盤(pán)上,字符一律以ASCII形式存儲(chǔ),數(shù)值型數(shù)據(jù)既可以用ASCII也可以用二進(jìn)制存儲(chǔ)。
10.3 文件的使用
ANSI C標(biāo)準(zhǔn)采用”文件緩沖系統(tǒng)“處理數(shù)據(jù)文件。所謂文件緩沖系統(tǒng)是指系統(tǒng)自動(dòng)地在內(nèi)存區(qū)為程序中每個(gè)正在使用的文件開(kāi)辟一個(gè)文件緩沖區(qū)。文件緩沖區(qū)作用:程序數(shù)據(jù)區(qū)——輸入(或輸出)文件緩沖區(qū)——磁盤(pán)。
文件類(lèi)型指針:FILE *文件名,如FILE *f1。它是指向一個(gè)文件的文件信息區(qū)(存放這文件的有關(guān)信息的地方)。
打開(kāi)文件,所謂的”打開(kāi)“,是指為文件建立相應(yīng)的信息區(qū)(用來(lái)存放有關(guān)文件的信息)和文件緩沖區(qū)(用來(lái)暫時(shí)存放輸入輸出的數(shù)據(jù))。
fopen函數(shù),打開(kāi)文件。函數(shù)調(diào)用方法:fopen(文件名,使用文件方式),例如fopen("a1","r"),fopen(a2,“r”),F(xiàn)ILE *fp=fopen(a3,“w”),a2、a3是存放文件名的數(shù)組名。
文件使用方式 | 含義 | 如果指定的文件不存在 |
”r“(只讀) | 為了輸入數(shù)據(jù),打開(kāi)一個(gè)也存在的文本文件 | 出錯(cuò) |
"w"(只寫(xiě)) | 為了輸出數(shù)據(jù),打開(kāi)一個(gè)文本文件 | 建立新文件 |
"a"(追加) | 向文本文件尾添加數(shù)據(jù) | 出錯(cuò) |
"rb"(只讀) | 為了輸入數(shù)據(jù),打開(kāi)一個(gè)二進(jìn)制文件 | 出錯(cuò) |
"wb"(只寫(xiě)) | 為了輸出數(shù)據(jù),打開(kāi)一個(gè)二進(jìn)制文件 | 建立新文件 |
"ab"(追加) | 向二進(jìn)制文件尾添加數(shù)據(jù) | 出錯(cuò) |
"r+"(讀寫(xiě)) | 為了讀和寫(xiě),打開(kāi)一個(gè)文本文件 | 出錯(cuò) |
"w+"(讀寫(xiě)) | 為了讀和寫(xiě),建立一個(gè)新的文本文件 | 建立新文件 |
"a+"(讀寫(xiě)) | 為了讀和寫(xiě),打開(kāi)一個(gè)文本文件 | 出錯(cuò) |
"rb+"(讀寫(xiě)) | 為了讀和寫(xiě),打開(kāi)一個(gè)二進(jìn)制文件 | 出錯(cuò) |
"wb+"(讀寫(xiě)) | 為了讀和寫(xiě),建立一個(gè)新的二進(jìn)制文件 | 建立新文件 |
"ab+"(讀寫(xiě)) | 為了讀和寫(xiě),打開(kāi)一個(gè)二進(jìn)制文件 | 出錯(cuò) |
fclose函數(shù),關(guān)閉文件。fclose函數(shù)調(diào)用的一般形式:fclose(文件指針),例如:fclose(fp);
對(duì)文本文件讀寫(xiě)一個(gè)字符的函數(shù)
函數(shù)名 | 調(diào)用形式 | 功能 | 返回值 |
fgetc | fgetc(fp) | 從fp指向的文件讀入一個(gè)字符 | 成功(返回讀取的字符),失敗(返回-1,即文件結(jié)束標(biāo)志EOF) |
fputc | fputc(ch,fp) | 把字符ch寫(xiě)到文件指針變量fp所指向的文件中 | 成功(返回輸出的字符),失。ǚ祷-1,即文件結(jié)束標(biāo)志EOF) |
讀寫(xiě)一個(gè)字符串的函數(shù)
函數(shù)名 | 調(diào)用形式 | 功能 | 返回值 |
fgets | fgets(str,n,fp) | 從fp指向的文件讀入一個(gè)長(zhǎng)度為(n-1)的字符串,存放到字符數(shù)組str中。 | 讀成功(返回地址str),失。ǚ祷豊ULL) |
fputs | fputs(str,fp) | 把str所指向的字符串寫(xiě)到文件指針變量fp所指向的文件中。 | 輸出成功(返回0),失。ǚ祷胤0值) |
用格式化的方式讀取文件:
fprintf(文件指針,格式字符串,輸出列表);例如:fprintf(fp,"%d,%f",i,f);
fsanf(文件指針,格式字符串,輸入列表);scanf(fp,"%d,%f",&i,&f);
用二進(jìn)制方式向文件讀取一組數(shù)據(jù):它們一般調(diào)用形式:讀入:fread(buffer,size,count,fp);輸出:fwrite(buffer,size,count,fp);其中buffer是地址,size:要讀寫(xiě)的字節(jié)數(shù),count:要讀寫(xiě)多少個(gè)數(shù)據(jù)項(xiàng)(每個(gè)數(shù)據(jù)項(xiàng)的長(zhǎng)度為size)。注意,打開(kāi)文件時(shí)要使用二進(jìn)制形式,如:fopen(”file1“,”wb“)。
文件位置標(biāo)記
(1)用rewind函數(shù)使文件位置標(biāo)記指向文件開(kāi)頭。
(2)用fseek函數(shù)改變文件位置標(biāo)記,fseek函數(shù)的調(diào)用形式為:fseek(文件指針,位移量,起始點(diǎn)),起始點(diǎn)可以用0、1、2代替,其中0代表文件開(kāi)始位置,1代表當(dāng)前位置,2代表文件末尾位置。起始點(diǎn)名字如表:
起始點(diǎn) | 名字 | 用數(shù)字代表 |
文件開(kāi)始位置 | SEEK_SET | 0 |
文件當(dāng)前位置 | SEEK_CUR | 1 |
文件末尾位置 | SEEK_END | 2 |
位移量應(yīng)是long型數(shù)據(jù)(在數(shù)字的末尾加一個(gè)字母L,就表示long型)
例如:fseek(fp,100L,0)將文件位置標(biāo)記向前移到離文件開(kāi)頭100個(gè)字節(jié)處。
文件讀寫(xiě)的出錯(cuò)檢測(cè)
ferror函數(shù),檢查輸入輸出函數(shù)出錯(cuò)的情況,一般調(diào)用形式:ferror(fp);出錯(cuò)時(shí)返回非0值,未出錯(cuò)返回0值。注意,對(duì)同一個(gè)文件每一次調(diào)用輸入輸出函數(shù),都會(huì)產(chǎn)生一個(gè)新的ferror函數(shù)值。
clearerr函數(shù),作用是使文件錯(cuò)誤標(biāo)志和文件結(jié)束標(biāo)志為0。一般調(diào)用形式:clearerr(fp)。