天天看點

C語言基礎知識總結(一)

好久沒有寫NDK啦,這兩天在拿起來做開發,感覺基礎知識有點生疏啦,正好趁周末溫故一下,做個小筆記友善以後檢視。

1、占位符

printf("%d\n", i);
           

我們做一些日志輸出的時候往往會這麼書寫,這個%d是起到一個占位的作用。C語言中基本資料類型的占位符分别是:

1、int %d

2、float %f

3、short %d

4、long %ld

5、char %c

6、double %lf

7、字元串 %s

8、十六進制 %x

9、八進制 %o 

2、周遊數組

//不标準 Linux會編譯出錯
	for (int i = 0; i < 10; i++){
	    printf("%d\n", i);
	}
	
//标準的寫法
	int n = 0;
	for (; n < 5; n++){
		printf("%d\n", n);

	}
           

 3、指針

先看幾個常見的概念:

(1)、& 表示取位址符,

void change(int i){//會重新建立一個i位址
	i = 300;
}

void change(int *p){
	*p = 300;
}

//指針存取的是變量記憶體位址
void main(){
	int i = 90;
	printf("i的值為:%d\n",i);
	int *p = &i;
	//*p = 200;//間接指派
	//change(i);
	change(p);
	printf("i的值為:%d\n",i);

	system("pause");
}
*/
           

(2)、指針有類型,位址沒有類型,位址隻是開始的位置,類型讀取到什麼位置結束。

void main(){
	int i = 90;
	int *p = &i;
	double j = 99.9;
	p = &j;

	printf("double size:%d\n",sizeof(double));
	printf("%#x","%lf\n",p,*p);//想通過4位元組讀取8位元組變量的值,是不行的

	getchar();
}
           

(3)、空指針的預設位址為0

(4)、多級指針

void main(){
	int a = 50;
	//p1儲存的a的位址
	int *p1 = &a;
	//p2儲存p1的位址
	int **p2 = &p1;
	printf("p1:%#x,p2:%#x\n",p1,p2);
	**p2 = 99;
	printf("%d\n",a);

	getchar();
}
           

 (5)、指針的運算

指針的運算,一般在數組周遊時才有意義,基于數組在記憶體中線性排列的方式。

void main(){
	//數組在記憶體連續存儲
	int ids[] = {12,45,23,33,11};
	//數組變量名:ids就是數組的首位址
	printf("%#x\n", &ids);
	printf("%#x\n", ids);
	printf("%#x\n",&ids[0]);
	//ids 等價于&ids[0],ids+1等價于&ids[1],ids+i等價于&ids[i]
	//*ids等價于ids[0],*(ids+1)等價于ids[1],*(ids+i)等價于ids[i]

	//指針變量 
	int *p = ids;
	printf("%d\n",*p);
	//指針的加法
	p++;//p++向前移動sizeof(資料類型)個位元組
	printf("%d\n",*p);

	getchar();
}
           

(6)、函數指針

void msg(char* msg,char* title){
	MessageBox(0, msg, title, 0);
}

int msg(char* msg, char* title){
	MessageBox(0, msg, title, 0);
	return 0;
}

//程式是資料和指令的集合
void main(){
	//msg();

	//函數傳回值類型,函數指針名稱,函數的參數清單
	//void(*fun_p)(char* msg, char* title) = msg;
	//fun_p("内容","标題");

	printf("%#x\n",msg);
	int(*fun_p)(char* msg, char* title) = msg;
	fun_p("内容", "标題");

	getchar();
}
           
int add(int a,int b){
	return a+b;
}

int minus(int a, int b){
	return a - b;
}

//msg函數需要傳遞一個函數指針參數
//類似java回調函數
void msg(int(*fun_p)(int a,int b),int m,int n){
	//int r = fun_p(m, n);
	//MessageBox(0, "hhh","ddd", 0);
	//printf("%d\n",r);

	printf("執行一段代碼...\n");
	printf("執行回調函數...\n");
	int r = fun_p(m, n);
	printf("執行結果:%d\n",r);
}

void main(){
	//加法
	//int(*fun_p)(int a,int b)=add相當于
	msg(add, 10, 20);

	//減法
	msg(minus,60,10);

	getchar();
}
           

4、記憶體配置設定

1.棧區(stack),window下,棧記憶體配置設定2M(确定的常數)超出了顯示就會stack overflow錯誤,棧溢出

   自動配置設定、釋放

2.堆區(heap) 作業系統80%記憶體

   程式員手動配置設定、釋放

3.全局區或靜态區

4.字元常量區

5.程式代碼區

/*
void main(){
	//40M
	//stack overflow錯誤,棧溢出
	//靜态記憶體配置設定  棧區
	int a[1024 * 1024 * 40];
}
*/

/*
//堆記憶體
void main(){
	//在記憶體上,配置設定40M的内容
	//位元組
	//void * 任意類型的指針
	int* p = (int*)malloc(1024 * 1024 * 10 * sizeof(int));

	//釋放記憶體
	free(p);
}
*/
           

 靜态記憶體和動态記憶體差別: 

靜态配置設定記憶體大小是固定的,問題:1、很容易超出棧記憶體的最大值 2、為了防止記憶體不夠用會開辟更多的記憶體,容易浪費

動态記憶體配置設定,在程式運作過程中,動态指定需要使用的記憶體大小,手動釋放,釋放之後這些記憶體還可以被重新使用。

//建立一個數組,動态指定數組的大小
//(在程式運作過程中,可以随意的開辟指定大小的記憶體,以供使用,相當于Java中的集合)
void main(){
	//靜态記憶體配置設定建立數組,數組的大小是固定的
	//int i = 10;
	//int a[i];

	int len;
	printf("輸入數組長度:");
	scanf("%d",&len);

	//開辟記憶體,大小為len*4位元組
	int *p = malloc(len*sizeof(int));
	//p是數組的首位址,p就是數組的名稱
	//給數組元素指派(使用這一塊剛剛開辟出來的記憶體區域)
	int i = 0;
	srand((unsigned)time(NULL));
	for (; i < len; i++){
		p[i] = rand() % 100;
		printf("%d,%#x",p[i],&p[i]);
	}

	//手動釋放記憶體
	free(p);

	getchar();
}
           

記憶體重新配置設定

void main(){
	int len;
	printf("輸入數組長度:");
	scanf("%d", &len);

	//int *p = malloc(len*sizeof(int));
	int *p = calloc(len, sizeof(int));
	int i = 0;
	srand((unsigned)time(NULL));
	for (; i < len; i++){
		p[i] = rand() % 100;
		printf("%d,%#x\n", p[i], &p[i]);
	}

	int addLen;
	printf("輸入數組長度:");
	scanf("%d", &addLen);
	//擴大剛剛配置設定的記憶體空間
	//1、原來的記憶體的指針 2、記憶體擴大之後的總大小
	int *p2 = realloc(p, sizeof(int) * (len + addLen));
	if (p == NULL){
		printf("重新配置設定失敗");
	}

	//重新指派
	i = 0;
	for (; i < len + addLen;i++){
		p2[i] = rand() % 200;
		printf("%d,%#x\n", p2[i], &p2[i]);
	}

	//手動釋放記憶體
	if (p2 != NULL){
		free(p2);
		p2 = NULL;
	}

	getchar();
}
           

總結:

     //重新配置設定記憶體的兩種情況:

    //縮小,縮小的那部分資料會丢失

    //擴大(連續的)

    //1、如果目前記憶體段後面有需要的記憶體空間,直接擴充這段記憶體空間,realloc傳回的指針

    //2、如果目前記憶體段後面的空閑位元組不夠,那麼就使用堆中的第一個能滿足這一要求的記憶體塊,

    //   将目前的資料複制到新的位置,并将原來的資料塊釋放掉,傳回新的記憶體位址

    //3、如果申請失敗,傳回NULL,原來的指針仍然有效 

 記憶體配置設定的細節

//1、不能多次釋放

//2、釋放完之後;給指針置NULL;标志釋放完成

//3、記憶體洩漏,p重新指派之後,

void main(){
	int* p1 = malloc(1024 * 1024 * 10 * sizeof(int));
	//free(p1);//這裡要釋放一下
	p1 = malloc(1024 * 1024 * 20 * sizeof(int));
	free(p1);
}
           
再free,并沒有真正釋放記憶體

 5、字元串

C語言中對于字元串的初始有兩種方式:

//使用字元數組存儲字元串
void main(){
	//char str[] = { 'w', 'e', 'r', 't','\0' };// \0表示結束
	//char str[6] = { 'q', 'w', 'e', 'r', 't' };
	char str[10] = "love you";
	//可以修改
	str[0] = 'L';
	printf("%s\n",str);
	printf("%#x\n",str);
	getchar();
}

//字元指針
void main(){
	//記憶體連續排列
	char *str = "how are you";

	//不可以修改
	//str[0] = 'H';

	//str += 1;
	//*str = 'H';

	printf("%s\n", str);
	printf("%#x\n", str);

	//使用指針加法截取字元串
	str += 3;
	while (*str){
		printf("%c",*str);
		str++;
	}
	printf("\n完成");

	getchar();
}
           

一些字元串中常用的函數:

//strlen(s) : 傳回S的長度,不包括字元串結束符NULL;

//strcmp(s1,s2) :比較兩個字元串是否相同,若s1==s2,傳回0,若s1>s2則傳回正數,若s1<s2則傳回負數;

//strcat(s1,s2):将字元串s2連接配接到s1上,傳回 s1;

//strcpy(s1,s2):将s2,複制到s1,傳回 s1.

//strchr 該函數傳回在字元串 str 中第一次出現字元 w 的位置,如果未找到該字元則傳回 NULL。

//strstr(str1,str2) 若str2是str1的子串,則傳回str2在str1的首次出現的位址;如果str2不是str1的子串,則傳回NULL。

void main(){
	char *s1= "i love you";
	char *s2 = "how are you";
	char d[20] = {'w'};
	
	strcpy(d, s1);//将s1,複制到d,傳回 d
	printf("%s\n", d);
	strcat(d, s2);//将字元串s2連接配接到d上,傳回 d;
	printf("%s\n", d);
	getchar();
}

void main(){
	char str[20];//靜态記憶體配置設定,會開辟的比實際中大,會造成浪費
	char *p = str;
	//指向了同一塊記憶體
	printf("str:%#x\n", str);
	printf("p:%#x\n", p);
	strcpy(p,"i love you");

	printf("%s\n", str);
	getchar();
}

void main(){
	char *str = "I want go to USA!";
	printf("%#x\n",str);
	
	char *p = strchr(str, 'w');
	printf("%#x\n", p);

	if (p){
		printf("索引位置:%d\n", p - str);
	}else{
		printf("未找到");
	}

	getchar();
}
           

 以上是一些C語言的基礎知識,下篇會重點介紹下C語言的結構體