C語言簡介
發展史:BCPL -> new B -> C -> Minix -> Linux -> gcc
C語言誕生: 1970年~1973年,在肯.湯姆遜和丹尼斯.里奇(影響大)主導下編寫完成,歸屬美國貝爾實驗室
C語言的誕生專門用于編寫操作系統,所以天生適合一些硬件編程,也以速度快著稱,也非常適合實現數據結構和算法
由于出現時間過早,也沒想到普通人也能使用C語言編程,因此存在著很多缺陷,但是前輩已經總結了一些避免陷阱的經驗
C語言三劍客:《C語言陷阱與缺陷》、《C指針》《C專家編程》
C語言語法很自由,自由也意味著危險,自由源于自律語法標準:C89語法標準,也是gcc默認的語法標準C99語法標準,對C語言的擴展和增強C11語法標準,全新的升級
一、第一個C語言程序:helld world
#include<stdio.h>
開頭#預處理程序員寫的代碼不是標準C代碼,需要一段程序進行翻譯成標準C代碼,負責翻譯的程序叫做預處理器,翻譯的過程叫預處理,被翻譯的代碼叫做預處理指令,以#開頭的都是預處理指令#include 的功能就是把一個頭文件導入到當前文件夾中#include<>:從系統指定的目錄下加載xxx.h#include"":先從當前目錄下加載xxx.h,如果找不到,再從系統指定目錄找stdio.h 標準輸入輸出庫函數頭文件:以.h結尾的文件,里面存儲的是一些輔助性的代碼,絕大多數都是函數的聲明源文件:以.c結尾的文件,里面存儲的是功能性代碼C語言標準委員會為C語言以函數的形式提供了一些基礎的功能,這些函數都會封裝在libc.so庫中很多頭文件負責對libc.so庫中的代碼進行聲明,stdio.h就是其中一個string.h stdlib.hint main()C語言以函數的形式來管理代碼,是管理代碼的最小單位,一個函數就是一段代碼的集合main函數是C程序的主函數,是整個C程序的執行入口和出口,有且只有一個int 是一種數據類型,表示函數的返回值類型是一個整數main函數的返回值返回給操作系統,main函數是由操作系統所調用的,反映了該程序是如何結束的,通常有三種:正數 出現異常(別人的錯誤)0 一切正常負數 出現錯誤(自己的錯誤)echo $? 可以獲取上一個程序的返回值
{printf("hello world");return 0;
}printf/scanf都是標準庫中的函數,負責輸入輸出數據,用來調試程序
轉義字符:鍵盤上一些沒有的符號,用一些特殊的字符來表示,這些特殊的字符就是轉義字符,\n就是其中之一。\n 換行\t 制表符,用于對齊數據\r 光標回到行首\a 鈴響\b 退一個字符%% 表示%\\ 表示\
C語言中以分號作為一行代碼的結束標注,使用{}來劃分區域
二、編譯器
把人能看懂的代碼組成的文件,翻譯成計算機能看懂二進制文件,由預處理器、編譯器、鏈接器組成。
gcc是HNU社區為了編譯Linux代碼而開發的一款免費的編譯器,默認采用C89語法標準,-std=gnu99可以設置C99語法常用的參數:-E 只顯示與處理的結果-c 只編譯不鏈接-o 指定輸出結果的名字-I 指定頭文件的加載路徑-S 進行匯編,生成匯編代碼-l 指定要使用的庫文件-Wall 盡可能多的產生警告-Werror 把警告當錯誤處理-std 指定編譯語法-D 命令行定義宏
三、C代碼變成可執行程序的過程
1、預處理:把源文件翻譯成預處理文件 一般用于查看宏定義的替換結果,檢查宏函數gcc -E code.c 顯示預處理處理的結果 gcc -E code.c -o code.i 生成以i結尾的預處理文件
2、編譯:把預處理文件翻譯成匯編文件 理解C/C++代碼的底層工作原理 函數重載原理gcc -S code.i 生成以.s結尾的匯編文件
3、匯編: 把匯編文件翻譯成2進制的目標文件 生成代碼庫、靜態庫、共享庫gcc -c code.s 生成以o為結尾的目標文件
4、鏈接:把若干個目標文件合并成一個可執行文件 多文件編程的基礎gcc code.o a.o b.o c.o ... 默認生成一個a.out的可執行文件
四、不同的C文件類型
.h 頭文件.h.gch 頭文件的編譯結果,它會被優先使用.c 源文件.i 預處理文件.s 匯編文件.o 目標文件.a 靜態庫.so 共享庫
五、數據的儲存單位
Bit 比特 一個二進制位,只能存0或者1,計算機中存儲數據的最小單位
Byte 字節 8個二進制位,計算機中存儲數據的基本單位
KB 1024字節
MB 1024KB
GB 1024MB
TB 1024GB
PB 1024TB
六、數據類型
為什么要對數據分類:1、現實生活中的數據都是自帶類別屬性2、對數據進行分類可以節約儲存空間,提高運行的效率C語言中的數據分為兩大類:自建(程序員自己設計,例如:結構、聯合、類)、內建(C語言中自帶)
可以使用sizeof計算類型的字節數大小 sizeof(signed long)
整型:signed 有符號signed char 1 -128~127signed short 2 -32768~32767signed int 4 正負20億signed long 4或8(由操作系統位數決定)signed long long 8 以9開頭19位數字的整數注意:signed不加就代表加unsigned 無符號unsigned char 1 0~255unsigned short 2 0~65535unsigned int 4 0~40億unsigned long 4或8(由操作系統位數決定)unsigned long long 8 1開頭的20位正整數注意:由于定義無符號的數據是比較麻煩,標準庫把這些無符號的類型重新定義成以下的類型:需要包含一個頭文件<stdint.h>uint8_t uint16_t uint32_t uint64_t浮點型:float 4double 8long double 12或者16(根據系統)注意:采用科學計數法存儲,二進制與真實的數據之間需要翻譯轉換,因此浮點型運算速度就比整型要慢,編程時盡量采用整型小數點后六位有效判斷float類型的數據是否是0float num;if(num 0 <= 0.000001 || num >= -0.000001)字符型:char 字符其實就是符號或者圖案,但是,在內存中存儲的是整數,需要顯示字符時,會根據ASCLL碼表中對應關系來顯示相應的符號或者圖案。0 '' 特殊字符,表示什么都沒有48 '0'65 'A'97 'a'
布爾型:由于先有了C語言后才有了bool類型,所以C語言不可能有真正的布爾類型,使用stdbool.h頭文件,該文件是對布爾類型做的模擬bool true false
七、變量與常量
什么是變量:程序運行期間數值可以發生改變的叫做變量,相當于存儲數據的盒子。
定義: 類型 變量名;int num;取名規則:1、只能是由字母、數字、下劃線組成2、不能以數字開頭3、不能與32個C關鍵字重名4、見名知意【功能、類型、作用域...】
使用:賦值:num = 100;參與運算:num*10;注意:C語言中變量的值默認是隨機的,為了安全起見,一般都初始化為0變量的輸入輸出:int printf (const char *format,...);功能:輸出數據format: "雙引號包含的格式信息(提示信息+占位符)"...: 要輸出的變量的列表返回值: 輸出的字符的個數int scanf(const char *format,...);功能:從鍵盤輸入數據foemat:"由雙引號包括的格式信息(占位符)"...:要接收的變量的列表返回值:成功輸入的變量個數注意:scanf需要的是變量的類型、變量的地址,變量的地址 = &變量名練習1:定義各種類型的變量并初始化,使用scanf輸入,使用printf顯示
#include <stdio.h> int main ( int argc, const char * argv[ ] )
{ char num_c= 0 ; short num_s= 0 ; int num_i= 0 ; long num_l= 0 ; long long num_ll= 0 ; unsigned char num_uc= 0 ; unsigned short num_us= 0 ; unsigned int num_ui= 0 ; unsigned long num_ul= 0 ; unsigned long long num_ull= 0 ; float num_f= 0 ; double num_d= 0 ; long double num_ld= 0 ; printf ( "請輸入num的值:" ) ; scanf ( "%hhd%hd%d%ld%lld" , & num_c, & num_s, & num_i, & num_l, & num_ll) ; scanf ( "%hhu%hu%u%lu%llu" , & num_uc, & num_us, & num_ui, & num_ul, & num_ull) ; scanf ( "%f%lf%LF" , & num_f, & num_d, & num_ld) ; printf ( "char=%hhd,short=%hd,int=%d,long=%ld,longlong=%lld" , num_c, num_s, num_i, num_l, num_ll) ; printf ( "uchar=%hhu,ushort=%hu,uint=%u,ulong=%lu,ulonglong=%llu" , num_uc, num_us, num_ui, num_ul, num_ull) ; printf ( "float=%f,double=%lf,longdouble=%LF" , num_f, num_d, num_ld) ;
}
類型占位符:C語言通過占位符來傳遞變量的類型 signed %hhd %hd %d %ld %lldunsigned %hhu %hu %u %lu %llu%f %lf %LF 什么是常量:程序運行期間數值絕對不能改變的叫常量字面值常量100 'a' "hello world"枚舉常量宏常量100 int(默認int)100l long100ll long long100u unsigned int100lu100llu3.14 默認double類型3.14f float
八、格式化輸入輸出
%nd 顯示n個字符寬度,如果不夠則補空格,右對齊
%-nd 顯示n個字符寬度,如果不夠則補空格,左對齊
%0nd 顯示n個字符寬度,如果不夠則補0,右對齊
%n.mf 顯示n個字符寬度,小數也算一位,不夠則補空格,m表示小數點后的位數(四舍五入)
%g 不顯示小數點后多余的0
九、運算符
自變運算符:前后++/--,使變量的值自動加1或者減1前自變 立即有效后自變 下一句語句生效注意:不要再一行語句中多次使用自變運算符算數運算符+ - * / %/ % 除數不能為0,會造成浮點數例外,核心已轉儲,程序直接死掉整數/整數 結果沒有小數部分關系運算符> < >= <= == !=比較的結果是0(假)或1(真),運算結果可以繼續參與運算 if(a>b==0)int num = 500;0<num<100;永遠為真邏輯運算符&& || !比較對象轉換為邏輯值,0轉換成假,非0轉換為真A && B 一假為假A || B 一真為真!A 求反&&、|| 具有短路特性:當左邊的表達式可以確定整個表達式的結果時,右邊不進行計算三目運算符運算對象有3個A?B:C 先判斷A的表達式真假,若為真執行B,假執行C注意:該語句不能使用流程控制語句,因為他必須要有運行結果賦值運算符= += -= *= /=num+=100 <=> num=num+100位運算符& | ~ ^ >> <<后邊講
十、類型轉換
自動類型轉換:只有相同類型的數據才能進行運算,不同類型數據自動轉換成相同類型再進行計算:轉換規則(以不丟失數據為基礎,適當犧牲一些空間)1、字節少的向字節多的轉 考慮優先級2、有符號向無符號的轉3、整型向浮點型轉強制類型轉換:(想要轉成的類型)原數據;int num;(short)num;注意:有丟失數據風險,慎重使用
十一、分支語句
if(表達式) //單分支
{表達式為真,執行此處代碼
}if(表達式) //雙分支
{表達式為真,執行此處代碼
}
else
{表達式為假,執行此處代碼
}if(表達式1) //多分枝
{表達式1為真,執行此處代碼
}
else if(表達式2)
{表達式2為真,執行此處代碼
}
else if(表達式3)
{表達式3為真,執行此處代碼
}
else
{當表達式123都為假時執行此處代碼
}
作業
作業1:輸入三個整數(鍵盤),從大到小顯示。
#include <stdio.h> int main ( int argc, const char * argv[ ] )
{ int a[ 3 ] ; int i, k, j; printf ( "請輸入三個整數" ) ; for ( i= 0 ; i< 3 ; i++ ) { scanf ( "%d" , & a[ i] ) ; } for ( i= 0 ; i< 3 ; i++ ) { for ( j= i+ 1 ; j< 3 ; j++ ) { if ( a[ i] < a[ j] ) { k= a[ i] ; a[ i] = a[ j] ; a[ j] = k; } } } for ( i= 0 ; i< 3 ; i++ ) { printf ( "%d" , a[ i] ) ; } return 0 ;
}
作業2:輸入一個年份,判斷是否時閏年
#include <stdio.h> int main ( int argc, const char * argv[ ] )
{ int year; printf ( "請輸入年份" ) ; scanf ( "%d" , & year) ; if ( year % 400 == 0 ) { printf ( "是閏年" ) ; } else if ( year % 4 == 0 && year % 100 != 0 ) { printf ( "是閏年" ) ; } else { printf ( "不是閏年" ) ; } }
作業3:輸入一個年份與月份,判斷該月多少天
#include <stdio.h> int main ( int argc, const char * argv[ ] )
{ int year, mon; printf ( "請輸入年份" ) ; scanf ( "%d" , & year) ; printf ( "請輸入月份" ) ; scanf ( "%d" , & mon) ; if ( year % 400 != 0 && year % 4 != 0 ) { if ( mon== 2 ) { printf ( "該月28天" ) ; } else if ( mon== 4 || mon== 6 || mon== 9 || mon== 11 ) { printf ( "該月30天" ) ; } else if ( mon== 1 || mon== 3 || mon== 5 || mon== 7 || mon== 8 || mon== 10 || mon== 12 ) { printf ( "該月31天" ) ; } else { printf ( "輸入錯誤" ) ; } } else { if ( mon== 2 ) { printf ( "該月29天" ) ; } else if ( mon== 4 || mon== 6 || mon== 9 || mon== 11 ) { printf ( "該月30天" ) ; } else if ( mon== 1 || mon== 3 || mon== 5 || mon== 7 || mon== 8 || mon== 10 || mon== 12 ) { printf ( "該月31天" ) ; } else { printf ( "輸入錯誤" ) ; } } return 0 ;
}
作業4:輸入一個三位整數,判斷是否是水仙花數
#include <stdio.h> int main ( int argc, const char * argv[ ] )
{ int g, s, b; int num; printf ( "請輸入一個三位整數" ) ; scanf ( "%d" , & num) ; b= num/ 100 ; s= num% 100 / 10 ; g= num% 10 ; if ( num>= 100 && num<= 999 ) { if ( num== g* g* g+ s* s* s+ b* b* b) { printf ( "是水仙花數" ) ; } else { printf ( "不是水仙花數" ) ; } } else { printf ( "請仔細審題" ) ; } return 0 ;
}
作業5:輸入一個成績,判斷該成績的等級
#include <stdio.h> int main ( int argc, const char * argv[ ] )
{ int cj; printf ( "請輸入成績" ) ; scanf ( "%d" , & cj) ; if ( cj< 0 || cj> 100 ) { printf ( "輸入錯誤" ) ; } else { if ( cj<= 100 && cj>= 90 ) { printf ( "A" ) ; } else if ( cj< 90 && cj>= 80 ) { printf ( "B" ) ; } else if ( cj< 80 && cj>= 70 ) { printf ( "C" ) ; } else if ( cj< 70 && cj>= 60 ) { printf ( "D" ) ; } else if ( cj< 60 && cj>= 0 ) { printf ( "E" ) ; } } return 0 ;
}