1.編譯程序
(1)gcc xx.c,他會默認生成一個a.out的可執行文件,在a.out所在目錄,執行./a.out
(2)gcc xx.c -o xx,生成一個xx可執行文件,注意不要命名成xx.c,這樣會覆蓋原先的xx.c文件內容
(3)gcc xx.c -o xx -g -Wall,-g -Wall的意思是開啟所有的語法警告,
(4)gcc只檢查語法錯誤,不會檢查邏輯錯誤
(5)每次修改完.c程序都必須要執行一次gcc
如果覺得gcc太麻煩,寫一個shell腳本
思路:
mygcc xx.c
(1)參數
(2)xx.c文件是否存在
(3)如果存在,rm ./a.out gcc xx.c
(4)如果gcc出錯,#判斷./a.out這個文件是否存在,exit
(5)./a.out
1 if [ $# -eq 0 ]
2 then
3 echo "gcc what"
4 elif [ $# -eq 1 ]
5 then
6 if [ -e $1 ]
7 then
8 if [ -f $1 ]
9 then
10 #是否是.c文件
11 if [ -e ./a.out ]
12 then
13 rm ./a.out
14 fi
15 gcc $1
16 if [ -e ./a.out ]
17 then
18 ./a.out
19 fi
20 else
21 echo "$1 is not a file"
22 fi
23 else
24 echo "no such file"
25 fi
26 else
27 echo "too much arguments"
28 fi
2.hello world程序
(1)
int main()
{
return 0;
}
(2)可執行程序一執行,就會去找一個叫做main函數,然后運行main大括號里面的語句
(3)一個.c文件有且只能有一個main的函數
(4)如果一個函數碰到return就代表這個函數運行結束,return后面的語句將永遠不會被執行
(5)如果是main函數,他可以將前面的int省略,return也是可以省略
(6)main(int argc,char *argv[])
(7)#include<stdio.h>是一個c語言標準輸入輸出庫
3.注釋
(1)//代表單行注釋
(2)/* /多行注釋,第一個/會與遇到第一個*/匹配
4.注釋使用情況
(1)注釋代碼
(2)解釋代碼
(3)寫清文件名,文件制作方,如果是某人:要寫清聯系方式
4.printf:打印函數
打印""里面的語句
\n:轉義字符,代表換行
5.代碼格式
main()
{
}
注意:每碰到一個{,就要換行,再來一個Tab鍵
6.常量
1>常量
(1)1,2,3,4:整型常量
(2)'a','b','c':字符常量
(3)1.2,2.4:浮點常量
(4)"hello world":字符串常量
(5)0xff1:地址常量
2>常量的特點
(1)常量不會改變
(2)常量不能作為左值
(3)8,const(只讀常量),define(宏常量)
7.地址
內存:字節:Byte是計算機存儲的最小單位
位:bit:一個字節占8位
1M=1024KB
1KB=1024Byte
1Byte=8bit
地址:是每一個字節所對應的編號
(中國===>每一個家庭(房子)===》門牌號)
(計算機===>字節========》地址)
8.進制
二進制:0~1 以0B,0b,
八進制:0~7 以0開頭,012
十進制:0~9
十六進制:0~15,0x開頭,0X
10:a,A
11:b:B
12:c:C
13:d:D
14:e:E
15:f:F
2,8,16進制===>10進制
12:1X101+2X100=12
0b0010:0X23+0X22+1X21+0X20=2
012:1X81+2X80=10
0x12:1X161+2X160=18
10進制===》2,8,16進制
12:1100=1X23+1X22
12/2=6...0 [1]
6/2=3...0 [2]
3/2=1...1 [3]
1/2=0..1 [4]
9.變量
1>變量的特點
(1)可以改變的量
(2)可以作為左值,也可以作為右值
2>變量的定義
在shell腳本里:變量名=值
在C語言里面:數據類型 變量名;
同時定義多個同種類型的變量:數據類型 變量1,變量2;
3>數據類型
整型數據類型:int
字符數據類型:char
浮點類型:float(單精度) double(雙精度)
float類型的變量是精確到7位
double類型的變量是精確到16位(具體根據編譯器定)
數據類型的作用
(1)標志著后面的變量具體是接收什么類型的值
(2)這個變量在內存當中占幾個字節
int:4
char:1
float:4
double:8
4>整型變量
(1)int value=8;
(2)int value;value=7;
5>字符變量
(1)char ch='c';
(2)char ch;ch='d';
6>浮點變量
(1)float f1=1.2;
(2)double f2=2.3;
7>變量的使用
int value;
value=8;
10.標識符的命名規范
硬性規范:
1>不能用數字開頭
2>只能由字母,下劃線和數字組成
3>不能與C語言關鍵字相同
建議的規范:
1>不能用拼音,多查字典
2>盡量使用駝峰numOfStudent,num_of_student
3>見名知義
10.printf具體的用法
1>
int a=6;
float b=9.8;
printf("a=%d,b=%f\n",a,b);
%d:占位符,是輸出整數
%c:占位符,是輸出字符
%f:占位符,是輸出浮點數
2>%m.nf
m<=n+1+整數實際部分的位數,m無效
m>n+1+整數實際部分的位數,m有效,左邊以空格補全
11.大端小端存儲法
小端法:低位上的數存儲在低的地址所對應的字節
大端法:低位上的數存儲在高的地址所對應的字節
用處:一般網絡傳輸內容的時候
0x0123456:小端
hston
0x56342301:大端
hntos
12.打印特殊字符
":\"
':\'或'
%:%%
\:\\
13.字符與ASCII編碼
1>字符是一個特殊的整型,占8位
2>記住的字符
'\0':0
'空格':32
'0':48
'A':65
'a':97
全球unicode編碼
14.scanf:scan formatter格式化輸入函數
1>基本用法
int a;
//&a:取a變量的地址
scanf("%d",&a);
printf("a=%d\n",a);
2>同時輸入多個變量
int a;
int b;
scanf("%d%d",&a,&b);
3>
%d:
%f:
%c:
%lf:輸入double類型的數據
%p:輸出變量的地址
注意點:
(1)scanf,后面必須是取變量的地址
(2)一個變量必須先定義出來,再進行scanf
(3)不要在scanf()里面做小動作
15.getchar()和putchar()
char ch;
ch=getchar();
putchar(ch);
16.數據類型轉換
1>隱式轉換:精度小的===》精度大的
char===>short int===>int====>float===>double
2>強制類型轉換
(數據類型)變量/常量
int a=9;
int b=8;
float c=(float)a/b;
printf("c=%f\\n",c);
0:+
1:-
1+(-1)=0;
0000 0000 | 0000 0000 | 0000 0000 | 0000 0001
+1000 0000 | 0000 0000 | 0000 0000 | 0000 0001
1000 0000 | 0000 0000 | 0000 0000 | 0000 0010
問題:如果是按照上面的格式去運算1+(-1)=-2,不符合事實邏輯
原碼:
反碼:正數的反碼與原碼相同;負數的反碼在原碼的基礎之上,符號位不變,后面依次取反(0變1,1變0)
補碼:正數的補碼與原碼,反碼相同。負數的補碼在反碼基礎之上+1
解決之道:
1: 0000 0000 | 0000 0000 | 0000 0000 | 0000 0001
-1:
原碼:1000 0000 | 0000 0000 | 0000 0000 | 0000 0001
反碼:1111 1111 | 1111 1111 | 1111 1111 | 1111 1110
補碼:1111 1111 | 1111 1111 | 1111 1111 | 1111 1111
0000 0000 | 0000 0000 | 0000 0000 | 0000 0001
+1111 1111 | 1111 1111 | 1111 1111 | 1111 1111
10000 0000 | 0000 0000 | 0000 0000 | 0000 0000
結論:
(1)數據在內存當中是以數據的補碼存在。
(2)數據是以補碼存在,原碼輸出
18.運算符
注意點:計算機只進行相同類型數據的運算,最后算出來的結果也與他們相同的數據類型
1>算數運算符
+:
-:
*:
/:
%:%左右兩個的數都必須是整數
++:
案例:
后綴++:
int a=9;
int b=a++;//b=a,a=a+1
printf("b=%d\na=%d\n",b,a);
前綴++:
int a=9;
int b=++a;//a=a+1,b=a
printf("b=%d\na=%d\n",b,a);
后綴--:
int a=9;
int b=a--;//b=a,a=a-1
printf("b=%d\na=%d\n",b,a);
前綴--:
int a=9;
int b=--a;//a=a-1,b=a
printf("b=%d\na=%d\n",b,a);
2>位運算
|:位或:有1就為1
案例:
3:0011
|5:0101
0111
&:位與:有0就為0
案例:
3:0011
&5:0101
0001
^:異或:只要不同就為1
案例:
3:0011
^5:0101
0110=6
~:取反運算:按位取反
案例:正數取反
3:0000 0000 | 0000 0000 | 0000 0000 | 0000 0011
~3:
補碼:1111 1111 | 1111 1111 | 1111 1111 | 1111 1100
反碼:1111 1111 | 1111 1111 | 1111 1111 | 1111 1011
原碼:1000 0000 | 0000 0000 | 0000 0000 | 0000 0100
案例:負數取反
-3:
原碼:1000 0000 | 0000 0000 | 0000 0000 | 0000 0011
反碼:1111 1111 | 1111 1111 | 1111 1111 | 1111 1100
補碼:1111 1111 | 1111 1111 | 1111 1111 | 1111 1101
~(-3):
補碼:0000 0000 | 0000 0000 | 0000 0000 | 0000 0010
<<:左移:
案例:正數
3:
0000 0000 | 0000 0000 | 0000 0000 | 0000 0011
<<2
0000 0000 | 0000 0000 | 0000 0000 | 0000 1100
案例:負數
-3:
原碼:1000 0000 | 0000 0000 | 0000 0000 | 0000 0011
反碼:1111 1111 | 1111 1111 | 1111 1111 | 1111 1100
補碼:1111 1111 | 1111 1111 | 1111 1111 | 1111 1101
<<2
補碼:1111 1111 | 1111 1111 | 1111 1111 | 1111 0100
反碼:1111 1111 | 1111 1111 | 1111 1111 | 1111 0011
原碼:1000 0000 | 0000 0000 | 0000 0000 | 0000 1100
:右移
案例:正數
3:
原碼:0000 0000 | 0000 0000 | 0000 0000 | 0000 0011
2
0000 0000 | 0000 0000 | 0000 0000 | 0000 0000
案例:負數
-3:
原碼:1000 0000 | 0000 0000 | 0000 0000 | 0000 0011
反碼:1111 1111 | 1111 1111 | 1111 1111 | 1111 1100
補碼:1111 1111 | 1111 1111 | 1111 1111 | 1111 1101
2:右移以符號位補全
補碼:1111 1111 | 1111 1111 | 1111 1111 | 1111 1111
反碼:1111 1111 | 1111 1111 | 1111 1111 | 1111 1110
原碼:1000 0000 | 0000 0000 | 0000 0000 | 0000 0001
3>關系運算符
:
<:
=:
<=:
==:
!=:
在計算當中,關系運算符構成的運算,我們可以看成一個事件,如果這個事件成立,其結果(邏輯結果【0/1】)1;如果事件不成立,其結果為0
4>邏輯運算符
事件1&&事件2:并且,事件1成立并且事件2也成立,整個邏輯結果才為1;否則,整個邏輯結果為0
事件1||事件2:或者,事件1成立或者事件2也成立,整個邏輯結果才為1;否則,整個邏輯結果為0
!事件:非,如果事件成立,邏輯結果1,!1,整個結果為0;否則,邏輯結果為1
進階:
事件1&&事件2:如果事件1不成立,就不會執行&&后面的運算
事件1||事件2:如果事件1成立,就不會執行||后面的運算
4>取地址運算符
&
案例:
int a;
printf(“a的地址=%p\n”,&a);
5>字節長度運算符
sizeof(數據類型/變量名)
6>三目運算符(條件運算符)
事件1?事件2:事件3
用法:如果事件1成立,就執行事件2,將事件2的運算結果作為整個事件的結果;
如果事件1不成立,就執行事件3,將事件3的運算結果作為整個事件的結果;
總結:
1>()===>單目====》算數=====》關系====》邏輯====》三目=====》賦值====》,
2>單目====》雙目=====》三目
19.三大執行流程
(1)順序執行流程
(2)條件執行流程
(3)循環執行流程
int a=8;
int b=7;
int c=a+b;
20.條件執行流程
1>
if(條件)
{
}
用法:如果條件成立,就執行{}里面的語句
注意點:
(1)如果{}不加,只會執行if下面語句的一行代碼
if(條件)
語句
(2)不管if下面執行幾條語句,請你用{},便于將來代碼調試
2>
if(條件)
{
語句體;
}
else
{
語句體;
}
3>
if(條件)
{
語句體;
}
else if(條件)
{
語句體;
}
4>
if(條件)
{
}
else if(條件)
{
}
else if(條件)
{
}
else
{
}
注意點:
(1)如果if語句有else,那么else必須放在最后,不可以放在if 和else if中間
(2)if語句可以嵌套
/*
練習:
1>輸入一個成績score,
0<=score<60:D
60<=score<85:C
85<=score<90:B
90<=score<100:A
用if語句實現
2>輸入一個你的工資,如果工資小于等于1000,那么所得的工資就是實際工資;如果工資大于1000,大于1000的部分需要繳納0.05的稅,求實際所得到的工資總額,使用三目運算符完成
*/
22.條件分支switch
/*
死人(王五)
案例1(根據張三握了他的手):張三;
案例2(根據喉嚨發黑,李四跟死者喝酒):李四
案例3(柯南脖子有嘞痕):王二麻子
案例4 (倉老師):王任;
*/
/*
switch(變量)//ch
{
case 常量1:
語句體1;
break;//跳出
case 常量2:
語句體2;
break;
case 常量3:
語句體3;
break;
default:
語句體4;
break;
}
用法分析:
看變量與下面的常量值那個相同,就執行對應的語句體,執行完之后跳出switch},繼而執行下面的語句
注意點:
(1)case后面的值必須是常量。
(2)case后面的值是唯一的,不能與其他case后面的值相同
(3)default可以沒有,也可有,有的話可以放在任意位置
(4)每一個case后面的語句都必須要有break
/*
輸入兩個整數,再輸入一個運算符,根據運算符的+ - * /,然后計算相應的運算結果,使用switch-case完成
*/
吸收輸入緩存流里面的回車殘留,
1>char ch;
scanf(“%c”,&ch);
2>getchar()
3>getc(stdin)
23.循環
whie(條件)
{
語句體;
}
/*
晚上作業:
打印如圖:
*/
24.do—while
do
{
語句體;
}while(條件);
25.for循環
for(表達式1;條件;表達式3)
{
語句體2;
}
分析:
【1】先執行表達式1,表達式1有且只執行一次;
【2】再去判斷條件是否成立;如果條件成立,就執行語句體2;
【3】執行完語句體2之后再去執行表達式3
【4】再從步驟2開始判斷
注意點:
(1);不能省略,也不能寫成,隔開
(2)表達式1,表達式2,表達式3都可以省略,但是;不能省略。如果三個表達式都省略,代表這個for循環是一個死循環
案例:
int i;
int sum=0;
for(i=1;i<=100;i++)
{
sum+=i;
}
26.break的用法
(1)break只能用在switch,while,do—while,for
(2)break是跳出整個循環,繼而執行下面的代碼
(3)當碰到break語句時,break下面的直到循環體}里面的代碼不會被執行
(4)break只跳出最近的一層循環
27.continue
(1) continue只能用在while,do—while,for
(2) continue是跳出一次循環,繼而執行下面的循環
(3)當碰到continue語句時,continue下面的直到循環體}里面的代碼不會被執行,但是for表達式3還會繼續執行
(4) continue只跳出最近的一層循環的一次循環
/*
判斷200~300之間的素數
素數:只能被1和他本身整除的數
如果是素數,就輸出該數
*/
28.數組
1>數組的定義
int array[4];
2>數組的初始化
//1.數組的初始化
int array1[6]={1,3,5,6,7,8};
//2.元素不足用0補全
int array2[6]={1,3,4};
//3.如果行號省略,根據后面元素的實際個數確定行號
int array3[]={1,2,3,5};
//4.
int array4['a']={1,2,3};
//5.
int array5[6]={[4]=8,[5]=7};
3>數組元素的訪問:數組名[下標]
0<=下標<數組大小
29.指針
指針:就是地址
1>指針的定義和初始化
int a;
int *p=&a;
int *q;
q=&a;
2>同時定義多個指針變量
int p1,p2;
不能這么寫:int *p1,p2;就代表p1是指針變量,p2是整型變量
3>二級指針:指針的指針
int a;
int *p=&a;
int **q=&p;
使用q訪問a:**q=8;
4>指針所占字節數
int *,char *,float *…
在32位機:4個字節
在64位機:8個字節
30.指針與一維數組的關系
數組名就相當于首元素的地址
int arr[4];
int *p=arr;
第i個元素的地址:arr+i==>&arr[i]===>p+i===>&p[i]
第i個元素:(arr+i)====>arr[i]===>(p+i)====>p[i]
區別:
1>arr不能自加,因為arr相當于一個int * const arr;
2>p可以自加
31.const關鍵的使用
constant,如果一個變量使用const修飾,代表這個變量屬性只讀,不可寫(不可改變)
const變量只能在定義的時候進行初始化
const int a;
int const a;
兩者效果一樣,
int a=9;
const int *p=&a;
int const p=&a;
如果const是寫在號的左邊,代表這個變量將來如果用p訪問變量的時候,內容只讀,這兩種寫法,效果一樣
int a=9;
int b;
int const p=&a;
如果const是寫在號的右邊,代表這個指針變量本身的內容只讀,不可更改
int a=9;
int b;
const int * const p=&a;
如果*左右兩邊都有cosnt,代表p所指向的內容只讀,p本身的內容只讀
/*
練習:定義一個整型數組,使用指針去對數組進行排序
練習:
int arr[5]={1,2,3,4,5};
請你將數組元素顛倒輸出,變成{5,4,3,2,1},不準使用第二個數組。
練習:使用指針交換兩個變量的值
*/
32.指針數組
//指針數組
//先算[],代表他是一個數組,再算*,代表這個數組所有的元素都是指針
int a,b,c;
int *p[3]={&a,&b,&c};
*(p[0])=7;
printf("a=%d\\n",a);
33.二維數組
1>
/*
二維數組:看成多個一維數組構成
*/
//2代表行數,3代表列數
//二維數組的定義
int arr[2][3];
//1.
int arr1[2][3]={{1,2,3},{4,5,6}};
//2.
int arr2[2][3]={1,2,3,4,5,6};
//3.
int arr3[2][3]={{[1]=3},{[2]=6}};
//4.
int arr4['a'][3]={1,2,3};
//5.行號省略,取后面算元素的個數,找到最近的數是列的倍數
int arr5[][3]={1,2,3,4};
//錯誤的,列號不能省略
//int arr6[5][]={1,2,3,4};
2>訪問二維數組元素
//數組名[行下標][列下標];
//0<=行下標<行數 0<=列下標<列數
// int arr6[2][3];錯誤
// arr[2][3]={1,2,4,5,6};
3>
/*
第i行首元素的地址:&arr[i][0]===>arr[i]===>(arr+i)===>arr+i
第i行j列元素的地址:&arr[i][j]====>arr[i]+j===>(arr+i)+j
第i行j列元素:arr[i][j]===>(arr[i]+j)====>(*(arr+i)+j)
*/
4>數組指針
//先算(p),代表p是一個指針變量,再算[3];代表這個指針變量將來指向一個大小為3的一維數組,數組指針,行指針
int (p)[3]=arr;
34.函數
1>函數定義格式
數據類型 函數名(數據類型 變量1,數據類型 變量2,......)
{
}
數據類型:[unsigned ]int ,char ,float ,double,void(空類型)
2>形參
形參:形式上的參數,在函數定義的時候存在
3>實參
實參:有實際意義的參數,在函數調用的時候存在
4>函數定義注意點:
(1)函數不能嵌套定義
(2)函數名不能與系統提供的函數名相同
(3)函數不能重復定義
(4)如果函數的數據類型是int,char,float。。。,那么這個函數必須要有return,return 后面的值的數據類型必須要與函數的數據類型保持一致
(5)如果函數的數據類型是void,那么函數可以有return,也可以沒有return,如果有return的話,return后面沒有數值
(6)函數定義時形參的個數,必須要與函數調用時實參個數相同
(7)形參變量的數據類型即使相同,也不能省略數據類型,比如:如下錯誤void sum(int a,b);必須要寫成void sum(int a,int b)
(8)形參個數可以是多個,沒有限制;形參變量的數據類型可以各不相同
5>函數調用:函數名();
6>return在函數中的作用
(1)函數結束的標志,當函數碰到return時,該函數return下面的語句不會被執行
(2)將return后面的值返回給函數調用者
7>函數的遞歸:函數自己調用自己
8>函數指針
//先算(p),代表p是一個指針變量;再算(),代表將來p這個指針執行一個沒有形式參數的函數;再看void,代表p指向的這個函數返回值是void類型
//函數名是函數的入口地址
void (p)()=test;
9>指針函數
//指針函數:就是函數的返回值是指針
//不要返回一個自動存儲類型的局部變量的地址
35.變量按作用域分
1>局部變量:定義在函數內部的變量叫做局部變量
2>全局變量:定義在函數外部的變量叫做全局變量
作用域只能決定訪問性
注意點:
如果全局變量和局部變量同名,局部變量會看不見全局變量的存在
變量按生存期分
靜態變量:
自動變量:
局部變量
1>靜態局部變量
2>自動局部變量
全局變量
1>靜態全局變量
2>自動全局變量
/*
1>利用函數求一個數組的最大值。
2>將萬年歷改成函數格式,對其進行合理(按模塊功能)的封裝
3>
(1)指針
一維數組
二維數組
函數
(2)
指針和變量關系
指針和一維數組
指針和二維數組
指針和函數
(3)
指針數組:
數組指針:
指針函數:
函數指針:
*/