《C语言程序设计教程》(一)
- 標識符規則
- 常量變量
- 變量的初始化
- 數據類型
- 實型數據
- 字符型數據
- 基本表達式和運算符
- sizeof
- 類型強制轉化
- printf格式控制字符
- 附加格式符
- putchar
- 標準輸入
- scanf調用注意點
- getchar
- 條件運算條件表達式
- if條件
- for
- breakcontinue
- 判斷是否是素數
- 數組
- scanf函數
- getchar方法
- 字符數組
- 字符串
- 字符串的輸入輸出
- 字符串處理函數
- 指針
- 訪問類型
- 指針變量定義
- 指針的比較
- 指針和一維數組關系
- 利用指針遍歷一維數組的兩種方法
- 2維數組指針
- 二維數組的指針變量
- 字符串指針
- 字符串指針變量使用的注意點
- 函數返回值是指針
- 指向函數的指針
- 二級指針
- 指針函數
- 數組指針
- 指針tip
- 結構體
- 結構體變量的成員引用操作
- 結構體變量的初始化
- 結構體與數組
- 結構體如何訪問數組成員
- 結構體與指針
- 結構體鏈表
- 動態內存分配
- 內存釋放
- 共用體
- 共用體的定義
- 共用體的訪問對象
- 結構體和共用體的聯合使用
- 枚舉
- typedef
- 函數的申明與調用
- 參數傳遞
- 局部變量全局變量
- 變量的存儲類別
標識符規則
常量、變量
int c= 7; #define PAI = 3.1415926;//常量的標識符全好是大寫。變量的初始化
可以多個同類型的一起賦值
int c= 7,b = 6;數據類型
實型數據
也稱為浮點數。兩種表現形式:
- 十進制小數
- 指數形式
需用的注意以下幾點:
在實型計算中,不區分單精度還是雙精度,都按照double,除非,你在數字后面指定了f或F,則認為是float。
double 提供16位有效數字,就是7位整數。
float提供7位有效數字,就是16位整數。
字符型數據
字符常量是用單引號括起來的字符。
- 只有用單引號括起來的才是字符常量,用雙引號或者其他符號括起來不是字符常量。
- 字符常量只能是單個字符,不能是多個,轉義的除外。
- 字符常量以ASCLL碼存儲,范圍0-255,字符常量是以ASCLL
等價的整數值就行運算。
轉義字符
是一種特殊的字符常量,以\開頭,有特定的含義。
\n 回車換行
\t 橫跳下一個制表符
\b 退格
\r 回車
\f 走紙換頁
\ 反斜線\
\’ 單引號
\” 雙引號
字符變量
char o = 'a';一個字符變量占一個字節的分配空間。
一個中文漢字=兩個字符,占2個字節。
字符串常量
字符串常量是由一對雙括號括起來,系統會自動在每個字符串結束后面加一個字符串結束標志’\0’。
字符常量和字符串常量區別
在c語言中,可以把一個字符常量賦值給字符變量,但是不能把一個字符串常量賦值給字符串變量,因為在
c中,沒有定義相應的字符串變量,在后面會講到用字符數組來存放一個字符串常量。
字符串常量的字節數,是字符串的字符個數+1,因為還有一個字符串結束標識符也占一個字節。
基本表達式和運算符
在c語言中一些基本的,我就不講。
sizeof是用來結束數據的字節數。
/:是除法運算,如果參加運算的都是整型,那么結果就是整型,舍去小數;但是如果參加的運算有一個是實型,那么結果就是double。
%:求余運算,要求參加運算的量都是整型,然后取兩數的余數。
sizeof
這個功能是求數據在內存中所占的字節數。
int a = sizeof(10);printf("%d",a);類型強制轉化
double c = (double)(a+b);printf格式控制字符
附加格式符
putchar
可以用來輸入字符常量和字符變量。
putchar('a');標準輸入
scanf(“格式控制字符”,地址表列); //地址列表中給出的各變量的地址,地址是通過取地址符&后面跟變量名來獲取的。scanf調用注意點
getchar
這個函數執行的時候,會等待用戶來輸入一個字符。
條件運算、條件表達式
a>b?a:bif條件
if的條件不一定是條件表達式為true,也可以是一個常量只要不是0,就可以的。
for
使用for循環的時候,如果3個判斷條件沒有時,也要要分號隔開。
for(;(c = getchar())!='\n';)break、continue
break:是跳出、結束循環,continue:是繼續循環。break使用范圍,就是在while、do….while、for、switch。而continue是結束本次循環 ,只能在while、do….while、for中使用,如果在while和do…while中使用,遇到continue會直接回到while后面的判斷,而執行for的時候就直接到for循環的第三個條件表達式。
判斷是否是素數
素數又稱質數,是指不能被其他的整數整除的自然數,其算法思想:用n去依次除以2~~n-1之間的每一個數,如果每次整除,則n是素數;只要有一次實現整除,則判斷不是質數,這個就是優化,沒必要一直看到底。
int n,i,flag;i = 2;flag = 0;n = 0;printf("請隨便輸入一個數:\n");scanf("%d",&n);for(i=2;i<=n-1;i++){if(n%i==0){flag =1;break;}}if(flag==1){printf("這個數不是質數");}else{printf("這個是質數");}數組
c語言中的數組長度不可以用變量去定義。
scanf函數
利用scanf輸入數據,一次數據輸入的結束是通過,空格,Enter,Tab 來結束一次,特別是在循壞中。
getchar()方法
這個方法是用來輸入字符的,并且返回這個字符的ascll編碼,需要注意這個方法每次輸入只能是一個字符,如果輸入多個,則只接收第一個字符,另外,如果多個字符輸入在一行,它的結束標志,就是回車,如果每輸入一個字符換行,那么連續兩次回車,就是結束標志。此外它比scanf輸入字符好,因為空格它同樣能處理,而scanf不行,它會當做結束符。
字符數組
char a[10]={'a''b''c''d'};如果字符數組的長度大于字符個數,那么系統默認會給其他數組元素為'\0'如果你在定義的時候,指定字符,那么可以不顯示指定字符數組的長度,編譯器會自動知道。字符串
c語言的字符串是指有限個組成的字符序列,它是以字符數組的形式存放,并且以’\0’作為字符串的結束標志。
char s[10] ={"hello"}如果字符數組的長度大于字符個數,那么系統默認會給其他數組元素為’\0’
處理字符數組時候,一旦遇到’\0’就表示字符串已經結束,如果字符串有多個’\0’,那么會認為在第一個’\0’之前的是有效字符。
字符串和字符數組最顯著的區別,就是字符數組中,如果數組長度等于字符個數,那么是不需要添加’\0’
在計算字符串的長度時,‘\0’是不參加計算的。
如果你在定義的時候,指定字符,那么可以不顯示指定字符數組的長度,編譯器會自動知道。
只要字符串沒有字符,那么系統會自動加上’\0’
如果你一直給字符串賦值,那么strlen是變的,這個一定要在后面注意,這點和java是不一樣。
字符串的輸入輸出
char a[20];char b[20];scanf("%s",a);//使用字符控制符去輸入,字符串必須是存放在字符數組中printf("%s",a);//打印的時候也是直接數組名gets(b);//傳入數組名,這種方法和上面比,每次只能輸入一個字符串,上面可以是多個。puts(b);//輸出完成后,會自動換行。注意如何利用scanf輸入多個字符串:
scanf("%s%s",a,c);一般的在scanf遇到一個%s,就是一次,千萬不能理解這個是一次輸入兩個,那就不對了,不要看他們是同一行。
字符串處理函數
char c1[80]={"sdada"};char c2[80]={"hsdkjass"};int i =0;//strcat(c1,c2);//將后面的字符串連接到前面來//后面的字符串可以是數組名,//也可以是字符串常量,但是字符串1必須是字符串數組名。//strcpy(c1,c2);//將后面的字符串復制到前面字符數組//后面的字符串可以是數組名,//也可以是字符串常量,但是字符串1必須是字符串數組名。//c1="sdasda";錯誤的//c1 = c2;錯誤的//int r = strcmp(c1,c2);//字符串比較函數//返回一個整數值,如果是0,代表兩個字符串相等//如果是正整數,代表前面字符串大//如果是負整數,代表前面的字符串小。//比較的實質,是從開始比較每一個字符的ascll//這兩個參數可以是字符數組或者字符常量//兩個字符串之間比較絕對不可以用> < == !=int t = strlen(c1);//返回字符數組的實際長度不包含結束標識符。//sizeof是返回參數的內存空間,也就是字節數。//該方法的參數可以是字符數組或者字符常量指針
程序運行時,所有的程序和數據都是放在內存中,內存是以字節為單位的連續的存儲空間,每一個內存都有一個編號,稱為內存地址。
一個字節就是一個存儲單元。
變量的地址是由編譯器動態分配的,對用戶是無關的。
指針:就是指向某個對象(可能是簡單變量、數組、函數)所占用的存儲單元的首地址,這里說明一下,一個對象,開辟的空間一定是連續的,所以,指針就是指向這個連續空間的首地址。
指針變量:存放變量地址的變量。
訪問類型
直接通過變量名來訪問。
先找到存放該變量的地址的變量,先找到地址,在訪問。
指針變量定義
int *i_pointer;//表示指向整型變量的指針變量。其中* 表示定義指針變量,前面的類型,也稱基類型,表示指針變量所指向的變量的類型。
指針變量只能指向定義時所規定類型的變量。
不可以將任何非地址的值,賦給指針變量,除了0(NULL)必須是大寫。
int *p;*p = 0;*p =NULL;指針變量定義好了之后,必須要初始化,否則變量值不確定。
指針初值,可以賦3種形式
*是間接訪問運算符,它是先訪問指針變量,然后在訪問它指向的變量的值。
指針變量的算術運算。
指針p+n,是指指針p原來指向的數據單元格之后的第n個數據單元格,而數據單元格和數據類型有關。
在這里,我要說明一下,數據存儲單元和內存單元的對比。
數據存儲單元格是人們簡化內存單元格的。
int *p;int a;p=&a;//假如a的地址是2000,則p+1 = 2004//原因int的數據類型占4個字節所以在這,你就要理解指針變話p++,就是使p指向下一個空間。
指針的比較
在同一段連續的存儲空間,如果p的地址值小于q的地址值,那么結果為1,反之為0。
指針和一維數組關系
數組名就是指針,是數組的首地址,這個叫做靜態指針。
int a[10];int *p;p =a;//p = &a[0]兩種等價根據指針運算p+1,就是指向數組中的下一個元素。
利用指針遍歷一維數組的兩種方法
for(i=0;i<5;i++){scanf("%d",p+i);//根據i的變化,改變指針指向的地址}for(i=0;i<5;i++){printf("%d",*(p+i));}for(p=a;p<a+5;p++){scanf("%d",p);//指針初始值指向數組的首地址,指針的地址范圍應該是控制數組首地址加上數組的個數,自增改變指針的地址。}for(p=a;p<a+5;p++){printf("%d",*p);}在一維數組中
a[i] =p[i] = p+i = a+i//都表示是指向某一個元素2維數組指針
從二維數組來看,a是二維數組名,a就代表了整個二維數組的首地址。a+1代表第一行。
a[0]+1,就代表第一列。
故:
//在這里,我們把對二維數組的處理,當成多個1維數組來處理。
在二維數組有兩個概念
- 行地址前就加*就變為列地址。
- 列地址前加&就變為行地址。
- 只有在列地址前加*才能訪問該二維數組的值。
二維數組的指針變量
int a[2][2];int (*p)[2];//指針變量的括號一定不能少p =a;int i,j;for(i =0;i<2;i++){for(j = 0;j<2;j++){scanf("%d",(*(p+i)+j));}}for(i =0;i<2;i++){for(j = 0;j<2;j++){printf("%d",*(*(p+i)+j));}}字符串指針
用指針變量操作字符串,指針變量指向的是字符串的首地址,也就是第一個字符地址。
char str[]="helloworld";char *p;//定義字符串指針p = str;//指向字符串的第一個字符的首地址int i = 0;for(i = 0;*p!='\0';p++){printf("%c",*p);printf("%s",p);//注意這種操作打印字符串是通過指向第一個指針的*地址*,這里就不是值了。一直到字符串結束,這種比較方便,后面使用的比較多。}字符串指針變量使用的注意點
char c1[10]="hello";char *pa;pa="hello"//表示指針變量指向的是字符串的第一個字符的首地址pa+2//指向字符串的第3個字符地址,指針變量可以指向字符串的任意位置,可以隨意改變指針變量的值c1作為字符串的數組名,可以作為首地址,可以進行加減,但是不能賦給c1,因為數組名是地址常量,不可以改變。(這點和前面使用一樣,需要注意)函數返回值是指針
定義函數,返回類型是指針。
定義類型
數據類型 * 函數名 (參數表) int *max(){int i = 0;int k = 0;static int data[]={1,2,34,9,0,17,8,7};for(i=0;i<8;i++){if(data[i]>data[k]){k = i;}}return &data[k]; }void test19(){int *p;p = max();//需要定義的指針變量去接收函數返回值,這里定義的指針變量需要和函數定義的返回類型一致。printf("%d",*p);}指向函數的指針
指向函數的指針,實際上就是函數執行的入口,函數名就代表中該函數的入口地址。
數據類型 (* 指針變量名) (參數表)對函數的調用
(* 指針變量名) (實參)例子:
int max1(int data[],int n){int i = 0;int k = 0;for(i=0;i<n;i++){if(data[i]>data[k]){k = i;}}return data[k]; }void test20(){int a[4] ={2,9,8,0};int (*p)(int a[],int n);//定義指針函數int m = 0;p = max1;//在此之前,你需要申明一下max1函數,這里我申明了指向函數的入口m = (*p)(a,4);//執行函數printf("%d",m);}二級指針
定義:一個指針變量存放的是另一個指針變量地址。
int i = 78;int *p;int **pp;//定義二級指針p = &i;pp = &p;printf("%d",i);printf("%d",*p);printf("%d",**pp);指針函數
定義: 數組中的每一個元素都是指針類型。
char *a[100]={"hello","world"};int i = 0;for(i = 0;i<2;i++){printf("%s",a[i]);//a[0]就是指向第一個數組元素的(首地址)指針,所以直接打印字符串//在前面說過,如果指針指向的是字符串的首地址,打印出來,則是整個字符串}數組指針
定義:指向整個數組的指針。
int a[4]={1,2,3,4};int (*p)[4];p = a;//這個是指向整個數組的指針,這里注意區分之前用的多的是指向數組的第一個元素的指針。int a[2][3]={1,2,3,4,5,6};int (*p)[3] = a;//這里的指針是數組中存在每一個元素首地址的指針集合,而這里每一個元素換成一行的首地址,這里需要重點理解一下。為什么可以指向一個二維數組呢,原因很簡單,你可以這樣理解,二維數組其實,我們可以看成2行的1維數組,p[0]就是指向1,2,3的首地址1,p[1]就是指向2,3,4的首地址2,然后p[0]+2,就是指針移動指向3。printf("%d",*(p[1]));printf("%d",*(*(p+1)+1));//訪問第二行的第二個元素。指針tip
在前面我們說過,數組名是靜態指針,不可以進行自加自減,但是可以執行a+1等運算操作,注意一下。
結構體
我們前面學習了,可以利用數組進行同一種數據類型的處理,而我們也是有可能把不同的數據類型作為一個整體,這時,就可以選用結構體來處理這種數據。
結構體作為一種數據結構,是不太方便好去遍歷,我們可以通過鏈表去實現對結構體的遍歷。鏈表是可以通過結構體去實現的。
struct date{int year;int months;int days;};struct date birth;//定義一個結構體date的變量//需要注意的是定義結構體類型,本身不占用存儲空間,//只是說明了結構體組織形式,只有定義結構體;變量,才占用空間。//在本例中,結構體占的空間,就是3個int所占空間之和。struct date birth1,birth2,birth3//定義多個結構體變量,用逗號隔開。struct date{int year;int months;int days;} birthday;//可以在定義結構體類型時,一起定義結構體變量。下面這是我們處理結構體定義常用方法。利用typeof定義新的結構體類型名代替定義的結構體類型名。
typedef struct date{int year;int months;int days;} Date;Date birthday;//這樣定義結構體變量就簡單,也好記。struct date birthday兩種等價結構中定義中,可以嵌套結構體變量。
typedef struct date{int year;int months;int days;struct birthday1;} Date;結構體變量的成員引用操作
.是結構體成員運算符,在所有優先級中是最高的。
struct StudentDate{int year;int month;int day;};struct Student{int num;char name[20];char sex[10];float score;struct StudentDate birthday;};struct Student s;//定義結構體變量scanf("%d",&s.num);//如果直接是結構體//的成員,直接通過.運算符來進行操作printf("%d",s.num);scanf("%d",&s.birthday.year);printf("%d",s.birthday.year);//如果是內嵌結構體成員,//則需要通過外部的結構體變量去引//用內部結構體變量的成員,這里需要注意內部結構體變量已經申明在外部結構體中,不需要在定義了。結構體變量的初始化
struct StudentDate{int year;int month;int day;} a={1996,9,10};struct StudentDate{int year;int month;int day;};struct StudentDate a ={199,9,10};//定義結構體變量并賦值- 一定不能在結構體內部初始化。
- 賦值的時候一定要和結構體中定義的順序一致。
- 如果結構體中有內嵌,初始化和外部結構體一起初始化,按照順序即可。
結構體與數組
結構體中成員可以是數組類型
struct student{int a[10];};struct student s;scanf("%d",&s.a[1]);printf("%d",s.a[1]);結構體數組,即該數組中每一個元素都是結構體類型。
struct student{int a[10];};struct student s[3];//定義了一個包含3個元素//的數組,并且每一個元素都是結構體類型scanf("%d",&s[2].a[1]);printf("%d",s[2].a[1]);結構體數組初始化:
struct student{int a[10];} s[3]={{12},{22},{4}};結構體如何訪問數組成員
這里演示的是通過結構體指針去訪問,通過結構體變量訪問比較簡單,自行看。
struct Student {int num;char name[20];float score[5]; };p->score[0]結構體與指針
結構體鏈表
結構體成語可以指向本結構體類型的指針,可以用這個來構造比較復雜的數據結構體,鏈表。
鏈表是由稱為節點的元素組成,節點多少根據需要來定。
每一個節點包含:
鏈表結構特點:鏈表有一個首指針,它指向鏈表的第一個節點,最后一個節點稱為 “表尾”,表尾節點的指針為null。
動態內存分配
malloc:從內存中申請一塊指定字節大小的連續空間,返回該存儲地址的首地址作為函數的返回值,如果申請失敗,說明沒有足夠的空間可以分配,返回空指針。
int *p;p = (int *)malloc(sizeof(int));//通過該函數動態申請了一個int類型大小if(p!=null){*p = 23;}else{exit(1);//exit是系統標準函數,作用是關閉//所有打開文件,并終止程序執行。參數為0是正常結束,非0//表示不正常結束。}由于該函數返回的是void類型的指針,所以需要進行強制類型轉換,轉換為指針變量所應該指向的數據類型。
內存釋放
free()函數。
注意點:
共用體
有時,我們希望在不同的時刻把不同的類型數據存放到同一個內存單元中。
共用體的定義
union un{float f;int i ;char c;};//定義共用體union un u;//定義共用體變量union un1{float f;int i ;char c;}u;//定義共用體變量和類型注意點:
共用體的訪問對象
通過.運算。
u.c = 'a';如果是定義的是指針,那么同樣可以通過—>去訪問對象。
- 由于共用體各個成員都共用一段存儲空間,所以在任意的時刻,只能有一種數據類型存放在共用體變量中,也就是說任意一個時刻,只有一個成員有意義。
- 在引用共用體變量時,必須保證其存儲類型的一致性,在一次程序運行時,一個成員操作了申明類型,在下一次中,還必須是這種類型。
- 共用體不能作為函數參數
- 共用體不能初始化,原因很簡單,如果初始化的話,那不就是說他們同時有意義,這不符合共合體的使用。
結構體和共用體的聯合使用
共用體可以出現在結構體中,結構體也可以出現在共用體中。
union un{int fivescore;float hunscore; };struct Student{int num;char name[20];char sex;int type;union un scrore;//這里將共用體定義在結構體中,需要定義共用體變量。(如果這里是定義結構體,那么這里就需要定義結構體變量) };p1->scrore.hunscore = hunscore1;//訪問內部共用體變量的時候,就需要注意,定義結構體指針,通過—>來訪問結構體的變量,因為這時得到的是共用體的變量,通過共用體變量名訪問成員,就必須是.運算符。枚舉
枚舉類,一個變量在很小的范圍內取值,則可以使用枚舉類。
enum Bool{Flase,True};//定義枚舉類型enum Bool bool;//定義枚舉變量enum Bool1{Flase1,True1} bool1; //在定義枚舉類型和枚舉變量printf("%d",True);//打印枚舉量的值,雖然定義和結構體很類似,但是訪問成員不是通過.運算。注意點:
- 枚舉元素是常量,有固定的數值,按枚舉的順序分別是 整數0,1,2,3;不能被用作變量,即不可以出現在賦值號的左邊。
- 不能有兩個元素相同的枚舉元素,枚舉元素也不能與其他變量同名。
- 枚舉元素作為常數處理,遇到枚舉元素,編譯器會將其中第一個元素賦值為0,然后依次疊加。自己可以修改為枚舉元素指定值,然后排在該枚舉元素后面的值,將自動一次疊加1。
typedef
用于用戶自己定義類型說明符。
typedef int INT;INT a = 5;//等價于int a =5typedef char NAME[20];NAME a1;//等價于 char a1[20];typedef struct Student{int num;float score;} S;S student;//等價于struct Student studenttypedef char *p;p p1;//等價于 char * p1這個使用你只需要,找到原始的元素定義的變量,直接用這個變量來簡化申明你自己定義的變量。
函數的申明與調用
函數聲明
c語言編譯,是從上到下,如果被調函數不在調用函數之前,則必須顯示申明,否則報錯。
函數類型 被調函數名(形參表列)//這種必須包括形參類型、變量名函數類型 被調函數名(形參類型表列)//這種只是形參類型,沒有變量名有些標準的庫函數,只需要導入頭文件即可。
參數傳遞
分類:
當形參為簡單變量時,在函數調用過程中,數據只能由實參傳給形參,而不能由形參傳回給實參,這種數據傳遞方式是單向,無論形參如果修改值,都不會影響實參的值。
數組作為參數傳遞:
局部變量、全局變量
局部變量:作用域僅限于函數內有效,離開該函數則沒有用。
- 在參數傳遞時,形參就是該調用函數的局部變量。
- 在不同的函數中,可以使用相同的變量名,互相不干擾。
全局變量:是指定義在函數外的變量,作用從定義的位置到本源程序文件尾。
變量的存儲類別
變量存儲方式:
變量存儲類別
static變量。又稱之為靜態變量。在函數局部定義中的變量,函數執行,該值仍然保留,等待下次該函數執行,除非該函數在也不執行,就釋放。
靜態變量在編譯時,只賦初值一次,賦值為0。而自動變量,每次執行完函數,都會重新賦值。自動變量未賦值,它的值是不確定的。
雖然靜態變量的值,函數執行結束,變量空間未釋放,但靜態變量不可以被其他函數調用。
寄存器變量。如果一個函數頻繁的使用某個變量計算,那么就可以使用寄存器變量。寄存器變量,只能給自動變量和形參定義,不可以將全局、靜態變量定義為寄存器變量。由于計算機的寄存器數目多,所以不宜定義太多寄存器變量。
extern(外部變量),這個可以類比是全局變量,但是全局變量是在該定義之后才可以使用該變量,那么在之前使用,則需要用extern申明,就可以當成全局變量使用,否則會產生語法錯誤。
總結
以上是生活随笔為你收集整理的《C语言程序设计教程》(一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: snowy框架
- 下一篇: Ingress暴露服务的方式