標準C基礎知識筆記一
Linux就是用c和c++來編寫的,但是兩者有區別,如何區分呢
先C,再C++
vi xxx.c,其擴展名為.c
用c語言的格式來寫的,不是用腳本語言來寫的
.c文件是源程序,不是可執行文件
通過gcc來進行翻譯成相應的機器指令a.out文件
gcc xxx.c a.out
1\編輯vi xxxx.c===》可移植
2\編譯gcc xxxx.c a.out,編譯,連接產生可執行文件a.out
gcc -c xxxx.c xxxx.o(編譯)
gcc xxx.o 產生a.out(連接)
3\執行a.out===》已經生成某個平臺的機器碼==》不可移植
可執行文件的格式是不一樣的:PE\COFF\ELF
C語言第一課:
mkdir c1
1、編輯第一個c語言源文件
vi hello.c
main()
{
}
2、編譯gcc hello.c
3、執行./a.out
4、調整環境變量
echo $PATH
PATH=$PATH:.
5、執行a.out
vi .bashrc
編輯.bashrc文件
兩個方向C,C++;要分清哪個是C的,哪個是C++的
vi xxx.c保存退出;是c程序的源程序
gcc xxx.c編譯,連接
./a.out執行
mkdir c1
cd c1
vi hello.c
main()
{
}
gcc hello.c==>gcc -c hello.c會產生一個hello.o,gcc hello.o會產生一個a.out文件
gcc hello.o -ohello(通過-o可以指定一個文件名)
gcc hello.c -ohehe
./a.out
vi hello.c
#include <stdio.h> //頭文件,是一個輔助文件
int main()
{
printf("hello world! \n"); //c語言中的輸出函數
#include "xxx"
return 0;
}
//ls /usr/stdio標準c自帶的h文件
C語言程序的結構
1、#開頭的叫預處理行;用<>號文件里的內容放在#行位置;可以有多行
預處理行必須寫在一行,如果在一行寫不開的話,必須用續行符\來進行連接(表示下一行和這一行實際上是同一行)
如#include \
<stdio.h>
<stdio.h>是標準C自帶的
2、int main()
{
printf("hello,world\n");
#include "xxx" //切記include后面用<>的話表示其內的是標準c的,如果是include自己的文件需要用“”
}
一個C語言程序必須有這一部分;主函數
3、在c語言中,表達完整的意思用語句并以;結尾
\轉義字符;\n換行;\r回車;\t TAB;\b退格;\\表示一個反斜杠字符
4、return 0;0與main方法中的int相呼應
return 0;一般情況下可以這樣理解:帶回0表示一切正常;其他的數字則表示有錯誤
return 0;這行也可以不寫
5、注釋:/*.......*/
//main函數是一個C程序中必備的而且唯一的
xxx的內容
printf("hello,c");
printf("hello,java");
改錯一定要改第一個錯誤
int 整數 0,5,100
char 字符 用單引號表示如'a','*','8'
float單精度(一般7位有效數字),double雙精度(一般15位有效數字),long double(非標準的) 小數3.5,4.9,
整數在計算機中是怎么表示的呢?(二進制)
00000000 (8位) 用權重最大的那位作為符號位;0的時候表示非負數;1表示正數
什么是權重(理解);
-128---127
補碼:正數的補碼為原碼,負數的補碼為正數的原碼各位取反再加1
正數直接用原碼來表示;負數用補碼來表示
unsigned int非負數,沒有符號位,0-255
ASCII碼 用0--127
'a'--'z' 97-122
'A'--'Z' 65--90
'0'--'9' 48--57
'\'-->13 '\n'--10 '\t'--9
nul空字符--->0 '空格'---32
字符當整數用的時候,用的是編碼;如‘0’+20=68
char最多是7位二進制就可以來表示,計算機管理存儲單元是以字節為單位;1個字節8位(二進制位)
一個漢字GB2312就是2個空閑的字符來表示;1個字符占用1個字節的位置
整數int用4個字節,32個二進制位來表示;1個表示符號位,31個表示數值;最大正數2的31次方-1;最小的負數為-2的31次方-1
short int短整數,系統只分配2個字節的空間來存儲-32768---32767;判斷一個數字是否偶數還是奇數只判斷存儲二進制的最為一位是奇數還是偶數即可。
unsigned short int 0-65535
long int長整數,4個字節
long long 8個字節,-2的63次方----2的63次方-1
unsiged longlong 2的64次方-1
小數 表示近似表示不精確
float單精度小數;4個字節 符號位1,階碼8,尾數23;
double 8個字節,符號位1,階碼11,尾數52
sizeof某種類型用幾個字節來表示
超出范圍溢出,上溢出或下溢出;
對于整數而言,溢出會導致回繞
對小數而言,溢出不會回繞,會變成無窮,正負無窮inf
3.5f
3.5d
3.5L
C真假:非0為真,0表示假(‘\0’,0.0,null)
c++另外還有個false為假
自動類型提升:
char,short---》int
float----》double
如何來輸出各種類型的數據
#include <stdio.h>
int main()
{
printf("hello,data\n");
printf("aaa%dbbb%fccc\n");//%格式化輸出;占位符;正常的情況下
pinrtf("aaa%ibbb%fccc%cddd\n",123,45.6,65);
}
%i/%d/:int
%hd/%ld: short int /long int
%u: unsigned int
%f: float/double
%g: float/double去掉了尾隨的0
%c:char
%s:“string”,用雙引號引起來的東西
%p:address
%x/%o:十六進制/8進制
n進制表示
數字/n取余;然后商/n取余,直到結束
16進制用0x開頭
8進制用0開頭
比較并了解:如何看printf在c語言的那個庫中
1、man printf
2、man -a printf
3、man 3 printf
stdio.h==standard input/output headerfile
變量===二進制位,一部分內存空間
變量名
名字:
1、只能有字母、數字和下劃線,數字不能在前
2、不能用關鍵字
3、不能用函數名
4、盡量做到見名知意
5、嚴格區分大小寫
定義一個變量,開始里面表示著一個不可預知的數據,垃圾數據==>指定初始值就不會有垃圾數據了
mkdir c2
vi init.c //進一步來驗證垃圾數據或指定值初始化
#include <stdio.h>
int main()
{
double income;
short int pen,notebook;
int age=40;//指定值初始化
double salary=1234.56,weight=78.9;
printf("income=%lf\n",income);
printf("pen=%hd,notebook=%hd\n",pen,notebook);
printf("");
return 0;
}
vi的環境參數文件;可以在vi下看set all
vi ~/.exrc
set nu
set ts=4
變量不是喜新厭舊而是見新忘舊
變量類型不需要重復說明,以后用的時候只需要用名字即可
#include <stdio.h>
int main()
{
int n=12345.6;
printf("n=%d\n",n); //最終顯示為12345
printf("n=%f\n",n); //
return 0;
}
強制類型轉換:用()把某個數值轉成其他類型的數值,但其類型并不轉換
變量定義必須放在最前面
計算某個類型的變量需要占多少個字節sizeof(只關心類型)
vi sizeof.c
#include <stdio.h>
int main()
{
int n=10;
printf("%i\n",sizeof(int));
printf("%i\n",sizeof(n));
printf("%i\n",sizeof(n+5));
printf("%i\n",sizeof(n+5.0)); //轉換成double
printf("%i\n",sizeof(n=123)); //sizeof只關注類型,不關注其數值
printf("n=%i\n",n)
return 0;
}
我們看下sizeof的匯編代碼
gcc -S sizeof.c
會產生一個sizeof.s的匯編語言的文件
gcc sizeof.s 也會產生一個a.out文件,和前面的一樣
vi sizeof.s
esp棧頂指針,我們傳輸的數據都放到棧里了
通過這個例子可以查看c程序與匯編程序;
不變的變量稱為常量;constant
不變的數值稱為字面量
const double PI=3.14
vi consant
#include <stdio.h>
int main()
{
const double PI=3.14;
const int i=10;
printf("PI=%g,i=%d\n",PI,i);
PI=3.15;//可能會出現編譯error或警告:向只讀變量PI賦值
return 0;
}
編譯的時候報程序中有游離的\錯誤:一般解決方案是里面存在中文的字符;比如
空格及標點符號等;需要換成英文的;看光標是不是變成2個字符的寬度了。
除了注釋和雙引號里面,其他地方都不能出現中文的字符
C里面還支持宏#define CLASS “sd1109”
#define CLASS “sd1109”意思是遇到CLASS換成sd1109
#define DATE 20110910 意思是遇到DATE換成日期
#define AA PI*
#define BB 10+i
printf("%s,%d,CLASS,DATE");
printf("%g\n",AA BB);
編譯的時候線做替換
gcc -E consant.c
對于常量變更時,盡量用const,少用define
常量必須初始化賦值
+ - * / % >< != == >= <=
/取得商
%取得余數
C里面沒有true或false
vi logic.c
#include <stdio.h>
int main()
{
int a=3,b=5;
printf("%d,%d,%d\n",a<=b,a>=b,a>=3);
a=-3;
printf("%d,%d\n",a>=0 && a<=100,0<=a<=100);//前面不成立后面就不用考慮了。
//在這里計算機會怎么來分析0<=a<=100呢?==》首先要看0與a對比不論如何都是0或1,所以0或1再與100相比,肯定成立
printf("%d,%d\n",a<0||a>100,b<0||b>100);//||前面條件成立的話短路
int y=2012;
printf("%d\n",!(y%4==0&&y%100!=0||y%400==0));
return 0;
}
&按位與 用途:測試某位是0還是1;
只有兩個都是1才是1,只要有一個是0則為0
|按位或 有一個1則為1,其他為0 用途:把某個位置設置為0或1
^異或 兩者相同為0,不同為1 0和A異或A值不變,1和A異或A值反過來了
~ 按位取反 20按位取反 20 00000000 00000000 00010100
取反 11111111 11111111 11101011
驗證下:vi bits.c
#include <stdio.h>
int main()
{
printf("%d,%d,%d\n",~20,~1,~0);
return 0;
}
-21,0,-1
結論:補碼:負數 正數二進制表示按位取反+1
>> 左移的時候右邊空位補0
<< 右移左空補符號位
在運算過程中,變量的值只有在賦值運算時,才發生變化
#include <stdio.h>
int main()
{
printf("%d,%d,%d\n",~20,~1,~0);
unsigned int n=-1;
printf("%u,%x,%d\n",n,m);
int m=-1;
printf("%x,%x\n",n>>3,m>>3);
printf("%x,%x\n",n,m);
printf("%x,%x\n",n<<3,m<<3);
m=300;
printf("%d,%d\n",m<<3,m>>3);
m=0x3862517b;
printf("%x\n",(char)m);
printf("%x\n",(char)(m>>16));
int a=0x12,b=0x34,c=0x56,d=0x78;
printf("%x\n",(a<<24)|(b<<16)|(c<<8)|d);
return 0;
}
地址運算符&
每一個變量,系統都會分配一部分內存空間。那么這部分內存地址在哪里呢?
通過地址運算符來進行定位這部分內存地址
& 根據變量或常量取地址 *根據地址找到對應的變量或常量
*&a====》還是a
vi address.c
#include <stdio.h>
int main()
{
int a;
int b;
printf("&a=%p,&b=%p\n",&a,&b);
(*&a)=100;(*&b)=888888;
printf("a=%d,b=%d\n",a,b);
return 0;
}
一個變量有多個編號時,以最小的地址編號的為準作為變量的地址。
xxx?yyy:zzz 三目運算符;xxx判斷是否成立,真用yyy,假用zzz
,運算符,把多個運算連在一起,是一個雙目運算符
t=a;a=b;b=t;
t=a,a=b,b=t;
,有些情況下也不是運算符,而是分隔符
如何區分是運算符還是分隔符呢?
,運算符是以最后一個,為計算結果
n=n>>3 a=a+50 a=a^b
等價n>>=3 a+=50 a^=b
運算和賦值合起來(組合賦值)
類似的還有:-= *= /= %= &= |= <<=
++a --a
#include <stdio.h>
int main()
{
int a,b,c,d;
a=b=c=d=0;//連續的賦值從右往左算;
a++;++b;
printf("%d,%d\n",a,b);
return 0;
}
a++;++a的區別在于:運算的結果;a++拿變量的舊值做結果(后++);++a拿變量的新值作為結果(前++)
a++<10;解釋:會對a進行++運算,但只會拿a的舊值與10進行比較;可以這樣理解:temp=a,a=a+1,temp<10;
vi a.c
#include <stdio.h>
int main()
{
int a=0;
int b=0;
printf("%d %d %d\n",b=a+++(a+++2),b,a=b++);
printf("%d %d\n",a,b)
}
gcc a.c
a.out
轉換成匯編
gcc -S a.c
vi a.s
ebp32位的BP ,ebp是基址指針 EbP與bp的關系就象AX與AL,AH的關系.
BP為基指針(Base Pointer)寄存器,用它可直接存取堆棧中的數據,它的作用是在調用函數時保存ESP使函數結束時可以正確返回;
EAX—EDX可稱為數據寄存器,你除了直接訪問外,還可分別對其高十六位和低十六位進行訪問。
它們的低十六位就是把它們前邊兒的E去掉,即EAX的低十六位就是AX。而且它們的低十六位又可以分別進行八位訪問,
也就是說,AX還可以再進行分解,即AX還可分為AH(高八位)AL(低八位)。
運算本身一般不會改變變量本身的值,只有幾個是改變變量的值:前++,前--
int a=9,b=2;===>a/b=4
變量類型終身不變(double)a/b,實際上a還是int變量,只是其數值變成了double類型來參與運算
在比較兩個小數是否相等的時候,不能用==只能用近似相等fabs(a-b)<1E-5
避免在一個語句里面使變量的值多次改變。
輸出:把內存中的數據顯示到屏幕上;
輸出printf("格式串",...);格式占位符
輸入scanf("格式串",地址表....);在這里的格式串只有占位符沒有其他東西
#include <stdio.h>
/*
%c字符
%d,%x,%o:十進制、十六進制、八進制
%ld,%hd:longint 、short int
%f:float
%lf:double
%s:字符串
*/
int main()
{
int n=0;//準備好存儲的地方
float f=0;
double d=0;
char c=0;//'\0' 表示空字符,空字符的數值是0
printf("請輸入一個整數和一個小數:");
scanf("%d%f",&n,&f);//只需要格式占位符,不需要其他的;如
printf("%d,%g",n,f);
scanf("%lf\n",&d);//X
//不要有\n,否則在后期運行的時候會出問題。格式串只要不是空白什么都行
//運行的時候跳過所有的空白字符,到遇到非空白字符為止
scanf("%c",&c);
printf("c=[%c](%d)\n",c,c);
return 0;
}
//輸入的信息一般用空白字符隔開即可,比如空格,tab
如果在格式串中輸入了非空字符,則要求用戶在輸入時必須是原樣輸入
================================================================
scanf也會帶回數據,成功的輸入了幾個數據。
printf("成功項數:%d\n",scanf("%f,%lf",&f,&d));