底子太薄,看東西太過於馬虎,到如今感受本身不會的東西太多,也沒有相對來講精通的東西。linux
老話說的很對,以往那些以爲之後用不上能夠跳過的東西在關鍵時候都會跳出來給你當頭一棒!當然,即便社會如此之動盪,人心如此之浮躁。踏踏實實學點東西,弄明白點東西,這纔是根本。ios
1. C語言數據類型程序員
1 #define SECOND_YEAR_TIME 365*24*60*60*30UL 2 #include"stdio.h" 3 #include"math.h" 4 int main() 5 { 6 printf("Total second is:%ld\n",SECOND_YEAR_TIME); 7 //int x= ((sizeof(int))*8); 8 printf("the max number of int is:%f\n",pow(2,32)); 9 printf("the length of int is:%d\n",sizeof(int)); 10 printf("the length of char is:%d\n",sizeof(char)); 11 printf("the length of long int is:%d\n",sizeof(long)); 12 printf("the length of float is:%d\n",sizeof(float)); 13 printf("the length of double is:%d\n",sizeof(double)); 14 printf("the length of short int is:%d\n",sizeof(int)); 15 printf("the length of long double is:%d\n",sizeof(long double)); 16 printf("the length of unsigned int is:%d\n",sizeof(unsigned int)); 17 return 0; 18 }
今天仔細看看C,居然連這些最基本的東西都沒法分辨清楚。可悲的實踐能力,好笑的這麼些年。數組
以上結果爲64位機下數據類型所佔位數。網絡
2. 在宏中define函數函數
#define MIN(A,B) A<=B?A:B #include"stdio.h" int main() { int a=45, b=43,x=0; x=MIN(a,b); printf("the min number is: %d",x); }
這樣能相對於在代碼體中直接定義函數在編譯時產生更優的性能結果,在嵌入式C中常用。oop
3. static int 與 const int 性能
#include"stdio.h" int main() { static int xx=3; int sum=0; for(;;) { sum=xx++; if(sum>100) { break; } } printf("The final number occur is: %d\n",sum); printf("The value of xx after the loop is %d\n",xx); }
#include"stdio.h" int main() { const int xx=3; int sum=0; for(;;) { sum+=xx; if(sum>100) { break; } } printf("The final number occur is: %d\n",sum); printf("The value of xx after the loop is %d\n",xx); }
在C 語言中,關鍵字static 有三個明顯的做用: 在函數體,一個被聲明爲靜態的變量在這一函數被調用過程當中維持其值不變。 在模塊內(但在函數體外),一個被聲明爲靜態的變量能夠被模塊內所用函數訪 問,但不能被模塊外其它函數訪問。它是一個本地的全局變量。 在模塊內,一個被聲明爲靜態的函數只可被這一模塊內的其它函數調用。那就是 ,這個函數被限制在聲明它的模塊的本地範圍內使用。優化
從上面兩段代碼能夠發現,static僅僅是在內存中保留了局部變量或者函數運行後的值,並不作銷燬,這樣能夠方便傳送給其餘函數。spa
const則是嚴格指明變量的值不發生任何變化。 break則是使得程序跳出循環體,其對if語句並不起任何做用;另外break在switch語句中是必不可少的部分,若是缺乏,則進入死循環。
4. 變量及指針變量的定義
#include"stdio.h" int main() { int a; //定義一個整數 int *a; // 定義一個指向整數的指針 int **a; //定義一個指向指針的指針,而且這個指針指向一個整數 int a[10]; //定義一個包含十個元素的整形數組 int *a[10]; // 定義一個包含十個指針元素的數組,每一個指針指向一個整形值 int (*a)[10] //定義一個有十個整形數組值的指針 int (*a)(int) //定義一個指向函數的指針,該函數至少一個整形參數且返回一個整數 int (*a[10])(int) //定義一個由十個指針的數組,該指針指向一個函數 }
5. const用法進階
#include"stdio.h" int main() { const int a=0; // 正確 int const b; b =0; // 錯誤 int a=100,b=1000,*p,*t; const int (*p=a); int const (*t); p+=8; // 正確,指針能夠修改,可是指向的整數是不能夠修改的 *t=3; // 錯誤 int* const p; // 常量指針,指向的整數能夠修改,可是指針不可修改 int const * a const; // 整數不能夠修改,同時指針也不可修改 }
6. voliaile
定義爲volatile 的變量是說這變量可能會被意想不到地改變,這樣,編譯器就不會去假設這個變量的值了。精確地說就是,優化器在用到這個變量時必須每次都當心地從新讀取這個變量的值,而不是使用保存在寄存器裏的備份。
1>告訴compiler不能作任何優化。
2>用volatile定義的變量會在程序外被改變,每次都必須從內存中讀取,而不能重複使用放在cache或寄存器中的備份。
7. int 與usigned int
#include<stdio.h> #include"string.h" int main() { int k=-1; printf("%d,%u",k,k); }
下圖爲程序運行結果與2^32次方計算結果。
8. 邏輯運算值對式子的影響
#include<stdio.h> #include"string.h" int main() { int a=5,b=6,c=7,d=8,m=2,n=2; int x=(m=a>b)&&(n=c>d); printf("邏輯表達式的值爲:%d\n",x); printf("程序運行後n的值爲:%d\n",n); printf("程序運行後m的值爲:%d\n",m); }
程序運行結果爲:
由於運算符&&是一種短路運算符,前面的一個條件(m=a>b)爲假,因此不會去執行後面的判斷條件,於是後面語句根本沒有執行,故n=2,而m=0.
9. 二維數組的指針
#include<stdio.h> int main() { int a[][3]={10,20,30,40,50,60}; // 1行2列的地址:a[1]+2,*(a+1)+2,&a[1][2] // 1行2列的值: *(a[1]+2),*(*(a+1)+2),a[1][2] printf("the first number is: %d",*(*(a+1)+2)); }
a[1]表明第二行的首地址,+2表明右移兩位。每一行表明一個班,整個數據表表明一個排,排長每次檢查一個班,即從a-》a+1,跳過的元素爲一個班的數量;而班長每次檢查的元素數量僅爲一個班的元素,即(a+1)+2表明這個班中的第三個元素。
10. 位操做
如下代碼利用位操做實現對a的第三位置1,以及清0操做。
#include<stdio.h> #define BIT3 (0x01a<<3) // 0x前綴表明十六進制;0前綴表明八進制;沒有前綴表明十進制 int main() { static int a=120; // 二進制爲:01100100 printf("BIT3的值爲:%d\n",BIT3); a |=BIT3; printf("a的bit3設置爲1後的值爲:%d\n",a); a &=~BIT3; printf("a的bit3清除後的值爲:%d\n",a); }
11. break 和 continue
在while循環,do...while循環和for循環中,能夠用break語句跳出循環,用continue語句結束本次循環。
而對用goto語句和if語句構成的循環,不能用break和continue語句進行控制。
break用於跳出循環,continue用於結束本次循環,並不是終止整個循環。
12.冒泡排序
#include<stdio.h> int main() { int a[10],temp; int i,j,k,l; printf("請輸入十個須要排序的數:\n"); for(i=0;i<10;i++) { scanf("%d",&a[i]); } for(j=0;j<10;j++) { for(k=0;k<j;k++) { if(a[j]<a[k]) { temp=a[k]; a[k]=a[j]; a[j]=temp; } } } printf("冒泡排序後的順序爲:\n"); for(l=0;l<10;l++) { printf("%d\n",a[l]); } }
13.字符串的讀取和輸出(C中)
#include"stdio.h" #include"string.h" int main() { char b[100]; gets(b); printf("輸入的字符數組爲:\n"); puts(b); }
14. C和C++中除數爲0
C語言:不報錯,運行時程序異常。
#include"stdio.h" int main() { int a=100,b=0; int c=a/b; printf("輸出的除法結果爲:%d\n",c); }
C++語言:一樣不報錯,運行程序異常。
15. strcat\strcpy\strncpy的用法
strcat的數組1定義的長度必須足夠大,以便能容納連接後的新字符串,不然會出現問題----實驗中不斷輸出連接後的語句,並不是正常輸出一句後中止。
#include"stdio.h" #include"string.h" int main() { char str1[30]={"People's Republic of China"};// 長度爲30的時候會報錯,40或更大則正常輸出 char str2[15]={"Mao ZeDong"}; printf("%s\n",strcat(str1,str2)); }
strcpy(str1,str2) 一樣也是將str2的內容複製到str1中,且1的數組大小必須足夠大。
strncpy(str1,str2,n)將str2中最前面的n個字符複製到str1中,取代str1中原有的最前面n個字符;複製的字符數不該該多與str1中原有的字符數。
16. strcmp\strlen\strlwr\strupr的用法
printf("%d\n",strcmp(str1,str2));
strcmp: 若是str1=str2,則函數值爲0; 若是str1>str2,則返回值爲一個正數; 若是str1<str2,則返回值爲一個負數。
比較的規律:英文字典中位置靠後的爲大,例如computer>compare; 小寫字母比大寫字母大,例如:DOG<dog;空格的做用:str 1<str1;
中文字符:也是按照ascii碼值來進行比較;
數字: 直接比較大小,大於返回1,小於返回-1.
strlen: 函數值爲字符串實際長度,不包含'\0',可是包含空格。
printf("%d\n",strlen(str1));
strlwr\strupr則是直接將字符串變爲所有小寫或者所有大寫:
printf("%s\n",strlwr(str1)); printf("%s\n",strupr(str1));
17.統計單詞的個數代碼
#include"stdio.h" #include"string.h" int main() { char a[100]; int i,num=0,word=0; printf("請輸入一段文字:\n"); gets(a); printf("輸入的字符段爲:%s\n",a); printf("輸入的字符段長度爲:%d\n",strlen(a)); for(i=0;a[i]!='\0';i++) { if(a[i]==' ') //未出現新單詞的情形 { word=0; } else if(word==0) //前一字符爲空格,即新單詞出現 { word=1; num++; } } printf("本段文字中的單詞數目爲:%d\n",num); return 0; }
18. 找出三個字符串中的最大者
#include"stdio.h" #include"string.h" int main() { char a[20], a1[3][20]; int i; printf("請輸入三個字符串:\n"); for(i=0;i<3;i++) { gets(a1[i]); } if(strcmp(a1[0],a1[1])>0) { strcpy(a,a1[0]); } else { strcpy(a,a1[1]); } if(strcmp(a,a1[2])<0) { strcpy(a,a1[2]); } printf("輸入的字符串最大的爲:%s\n",a); return 0; }
CMD中的C語言編譯、連接方法 & 上述程序運行結果:
gcc:
gcc -c test.c -o test.o
gcc test.o -o test.exe
vc:
cl (/c /TC /O1 /MD) test.c
link test.obj
19.選擇排序法(調試技巧:C語言須要在開始處聲明程序變量,不然會報莫名其妙的錯誤,C++才能在任意處聲明變量。)
對於10個數字而言,先將10個數字中的最小數與a[0]對換,再將a[1]到a[9]中最小的數與a[1]對換.......
#include"stdio.h" int main() { int a[5],i,j,k,m,temp=0; //c編譯器的緣由,此語句必須放在最前面 printf("請輸入五個數字,以回車鍵結束。\n"); for(i=0;i<5;i++) { scanf("%d\n",&a[i]); } for(j=0;j<5;j++) for(k=j+1;k<5;k++) { if(a[j]>a[k]) { temp=a[j]; a[j]=a[k]; a[k]=temp; } } for(m=0;m<5;m++) printf("選擇排序以後的結果爲:%d\n",a[m]); }
20. 局部變量&全局變量
局部變量:
main()函數中定義的變量m,n也只能在主函數中有效,而非由於在主函數中定義而對整個文件或程序有效;主函數也不能使用其餘函數中定義的變量。
不一樣程序中可使用相同名字的變量;
形式參數也屬於局部變量;
全局變量:函數內定義的是局部變量,函數外定義的是全局變量。做用域從定義位置到文件結束。C程序設計全局變量首字母大寫(習慣)。
非必要時不要使用全局變量,緣由以下:
全局變量的所有執行過程當中都佔用存儲單元,而非須要時開闢;
它使得函數的通用性下降,由於在移植時須要考慮外部變量對於函數的影響;
過多的全局變量下降了程序的清晰性;
全局變量與局部變量重名的時候,在局部變量的做用範圍內,外部變量將被屏蔽。
21. 變量的存儲類別
從變量的生存週期來區分,能夠分爲靜態存儲方式&動態存儲方式。靜態是指程序運行期間由系統分配固定的存儲空間的方式,動態則是指程序運行期間根據須要進行分配存儲空間的方式。(分別對應全局變量 & 局部變量、函數形式參數、函數調用時的現場保護和返回地址)
C語言中,變量和函數的基本屬性是:數據類型 & 數據的存儲類別(auto\static\register\extern)。
auto: 局部變量,包括形參,函數中定義的變量。都動態的分配存儲空間,程序調用結束即自動釋放;
static: 靜態局部變量。有時但願函數中的局部變量的值在函數調用結束後不消失而保留原值,即所佔用存儲單元不釋放,在下一次函數調用時直接使用上次調用結束時的值。(若是不講靜態局部變量賦初值,則編譯時自動賦初值爲0或者空字符)
如下程序反映了static的保留做用,編譯程序結果以下。
#include"stdio.h" int main() { int fun(int); int a=2,i; for(i=0;i<3;i++) printf("%d",fun(a)); return 0; } int fun(int a) { int b=0; static int c=3; b=b+1; c=c+1; return(a+b+c); }
register:通常狀況下,包括靜態存儲和動態存儲方式的值都是放在內存中的。但若是有一些變量使用頻繁,由於存取變量值須要花費很多的時間,所以C語言運行將局部變量的值放到CPU的寄存器中,須要時直接從寄存器中取出,而不須要去內存中,從而能夠提升執行效率。示例以下:
#include"stdio.h" int main() { long fac(long); long i,n; scanf("%ld",&n); for(i=1;i<=n;i++) printf("%ld!=%ld\n",i,fac(i)); } long fac(long n) { register long i,f=1; for(i=1;i<=n;i++) f=f*i; return f; }
只有局部自動變量和形式參數能做爲寄存器變量,其餘如全局變量不行,函數調用結束釋放寄存器。
局部靜態變量不能定義爲寄存器變量。
extern:在函數外部定義的全局變量,做用域爲定義處--》程序結尾。若是在定義點以前想引用該外部變量,則在引用前用關鍵字extern對該變量作」外部變量聲明「便可。例如:
int max(int , int) extern A,B; //在此處進行聲明便可 printf("%d\n",max(A,B)); int A=13,B=-8;
main函數以上定義的全局變量,是能夠被整個工程所調用的,須要在外部用extern關鍵字聲明。
相反,static所定義的全局變量,僅限於本文件引用,而不能被其餘文件引用。
22. 內部函數 & 外部函數
內部函數,與全局變量同樣,在前添加關鍵字static便可,僅適用於本文件引用,從而不擔憂重名問題。
外部函數,添加extern關鍵字。
23. 預處理命令
宏:
C語言提供的預處理功能主要包括:宏定義、文件包含、條件編譯。
宏名通常採用大寫字母表示,宏定義能夠引用已經定義的宏名,從而進行層層置換。宏定義只作字符替換,並不分配內存空間。帶參數的宏定義並不止簡單的字符替換,還要進行參數替換。
文件包含:
頭文件不用.h結尾,而改成.c或者沒有後綴名結尾都是能夠的,.h只是能更好的表示此文件的性質。
<>是到系統存放C庫函數頭文件的目錄中尋找,這稱爲標準方式;」 「號包含方式則優先到用戶當前目錄中尋找,找不到再按標準方式尋找。若是不在當前目錄中,則應該給出路徑,例如:
#include "C:\Martin\user_data\files1.h"
include的文件在預編譯後與調用文件已經成爲一個文件,於是此時須要注意文件中變量的做用域並未改變。
條件編譯:
爲什麼使用條件編譯,而不是if語句。----採用條件編譯能夠減小被編譯的語句,從而減小目標程序的長度,減小運行時間。特別是當編譯條件較多時,目標程序長度能夠大大減小。
24. 指 針
25. 結構體 & 共用體
」.「運算符在全部運算符中優先級最高,而且能夠像普通變量同樣進行各類運算,亦能夠引用結構體變量成員的地址。
指向結構體類型數據的指針變量,首先指向的是第一個元素的起始地址,,執行p++以後增長的值爲結構體數組的一個元素所佔的字節數(對於利用數組存儲多個對象的結構信息而言)。
26. 鏈表
若是不提供頭指針,則整個鏈表都沒法訪問。
#include"stdio.h" #define NULL 0 struct student { long num; float score; struct student *next; }; int main() { struct student a,b,c,*head,*p; a.num=10101; a.score=89.5; b.num=10103; b.score=90; c.num=10107; c.score=85; head=&a; a.next=&b; b.next=&c; c.next=NULL; p=head; do { printf("%ld %5.1f\n",p->num,p->score); p=p->next; } while(p!=NULL); }
malloc: void *malloc(unsigned int size); --->在內存的動態存儲區中分配一個長度爲size的連續空間,弱未能成功執行,則返回空指針NULL。
calloc: void *calloc(unsigned n, unsigned size); --->在動態內存中分配n個長度爲size的連續空間,成功則返回分配起始地址的指針,不然NULL。
free: void free(void *p); --->釋放由P指向的內存區域,無返回值。
27. sizeof和strlen
sizeof計算實際所佔內存大小,包含'\0';strlen計算字符串的長度,以‘\0’結尾,不包括‘\0’。
#include "stdio.h" #include"string.h" int main() { char a[]={'0','1','2','3','\0'}; char b[]={'0','1','2','3','\0','2','5','8','7'}; printf("%d\n",sizeof(a)); printf("%d\n",strlen(a)); printf("%d\n",sizeof(b)); printf("%d\n",strlen(b)); }
輸出結果爲:
28. 如何斷定一個整數有幾位
#include "stdio.h" int main() { int a,n=0; printf("請輸入一個數:"); scanf("%d",&a); while(a!=0) { n++; a=a/10; } printf("該數字的位數爲:%d\n",n); }
29. 靜態鏈表
全部節點都是在程序中定義的,不是臨時開闢的,也不能用完後釋放,這種鏈表稱爲靜態鏈表。
隊列爲線性表,僅能在隊尾進行插入,隊首進行刪除操做;鏈表爲非線性結構,每一個元素都包含了值以及另一個指針,是一種經常使用的存儲結構;棧則爲僅容許在一端進行操做的特殊線性表。
linux內核所包括的五個子系統: 進程調度、內存管理、虛擬文件系統、網絡接口和進程間通信。
創建鏈表的函數以下所示:
#include"stdio.h" #include"malloc.h" #define NULL 0 #define LEN sizeof(strct student) struct student { long num; float score; struct students *next; }; int n; struct student *creat(void) { struct studnet *head; struct student *p1,*p2; n=0; p1=p2=(struct student *)malloc(LEN); scanf("%ld,%f",&p1->num,&p1->score); head=NULL; while(p1->num!=0) { n=n+1; if(n==1) head=p1; else p2->next=p1; p2=p1; p1=(struct student*)malloc(LEN); scanf("%ld,%f",&p1->num,&p1->score); } p2->next=NULL; return(head); }
鏈表的插入函數:
struct student *insert(struct student *head,struct student *stud) { struct student *p0,*p1,*p2; p1=head; p0=stud; if(head=NULL) { head=p0; p0->next=NULL; } else { while((p0->num>p1->num)&&(p1->next!=NULL)) { p2=p1; p1=p1->next; } if(p0->num<=p1->num) { if(head==p1) head=p0; else p2->next=p0; p0->next=p1; } else { p1->next=p0; p0->next=NULL; } n=n+1; return(head); } }
鏈表元素的刪除函數:
struct student *del(struct student *head,long num) { struct student *p1,*p2; if(head==NULL) printf("\nlist id null! \n"); goto end; p1=head; while(num!=p1->num&&p1>next!==NLL) { p2=p1; p1=p1->next; } if(num==p1->num) { if(p1==head) head=p1->next; else p2->next=p1->next; printf("delete:%ld\n",num); n=n-1; } else printf("%ld not been found! \n",num); end; return(head); }
30.程序的存儲空間問題
通常認爲在c中分爲這幾個存儲區:
1棧 - 有編譯器自動分配釋放
2堆 - 通常由程序員分配釋放,若程序員不釋放,程序結束時可能由OS回收
3全局區(靜態區),全局變量和靜態變量的存儲是放在一塊的,初始化的全局變量和靜態變量在一塊區域,未初始化的全局變量和未初始化的靜態變量在相鄰的另外一塊區域。 程序結束釋放。
4另外還有一個專門放常量的地方。 - 程序結束釋放
在函數體中定義的變量一般是在棧上,用malloc, calloc, realloc等分配內存的函數分配獲得的就是在堆上。在全部函數體外定義的是全局量,加了static修飾符後無論在哪裏都存放在全局區(靜態區),在全部函數體外定義的static變量表示在該文件中有效,不能extern到別的文件用,在函數體內定義的static表示只在該函數體內有效。另外,函數中的 "adgfdf "這樣的字符串存放在常量區。
好比:
int a = 0; 全局初始化區
char *p1; 全局未初始化區
main()
{
int b; 棧
char s[] = "abc ";棧
char *p2; 棧
char *p3 = "123456 "; 123456\0在常量區,p3在棧上。
static int c =0; 全局(靜態)初始化區
p1 = (char *)malloc(10);
p2 = (char *)malloc(20);
分配得來得10和20字節的區域就在堆區。
strcpy(p1, "123456 "); 123456\0放在常量區,編譯器可能會將它與p3所指向的 "12345
31. strlen & sizeof & 轉義字符
#include"iostream" #include"string" using namespace std; int main() { char aa[]="absc\n\\\t\0\b\a\r\0"; cout<<"sizeof的值爲:"<<sizeof(aa)<<endl; cout<<"strlen的值爲:"<<strlen(aa)<<endl; return 0; }
能夠看出:sizeof計算的是整個數組的長度,包括系統爲字符串自動所添加的'\0',也計算在內。 若是制定了數組的大小,則以指定大小爲準。
strlen計算的是實際的有效字符長度,以'\0'做爲計算的結尾,即便後面還有字符,也不計算在內。