好久沒有寫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重新指派之後,
再free,并沒有真正釋放記憶體void main(){ int* p1 = malloc(1024 * 1024 * 10 * sizeof(int)); //free(p1);//這裡要釋放一下 p1 = malloc(1024 * 1024 * 20 * sizeof(int)); free(p1); }
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語言的結構體