《上》2021-09-03
《C程序設計---譚浩強》
1.1991年編寫的
2.C神器
《C目錄》
1.程序設計與C語言
2.算法--程序的靈魂
3.最簡單的程序設計--順序程序設計
4.選擇程序設計
5.循環程序設計
6.利用數組批量處理數據
7.使用函數實現模塊設計
8.善用指針
9.用戶建立自己的數據類型
10.文件的輸入輸出
《為什么學程序設計》
1.理解計算機如何工作
2.理解計算機工作原理
3.應用計算機解決問題
《為什么學C》
1.功能豐富
2.表達能力強
3.使用靈活方便
4.應用面廣
5.目標程序效率高
6.可移植性好
7.既有高級語言的優點,又有低級語言的許多特點
8.既適于編寫系統軟件、又能方便地用來編寫應用軟件
《C建議》
1.大學生畢業前一定要學好C,C語言是當前程序員的共同語言
2.在編寫底層設備驅動和內嵌應用程序應用廣泛
《如何學習C》
1.著眼于培養能力
(1)分析問題的能力
(2)構造算法能力
(3)編程能力
(4)調試程序能力
2.重視實踐環節
(1)C是一門應用課程、而非純理論課程
(2)學得好環不是看你知不知道,而是看你會不會干
(3)打好基礎很重要,為學習更高級的知識做準備
3.構造算法
(1)算法是程序的靈魂
(2)積累算法是必須的
《什么是計算機程序》
1.一組計算能識別和執行的指令
2.計算機的一切操作都是由程序控制
3.計算機的本質是程序的機器
《什么是計算機語言》
1.用于人與計算機交流的語言
2.計算機基于二進制工作,只能識別二進制----機器語言
3.符號語言、便于記憶,使用---又稱匯編語言
匯編---將符號語言裝換成機器語言
匯編語言與機器語言完全依賴具體的機器特性--低級語言
4.不依賴具體的機器的語言---高級語言--C系統描述語言
《C標準》
1.ANSI C和C89和C90是同一個標準
2.C99--對C89的擴充
3.TC1\TC2--技術修正
4.嵌入式系統編程以C89為準
《C語言的特點》
1.語言簡潔緊湊、使用靈活方便
2.運算符、數據類型豐富
3.結構化控制語句
4.語言限制不太嚴格、程序設計自由度大
5.允許直接訪問物理地址、能進行位操作、能實現匯編大部分功能
6.可移植性好、生成目標代碼質量高、程序執行效率高
《C語言的有多少個關鍵字》
C89 --32個
C99 --37個
《C語言的9種流程控制語句》
1.選擇
if
switch
2.循環
while
do while
for
3.跳轉
continue
break
return
goto
《C語言的34種運算符》
優先級 運算符 含義 結合方向
1 () 圓括號 自左向右
1 [] 下標運算符 自左向右
1 -> 指向結構體成員運算符 自左向右
1 . 結構體成員運算符 自左向右
2 ! 邏輯非運算符 自右向左
2 ~ 按位取反運算符 自右向左
2 ++ 自增運算符 自右向左
2 -- 自減運算符 自右向左
2 - 負號運算 自右向左
2 (類型) 類型轉換運算符 自右向左
2 * 指針運算符 自右向左
2 & 取地址運算符 自右向左
2 sizeof 長度運算符 自右向左
3 * 乘法運算符 自左向右
3 / 除法運算符 自左向右
3 % 求余運算符 自左向右
4 + 加法運算符 自左向右
4 - 減法運算符 自左向右
5 << 左移運算符 自左向右
5 >> 右移運算符 自左向右
6 <、<=、>、>= 關系運算符 自左向右
7 == 等于運算符 自左向右
7 != 不等于運算符 自左向右
8 & 按位與運算符 自左向右
9 ^ 按位異或運算符 自左向右
10 | 按位或運算符 自左向右
11 && 邏輯與運算符 自左向右
12 || 邏輯或運算符 自左向右
13 ?: 條件運算符 自右向左
14 =、+=、-=、 賦值運算符 自右向左
14 *=、/=、%= 賦值運算符 自右向左
14 <<=、>>= 賦值運算符 自右向左
14 &=、^=、|= 賦值運算符 自右向左
15 , 逗號運算符 自左向右
記憶口訣:
密不可分
四對半
四則
大于小于號多的
位高于邏輯,與高于或,異或夾中間
條件
賦值--四則與位(除了按位取反沒有復合運算)
逗號
結合方向:
單目、三目與賦值從右向左結合
其他的都是從左到右
《C語言的32關鍵字---ASIN C/C89/C90》
數據類型關鍵字(20)
基本數據類型關鍵字
1.void
2.char
3.int
4.float
5.double
類型修飾關鍵字
1.short
2.long
3.signed
4.unsigned
復雜類型關鍵字
1.struct
2.union
3.enum
4.typedef
5.sizeof
存儲類型關鍵字
1.auto
2.static
3.register
4.extern
5.const
6.volatile
流程控制關鍵字(12)
分支結構
1.if
2.else
3.switch
4.case
5.default
循環結構
1.while
2.do
3.for
跳轉結構
1.continue
2.break
3.return
4.goto
《C99新增的5個關鍵字》
1.inline
2.restric
3.Bool
4._Complex
5._Imaginary
《C語言注釋》
1.注釋是給人看的
2.在預處理時將注釋替換為空格,所以不產生目標代碼
3.單行注釋是C99標準的--//
4.多行注釋不可嵌套注釋--/**/
錯誤代碼:
#include<stdio.h>
int main(void)
{
/*
/*
*/
*/---報錯
return 0;
}
5.在字符串中的//與/**/不作為注釋的開始
#include<stdio.h>
int main(void)
{
printf("/*你好*/\n");--/*你好*/
printf("//我好");--//我好
return 0;
}
《C語言程序結構》
1.一個程序由一個或多個源文件組成
2.函數是C程序的主要組成部分
3.程序總是從main函數開始執行
4.C語言本身不提供輸入輸出語句
5.程序應當包含注釋
《程序設計的任務》
1.問題分析
2.設計算法
3.編寫程序
4.對源程序進行編輯、編譯、鏈接
5.運行程序,分析結果
6.編寫程序文檔
《算法的初探》
1.為解決某一問題采取的方法和步驟
2.數值運算算法、非數值運算算法(主要的)
3.采用方法簡單、運算步驟少的
4.算法的目的是求解,解就是輸出,沒用輸出的算法是沒有意義的
5.設計算法、實現算法
《算法的特性》
1.有窮性
2.確定性
3.有零個輸入或多個輸入
4.有一個輸出或多個輸出
5.有效性
《怎樣表示一個算法》
1.自然語言
2.傳統流程圖
3.結構化流程
4.N-S流程圖
5.偽代碼
《結構化程序的設計》
分而治之的思想
1.自頂向下
2.逐步細化
3.模塊化設計
4.結構化編碼
《編寫C程序必須具備的》
1.心中要有算法
2.掌握C語言的語法
《數據的表現形式》
1.常量--在程序運行過程中,其值不能被改變的量
整型常量
十進制
八進制
十六進制
二進制
實型常量
十進制小數形式
指數形式
E或e--以10為底的指數
E或e--前必須有數,后必須為整數
字符常量
普通字符--單引號引起來的一個字符
轉義字符--以\開頭的字符序列
把\后面的字符轉換成另外的意思
\n---n不是字母,n表示換行
\ooo--八進制表示 最大\177
\xoo--十六進制表示 最大\7F
因為ASCII表示的數的范圍0~127
字符串常量--用雙引號引起來的若干字符
符號常量--使用#define指定定義的
好處:
1.見名知意
2.一改全改
符號常量與常變量的理解
1.符號常量是一個符號、沒有地址,在預編譯后這個符號就不見了
2.常變量量--有地址、在編譯后存在
3.符號常量才是真正的常量,因為沒有地址,無法通過指針修改
#include<stdio.h>
#define PI 3.14
const int a=1;
int main(void)
{
printf("%x",&a);//0x404004
//printf("%d",&PI);//報錯
return 0;
}
2.變量---一個有名字的、具有特定屬性的一個存儲單元,在程序運行過程中,可以被改變
C89規定:變量必須先定義,后使用
C99規定:變量可以在函數或復合語句中定義
變量名:
代表一個存儲地址
通過變量寫入或獲取值的本質:
通過變量名找到相應內存地址
通過地址確定相應存儲單元
通過相應存儲單元中獲取值
變量值
存儲單元
3.標識符
1.用于對象命名的有效字符序列
數字、字母、下劃線
不能以數字開頭
不能是關鍵字
《數據的類型》
1.對數據分配存儲單元的安排
數據的長度
數據的存儲形式
2.結構圖
數據類型
基本數據類型
整型型
基本整型 int
短整型 short int
長整型 long int
字符型 char
C99增加的:
*雙長整型 long long int
*布爾 bool
浮點型
單精度浮點型 float
雙精度浮點型 double
復數浮點型 float_complex,double_comple,long long_comple
派生數據類型
指針類型 *
數組類型 []
結構體類型 struct
共用體類型 union
函數類型
枚舉類型 enum
空類型 void
《整型數據》
1.數據的存儲是以補碼形式存儲在內存中
2.C標準并沒有具體規定各種數據類型所占用的存儲空間,有各編譯系統自行決定
3.C標準值要求long類型長度不不短于int類型,short類型不長與int類型
sizeoof(short)<=sizeof(int)<=sizeof(long)<=sizeof(long long)
通常規定short占16位,long占32位,int的可以是16位,也可以是32位
int 在16或8位系統中 占16位
int 在32或64位系統中 占32位
無符號---表示不能表示負數,只能表示0和正數
若未指定signed或unsigned,則默認使signed
只有整型數據可以加signed或unsigned,實型不能加
字符是按其代碼(整數)形式存儲的,因此C99把字符數據作為整型類型中的一種
所以字符1與整數1不是一個概念
《浮點型數據》
1.用來表示小數
2.實數以指數形式存儲
一個小數使用指數形式表示不止有一種形式
只要在小數點移動的同時改變指數的值,就能保證小數的值不變
實數的指數形式--浮點數
3.規范指數形式
小數點前的數字為0,小數點后的數字不為0
3.14159 ----- 0.3.14159E1
4.浮點型 --小數部分 ---指數部分
小數位數越多,精度越高,表示范圍越小
小數位數越少,精度越低,表示范圍越大
類型 有效位數
float 6
double 15
整數默認使int 浮點數默認是double
《運算符》
1. /
兩個實數相除結果是雙精度實數
兩個整數相除結果是整數
有負數的除法向零取整
#include<stdio.h>
int main(void)
{
printf("%d\n",sizeof(5.0/3.0));//8--雙精度
printf("%d\n",5/3);//1
printf("%d\n",-5/3);//-1
return 0;
}
2. %
要求參加的運算對象為整數
實數沒有求余的說法
除%外的運算符的操作數可以是任意數據類型
#include<stdio.h>
int main(void)
{
printf("%d\n",5%3);//2
printf("%d\n",-5%3);//-2
printf("%d\n",5.0%3);//報錯
return 0;
}
3.字符
字符是整數代碼形式存儲的---ASCII
輸出形式有兩種
整數輸出
字符輸出
《語句》
1.表達式---運算符+操作數
2.語句---表達式+分號
3.空語句--沒有表達式,只有分號
4.復合語句--用花括號括起來的語句--又稱語句塊
#include<stdio.h>
int main(void)
{
int a=0,b=0;
a+b//表達式 ---報錯
a+b;//語句
; //空語句
{
a+b;//復合語句
}
return 0;
}
5.左值--出現在賦值運算符的左側
6.右值--出現在賦值運算符的右側
凡是是左值都可以作為右值
變量是左值--可被賦值改變
常量是右值--不可被賦值改變
表達是右值--不可被賦值改變
#include<stdio.h>
#define N 10
int main(void)
{
int a=0,b=0;
a=1;//左值可通過賦值改變
a=b;//左值可以作為右值
(a+b)=3*4;//報錯 (a+b)是表達式,是右值,不能作為左值,不能通過賦值改變
N=10;//報錯 N是常量,是右值,不能左值,不能通過賦值改變
printf("%d",a);
}
《有關輸入輸出的概念》
1.輸入輸出是以計算機為主體而言
2.C語言本身不提供輸入輸出語句,輸入輸出操作是由C標準庫函數來實現
好處:
使C編譯系統簡單精煉
在編譯階段避免處理有關硬件有關問題、提高可移植性
庫函數在鏈接階段與源目標文件連接,生成可執行文件
3.標準輸入輸出函數
putchar---輸出字符
輸出一個字符
顯示字符
控制字符
getchar---輸入字符
顯示字符
控制字符
說明:
1.在鍵盤上輸入信息時,并不是在鍵盤上敲一個字符就馬上送到計算機中去的
2.這些字符存儲在鍵盤的緩沖器中,只有按下Enter鍵才把這些字符輸入到計算機中去
3.最后按順序分別賦值給相應的變量
printf----格式化輸出
格式控制
%d--有符號的十進制整數
%c--輸出一個字符
%s--輸出字符串
%f--輸出實數
%f---整數部分全部輸出,小數部分輸出6位
%m.nf
m--數據的寬度
n--輸出的小數位數
默認右對齊
數據在右,左端補空格
%-m.n
m--輸出的列數
n--輸出的小數位數
- 左對齊
數據在左,右端補空格
#include<stdio.h>
int main(void)
{
int a=0;
char c=65;
char s[10]="nihao";
float f = 123.456;
printf("%d\n",a); //0
printf("%c\n",c); //A
printf("%s\n",s); //nihao
printf("%f\n",f); //123.456001---默認6位有效位
printf("%20.4f\n",f); // 123.4560---默認右對齊
printf("%-20.4f\n",f);//123.4560---加負號,左對齊
}
%e--指數形式輸出實數
小部分占6位
指數部分占5位
e占1列
指數符號占1列
指數占3列
#include<stdio.h>
int main(void)
{
float f = 123.456;
float f1 = 1234.4456;
printf("%e\n",f);//1.234560e+002
printf("%e\n",f1);//1.234446e+003
}
其他不常用
%i--與%d相同--按十進制整數數據實際長度輸出
%o--以八進制整數形式輸出
%x--以十六進制整數形式輸出
%u--以無符號十進制整數輸出
%g--輸出浮點數、選擇%f\%e輸出寬度較短的格式輸出,不輸出沒有意義的0
格式控制的一般形式
% 附加字符 格式字符
附加字符
l--長整型整數
m--數據的最小寬度
n--
實數--輸出n個小數
字符串--截取字符的個數
- 輸出的數字或字符在域內向左靠
#include<stdio.h>
int main(void)
{
char s[20]="hello word!";
printf("%s\n",s); //hello word!
printf("%10.7s\n",s); // hello w
printf("%-10.7s\n",s); //hello w
}
輸出列表
說明:
1.printf輸出時,輸出對象的類型要跟格式類型一致,否則會出現錯誤
2.除了X、E、G外,其他格式字符必須使用小寫
3.格式控制字符串內可以包含轉義字符
4.想輸出%,需要寫兩個
總結:
格式控制字符串=[格式聲明]+[轉義字符]+[普通字符]
格式聲明=%+[附加字符]+格式字符
附加字符={l,m,n,-}
格式字符={d,i,o,x,X,u,c,s,f,e,E,g,G}
scanf-----格式化輸入
格式控制--同printf
地址列表--地址
gets------輸入字符串
#include<stdio.h>
int main(void)
{
char s[20];//緩沖區
printf("%s",gets(s));//打印獲取到的數據
}
puts------輸出字符串
#include<stdio.h>
int main(void)
{
char s[30]="我在景德鎮等你";//緩沖區
puts(s);//打印緩沖區的數據 并自動換行
}
#include<stdio.h>
int main(void)
{
char s[20]="我說橋邊姑娘";//緩沖區
puts(gets(s));//覆蓋原來的數據,打印獲取到的數據 并自動換行
}
《流程控制》
if與switch的理解
switch使用同一個條件去匹配,每個匹配項共用這個條件,可以對這個條件進修改,到達狀態轉換的目的
if的多條件更多描述區間,switch描述的是某一點
if else 與 ?:的關系
等價
使用?:只需要一條語句就能達到同樣的效果
使用?:在不使用關鍵字的情況下就能達到同樣的效果
閏年的理解
1.能被4整除,不能被100整除
2.能被400整數 如:2000年是閏年 1900不是閏年
為什么需要循環?
程序處理的問題需要重復處理
continue 與 break
continue 結束本次循環
break 結束整個循環
《數組》
1.反映數據的特點與內在聯系
2.下標從零開始
長度的理解
程序運行過程中,不允許對同一數組的長度進行改變--C89
#include<stdio.h>
int main(void)
{
int len;
scanf("%d",&len);//獲取長度
int arr[len];//作為數組的長度
for(int i=0;i<sizeof(arr)/sizeof(int);i++)//循環獲取值
scanf("%d",&arr[ i]);
for(int i=0;i<sizeof(arr)/sizeof(int);i++)//循環顯示
printf(" %d ",arr[ i]);
return 0;
}
#include<stdio.h>
int main(void)
{
int len;
for(int i=0;i<5;i++) //循環獲取長度
scanf("%d",&len);
int arr[len];//作為數組的長度--最后一個起作用
for(int i=0;i<sizeof(arr)/sizeof(int);i++)//循環獲取值
scanf("%d",&arr[ i]);
for(int i=0;i<sizeof(arr)/sizeof(int);i++)//循環顯示
printf(" %d ",arr[ i]);
return 0;
}
C99支持變長數組
Fibonacci數列---斐波那契數列
1 1 2 3 5 8 13 21 35 ....
1.從第三項開始,每一項等于前兩項之和
冒泡算法--三段法理解
1.如果有2個數,需要比較2-1趟
2.如果有3個數,需要比較3-1趟
....
3.如果有n個數,需要比較n-1趟
1.第1趟需要比較n-1次
2.第2趟需要比較n-2次
.....
3.第j趟需要比較n-j次
算法實現:
#include<stdio.h>
int main(void)
{
puts("請輸入要比較的個數:");
int len;
scanf("%d",&len);
int arr[len];
/* 循環獲取用戶的輸入 */
for(int i=0;i<sizeof(arr)/sizeof(int);i++)
scanf("%d",&arr[ i]);
/* 排序之前 */
puts("排序之前") ;
for(int i=0;i<sizeof(arr)/sizeof(int);i++)
printf(" %d ",arr[ i]);
puts("") ;
/* 冒泡算法實現 */
for(int i=0;i<len-1;i++)
for(int j=0;j<len-1-i;j++)
{
if(arr[j+1]<arr[j])
{
int temp;//放最大的數
temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;//把最大的數交換到最后
}
}
/* 排序之后 */
puts("排序之后") ;
for(int i=0;i<sizeof(arr)/sizeof(int);i++)
printf(" %d ",arr[ i]);
}
《二維數組》
二維數組可以看成一個特殊的一維數組,這個特殊的數組的元素是一個個一維數組
內存存儲--按行存儲
int[3][4];
存儲結構:
a[0][0]
a[0][1]
a[0][2]
a[0][3]
a[1][0]
a[1][1]
a[1][2]
a[1][3]
a[2][0]
a[2][1]
a[2][2]
a[2][3]
邏輯結構:
a[0][0] a[0][1] a[0][2] a[0][3]
a[1][0] a[1][1] a[1][2] a[1][3]
a[2][0] a[2][1] a[2][2] a[2][3]
初始化時,行號可以省略,列號不可省略--看邏輯結構理解
《字符數組》
字符串的有效長度與字符數組的長度不是一個概念
字符串:雙引號引起來的字符,以'\0'為結束標志
字符串有效長度:'\0'之前的有效字符個數
字符數組:存放字符的數組
字符數組的長度:定義時寫的大小
因為C語言沒有字符串的數據類型,所以使用字符數組來表示
由上可知,字符數組的長度比字符串的長度大
字符串的輸入輸出
%s--一次性輸入\輸出
scanf("%s",字符數組名);
printf("%s",字符數組名);
#include<stdio.h>
int main(void)
{
char arr[30];
scanf("%s",arr);
printf("%s",arr);
}
《字符串處理函數》
puts(字符數組);
gets(字符數組);
#include<stdio.h>
int main(void)
{
char arr[10];
puts(gets(arr));//獲取直接輸出
}
#include<stdio.h>
int main(void)
{
char arr[10];
char *a;
a=gets(arr);//返回值為char *
puts(a);
}
#include<stdio.h>
int main(void)
{
char arr[10];
char *a;
a=gets(arr);//返回值為char *
*a=65;//把第一位改為A
puts(a);
}
strcat(字符數組1,字符數組2);
將字符數組2連接到字符數組1的后面
#include<stdio.h>
#include<string.h>//需要引入字符處理函數頭文件
int main(void)
{
char arr1[20]="hello";//被連接的數組要足夠大,否則會有意想不到的后果
char arr2[10]="word!";
puts(arr1);//連接之前 hello
strcat(arr1,arr2);
puts(arr1);//連接之后 helloword!
}
strcpy(字符數組1,字符數組2);
將字符數組2復制到字符數組1的中去
#include<stdio.h>
#include<string.h>//需要引入字符處理函數頭文件
int main(void)
{
char arr1[6]="hello";
char arr2[10]="word!";
puts(arr1);//復制之前 hello
strcpy(arr1,arr2);
puts(arr1);//復制之后 word! ---完全覆蓋原來的字符
}
strcmp(字符數組1,字符數組2);
將字符數組2與字符數組1比較
根據ASCII表進行比較,直到出現不同的字符或遇到'\0'為止
#include<stdio.h>
#include<string.h>//需要引入字符處理函數頭文件
int main(void)
{
int result;
char arr1[6]="hello";
char arr2[10]="aord!";
result=strcmp(arr1,arr2);
printf("%d",result) ;//1 字符串1>字符串2 正數
}
#include<stdio.h>
#include<string.h>//需要引入字符處理函數頭文件
int main(void)
{
int result;
char arr1[6]="hello";
char arr2[10]="word!";
result=strcmp(arr1,arr2);
printf("%d",result) ;//1 字符串1<字符串2 負數
}
#include<stdio.h>
#include<string.h>//需要引入字符處理函數頭文件
int main(void)
{
int result;
char arr1[6]="hello";
char arr2[10]="hello";
result=strcmp(arr1,arr2);
printf("%d",result) ;//0 字符串1等于字符串2 0
}
strlen(字符數組);
求字符的長度
#include<stdio.h>
#include<string.h>//需要引入字符處理函數頭文件
int main(void)
{
int result;
char arr[]="hello";
result=strlen(arr);
printf("%d\n",result) ;//5 字符串的有效長度
printf("%d",sizeof(arr)/sizeof(char));//6 字符數組的長度
}
strlwr(字符數組);
轉為小寫的函數
#include<stdio.h>
#include<string.h>//需要引入字符處理函數頭文件
int main(void)
{
char arr[]="WORD";
char *a;
a=strlwr(arr);//返回char *類型轉小寫
printf("%s\n",a);//word
}
strupr(字符數組);
轉為大寫的函數
#include<stdio.h>
#include<string.h>//需要引入字符處理函數頭文件
int main(void)
{
char arr[]="hello";
char *a;
a=strupr(arr);//返回char *類型轉大寫
printf("%s\n",a); //HELLO
}
《統計單詞個數》
1.一個空格對應一個新詞
#include<stdio.h>
#include<string.h>//需要引入字符處理函數頭文件
int main(void)
{
char string[100];//存放單詞的容器
int word=0;//統計單詞標志
int flag=0;//判斷是否以空格開頭標志
int number=0;//計數器
char c;//存放每個字符
gets(string);//獲取數據
for(int i=0;(c=string[ i])!='\0';i++)
{
if(string[0]!=' ')//不是以空格開始
{
flag=1;
if(c==' ')//一個空格對應一個單詞
{
word=1;
}
else
if(word==1)
{
word=0;
number++;
}
}
else//以空格開始
{
if(c==' ')
{
word=1;
}
else
if(word==1)
{
word=0;
number++;
}
}
}
if(flag)
printf("%d\n",number+1);//給第一個單詞加個空格
else
printf("%d\n",number);
}
《函數》
1.讓代碼可重用
2.使程序便于維護和閱讀
3.模塊化設計的需要
函數包括兩個部分
函數首部
函數的返回值
函數名
參數列表
函數體
具體實現
空函數的作用
提高程序的擴展性
實參與形參
實參:在調用函數時傳遞的參數
形參:在定義函數時寫的參數
調用函數的過程
1.實參把數據傳給形參
2.形參把數據轉入函數內部進行處理
函數的類型決定返回值類型
函數的原型=函數的首部
函數的聲明=函數的首部+分號
函數的遞歸調用--函數直接或間接的調用自己
《求0~15內的階乘》
#include<stdio.h>
int dg(int number);
int main(void)
{
int result;
int number=15;//最大階乘15
for(int i=1;i<=number;i++)
{
result=dg(i);
printf("%2d!=%d\n",i,result);
}
}
int dg(int number)
{
if(number == 1 || number==0)//0與1的階乘都是1
return 1;
else
return dg(number-1)*number;//遞歸到number的值為1位止
}
遞歸的次數不宜過多,太多會使棧溢出
遞歸思想
漢諾塔:漢諾塔(又稱河內塔)問題是源于印度一個古老傳說的益智玩具
一維數組和二維數組都做函數的形參
變量作用域
局部變量:
1.在復合語句內定義的變量
2.函數的形參
全局變量
1.函數之外定義
變量只能在作用域內有效
全局變量用于增加函數間數據聯系
全局變量與局部變量重名,局部變量有效---就近原則
#include<stdio.h>
int number=20;
int main(void)
{
{
int result;
int number=15;
printf("%d\n",number);//15
}
printf("%d",number);//20
}
變量存儲方式
1.靜態存儲--分配固定的存儲空間
2.動態存儲--根據需要分配存儲存儲空間
存儲空間可分為
1.程序區
2.靜態存儲區
3.動態存儲區
動態存儲區中存放的
1.函數形參
2.函數中定義的沒有使用static的變量
3.調用函數時現場保護和返回地址
對于這些數據,調用函數時動態分配存儲空間,函數結束時釋放這些空間。
所以兩次調用這個函數,分配的局部變量地址可能不一樣
函數和變量都有兩個屬性
1.數據類型
2.存儲類別
變量
自動變量
auto
不寫默認就是
值釋放
動態存儲
每次都會給初值
靜態變量
static
值不釋放
靜態存儲
只會給一次初值---靜態變量在第一次調用才會執行
寄存器變量
register
對于頻繁使用的值,把值存儲在寄存器中,提高程序效率
但是對應現在的計算機,速度很快,所以這個操作不是很必要了
全局變量
函數外定義的變量
作用域:從定義處到文件末尾
靜態存儲
使用extern可以擴展全局變量的"作用域"
1.在文件中擴展
2.擴展到其他文件
使用statc可以把全局變量的作用域限制在本文件中
作用域與生存期
作用域---空間角度
生存期---時間角度
定義與聲明
需要建立存儲空間的聲明--- 定義性聲明---定義 int a;
不需要建立存儲空間的聲明-- 引用性聲明---聲明 extern a;
內部函數與外部函數
加static的函數--內部函數
1.靜態函數
2.只能在本文件內使用
加extern的函數--外部函數
1.可以省略寫extern
2.默認是外部的
《結構體》
用戶建立用于存放不同數據類型的組合型的數據結構
聲明結構體的格式
struct 結構體名 {成員列表};
結構體類型名=truct+結構體名(結構體標記)
#include<stdio.h>
struct Student
{
int num;
char name[20];
char sex;
int age;
float score;
char addr[30];
};//聲明結構體
int main(void)
{
printf("%d",sizeof(struct Student));//68--獲取結構在內存中占的字節數
/*
計算機對內存的管理是以字為單位的,許多計算機系統以4個字節為一個字
類型 占空間 求余4剩余的空間
int num 4 0
char name[20] 20 0
char sex 1 3
int age 4 0
float score 4 0
char addr[30] 30 2
4+20+1+4+4+30=63 0+0+3+0+0+2=5
總:63+5=68個字節
*/
}
定義結構體類型變量
1.先聲明結構體類型,再定義該類型變量
struct 結構體名{成員列表};//聲明結構體
struct 結構體名 結構體變量名;//定義結構體
2.在聲明類型的同時定義變量
struct 結構體名{成員列表}結構體變量名列表;//聲明類型的同時定義
3.不指定結構體名而直接定義結構體類型的變量
struct{成員列表}變量名列表;
不能在去定義其他變量,用法不多
說明:
1.結構體類型名
2.結構體名
3.結構體變量名
要分清他們
4.結構體成員名可以與普通變量名重名,但是他們沒有任何關系,屬于不同的對象,互不干擾
結構體的初始化與引用
1.在定義結構體變量時對它的成員初始化
2.C99允許只對某一成員初始化
3.其他未初始化的成員
數值型初始化 0
字符型 '\0'
指針類型 NULL
其實他們的值都為0
4.通過結構體變量名引用成員
結構體變量名.成員名
5.對結構體的成員只能每個的輸入或輸出
6.結構體的成員中有結構體,通過成員運算符一級一級地找到最低的一級成員
7.結構體變量的成員的變量可以像普通變量一樣進行各種運算
8.同類型的結構體變量可以相互賦值
聲明、定義、初始化
#include<stdio.h>
struct Student
{
int num;//學號
char name[30];//姓名
char sex;//性別
int age;//年齡
float score;//成績
char addr[30];//地址
}student={1605406202,"藍祥樂",'M',18,99.0,"廣西"};//直接初始化
int main(void)
{
/* 輸出類型要抑制 */
printf("學號=%d\n",student.num); //學號=1605406202
printf("姓名=%s\n",student.name); //姓名=藍祥樂
printf("性別=%c\n",student.sex); //性別=M
printf("成績=%f\n",student.score);//成績=99.000000
printf("地址=%s\n",student.addr); //地址=廣西
}
聲明、定義、分別初始化
#include<stdio.h>
struct Student
{
int num;//學號
char name[30];//姓名
char sex;//性別
int age;//年齡
float score;//成績
char addr[30];//地址
};
int main(void)
{
struct Student student;//定義結構體變量
/* 分別賦值 */
student.num=1605406202;
student.name[0]='l';
student.name[1]='x';
student.name[2]='l';
student.name[3]='\0';//最好加'\0',字符串的結束標志
student.sex='男';//亂碼 ASCII沒有中文
student.score=90.0;
student.addr[0]='g';
student.addr[1]='x';
student.addr[2]='\0';
printf("學號=%d\n",student.num); //學號=1605406202
printf("姓名=%s\n",student.name); //姓名=lxl
printf("性別=%c\n",student.sex); //性別=? //因為ASCII沒有相應中文編碼 --單個字符
printf("成績=%f\n",student.score);//成績=99.000000
printf("地址=%s\n",student.addr); //地址=gx
}
至簡至美---能讓用戶喜歡
聲明、定義、使用掃描函數初始化
#include<stdio.h>
struct Student
{
int num;//學號
char name[30];//姓名
char sex[10];//性別 ---需要存中文請這樣寫
int age;//年齡
float score;//成績
char addr[30];//地址
}student;//聲明的同時定義
int main(void)
{
/* 初始化 格式控制要與變量類型一致,不然會有意想不到的效果 */
scanf("%d%s%s%d%f%s",
&student.num,
student.name,
student.sex,
&student.age,
&student.score,
student.addr);
printf("學號=%d\n",student.num); //學號=1605406202
printf("姓名=%s\n",student.name); //姓名=lxl
printf("性別=%s\n",student.sex); //性別=男
printf("成績=%f\n",student.score);//成績=99.000000
printf("地址=%s\n",student.addr); //地址=廣西
}
《枚舉》
概念
變量的值只有幾種可能
變量的值只限于列舉出來的值的范圍內
聲明枚舉的一般形式
enum [枚舉名]{枚舉元素列表};
說明:
1.C編譯對枚舉元素按常量處理--枚舉常量
2.C語言編譯時默認認為他們的值為0,1,2,3,4,...
3.可以在聲明時指定枚舉的值
4.可以聲明沒有名字的枚舉,直接定義枚舉變量
作用
限制輸入參數的值在枚舉范圍內,若果賦予其他值,就會出現錯誤信息,便于檢測
#include<stdio.h>
enum Data
{
one,two,three,four
};
int main(void)
{
/* 初值自動從零,自動加1 */
printf("%d\n",one);//0
printf("%d\n",two);//1
printf("%d\n",three);//2
printf("%d\n",four);//3
}
#include<stdio.h>
enum Data
{
/* 初值從2開始,自動加1 */
one=2,two,three,four
};
int main(void)
{
printf("%d\n",one);//2
printf("%d\n",two);//3
printf("%d\n",three);//4
printf("%d\n",four);//5
}
#include<stdio.h>
enum Data
{
/* 初值從0開始,自己觀察,自動加1 */
one,two,three=10,four
};
int main(void)
{
printf("%d\n",one);//0
printf("%d\n",two);//1
printf("%d\n",three);//10
printf("%d\n",four);//11
}
#include<stdio.h>
enum Data
{
one=2,two=1,three=10,four=3
}; //聲明枚舉
int main(void)
{
enum Data date;//定義枚舉變量
date=one; //把枚舉成員賦給枚舉變量
printf("%d\n",date);//2
printf("%d\n",two);//1
printf("%d\n",three);//10
printf("%d\n",four);//3
}
#include<stdio.h>
enum
{
one,two=2,three=10,four
}; //聲明無名枚舉
int main(void)
{
printf("%d\n",one);//0
printf("%d\n",two);//2
printf("%d\n",three);//10
printf("%d\n",four);//11
}
#include<stdio.h>
enum
{
one,two=2,three=10,four//在定義時可以賦值--第一次賦值
}; //聲明無名枚舉
int main(void)
{
printf("%d\n",one=2);//報錯 常量不能再被賦值
printf("%d\n",two);//2
printf("%d\n",three);//10
printf("%d\n",four);//11
}
#include<stdio.h>
enum hehe
{
one,two=2,three=10,four,five=10//在定義時可以賦值--第一次賦值
}; //聲明枚舉
int main(void)
{
printf("%d\n",sizeof(enum hehe));// 枚舉的大小是4個字節 所以枚舉是以int常量來處理
printf("%d\n",two);//2
printf("%d\n",three);//10
printf("%d\n",four);//11
}
《typedef》
概念
指定新的類型名來替代已有的類型名
應用
1.簡單的用一個新類型名替代原有的類型名
2.命名一個簡單的類型名替代復雜類型名
定義新類型名的方法
1.先按定義變量的方法寫出定義體
2.將變量名換成新類型名
3.在最前面加typedef
4.然后就可以使用新類型名去定義變量了
習慣把新類型名的第一個字母用大寫
typedef只是對已存在的類型指定一個新的類型名字,而沒有創造新的類型
用typedef給數組類型、指針類型、結構體、共用體、枚舉起別名,使編程更加方便
typedef與#define的理解
#define ---預處理階段、簡單字符串替換
typedef ----編譯階段,不是字符串簡單替換
使用typedef聲明的類類放在頭文件中,便于移植
《共用體》
概念
幾個變量共用同一段內存的結構
格式
union 共用體名{成員列表}變量表列;
說明
共用體所占內存長度等于最長的成員的長度
共用體的變量地址和各成員的地址都是同一個值
#include<stdio.h>
union uu
{
int i;
char c;
float f;
double b;
}; //聲明共用體
int main(void)
{
union uu uu; //定義共用體變量 共用體名與共用體變量名一樣不影響
printf("%d\n",sizeof(uu.i));// 4個字節
printf("%d\n",sizeof(uu.c));// 1個字節
printf("%d\n",sizeof(uu.f));// 4個字節
printf("%d\n",sizeof(uu.b));// 8個字節
printf("%d\n",sizeof(union uu));// 8個字節,共用體以最長類型的字節為準
}
union uu
{
int i;
char c;
float f;
double b;
}; //聲明共用體
int main(void)
{
union uu uu; //定義共用體變量 共用體名與共用體變量名一樣不影響
uu.i=65;
printf("%d\n",uu.i);// 65
printf("%c\n",uu.c);// 'A' 共用一個內存空間,數據都一樣
printf("%f\n",uu.f);// 0.000000 //解析失敗
printf("%f\n",uu.b);// 0.000000 //解析失敗
}
《結構體數組》
格式
struct 結構體名 {成員列表}數組名[數組長度];
《結構體指針》
概念
指向結構體變量的指針
1.指向結構體變量的指針
訪問成員的方法
1.結構體變量.成員名
2.*(指向結構體變量的指針).成員名
3.指向結構體變量的指針->成員名----這個是第二中的簡化
運算符
. 成員訪問符
-> 指向運算符
2.指向結構體數組的指針
不管指向結構體變量還是結構體數組,定義的指針類型要和指向類型要一致
《用指針處理鏈表》
鏈表
是一種數據結構
組成
頭指針
結點
1.用戶需要的實際數據
2.下一個結點的地址
尾指針
在內存中是不連續的--手拉手
靜態鏈表
動態鏈表
《簡單的指針》
指針是什么?
指針是存地址的變量,因此我們認為指針是一種地址類型。
地址是什么?
是內存空間的字節編號,因此一個字節對應一個地址。
指針的意義?
靈活訪問一塊空間。
指針的目的?
找對象,搞對象
定義變量的格式?
類型 變量名;
指針的三要素?
指針變量名、指針變量類型、指針對象類型。
指針變量名、指針變量類型、指針對象類型如何分辨?
定義 指針變量名 指針類型 指針對象類型
int *p p int * int
為什么指針對象類型為int,因為*p代表的含義是指針的指向對象,等價于對象的變量名,因此類型為int.
變量名與類型?
定義 變量名 類型 說明
int a a int 基本類型
int a[10] a int [10] 數組類型
int a(int a,int b) a int (int a,int b) 函數類型
int *a a int * 指針類型
指針對象與指針對象類型?
定義 指針對象 指針對象類型 說明
int *p *p int 本質是指針,指向一個整型型空間(整型指針)
int (*p)[10] *p int [10] 本質是指針,指向一個數組空間(數組指針)
int (*p)(int a,int b) *p int int(int a,int b) 本質是指針,指向一個函數空間(函數指針)
int **p *p int * 本質是指針,指向一個指針空間(二級指針)
如果p=&a,就是p指向a空間,上下對比可知*p是a。
推理:p=&a ---> *p = *&a ---> *p = a
由上可知 *& = 1,*p表示就是指針對象的空間,所以抹去*p剩下就是指針對象的類型。
類型如何看?
把變量名找出來,剩下的就是類型。
int a; 變量名是a 類型int
如果是指針,我們要找的一般是對象類型,把對象找出來,剩下的就是類型。
int *p; 對象為*p 對象類型為int
以上文字的Word格式文檔下載(內容和本網頁上的一模一樣,方便保存):
譚浩強C學習(上).docx
(45.03 KB, 下載次數: 42)
2021-9-3 23:14 上傳
點擊文件名下載附件
|