重拾c語言基礎(chǔ)-記錄筆記

自從出來工作之后就沒在用過 c 了,為了更加深入的學(xué)習(xí)一些底層的東西症副,不得已重新來過一遍基礎(chǔ)的知識(shí)點(diǎn)启泣。

C的基本數(shù)據(jù)類型

signed&unsigned

  • int是4個(gè)字節(jié),32位
  • int能表示2的32次方個(gè)數(shù)字
  • 把最高位抽出來亿蒸,用于表示正負(fù)凑兰,只剩下31位表示數(shù)值
  • 此時(shí)int能表示2的31次方
  • 如果最高位的值是0掌桩,那么int就是正數(shù),范圍就是0~2的31次方-1
  • 如果最高位的值是1姑食,那么int就是負(fù)數(shù)波岛,范圍就是-(2的31次方)~-1
  • 那么int的總范圍,就是-2的31次方~2的31次方-1
  • signed:有符號(hào)音半,表示最高位用于表示正負(fù)
  • unsigned:無符號(hào)则拷,表示最高位用于表示數(shù)值
  • 無符號(hào)int型只能表示正數(shù),并且取值范圍是0~2的32次方-1

原碼曹鸠、反碼煌茬、補(bǔ)碼

  • 原碼:把數(shù)值轉(zhuǎn)換成二進(jìn)制數(shù)值
  • 反碼:除最高位,其他位依次取反
  • 補(bǔ)碼:在補(bǔ)碼的基礎(chǔ)上物延,除最高位宣旱,其他位依次取反,然后+1
  • 正數(shù)的原碼叛薯、反碼浑吟、補(bǔ)碼相同

基本數(shù)據(jù)類型的長(zhǎng)度

JAVA

  • byte:1
  • short:2
  • int:4
  • long:8
  • float:4
  • double:8
  • boolean:1
  • char:2

C

  • short:2
  • int:4
  • long:32位操作系統(tǒng)是4個(gè)字節(jié),64位操作系統(tǒng)是8字節(jié)
  • float:4
  • double:8
  • char:1

示例代碼

#include <stdio.h>

int main(int argc, const char * argv[]) {
    
    //基本數(shù)據(jù)類型的長(zhǎng)度
    //sizeof返回的 unsign long 無符號(hào)的long類型
    printf("%lu\n",sizeof(int));//4
    printf("%lu\n", sizeof(short));//2
    
    printf("%lu\n", sizeof(long));//在32位操作系統(tǒng)中l(wèi)ong的長(zhǎng)度4個(gè)字節(jié)耗溜,64位操作系統(tǒng)中l(wèi)ong的長(zhǎng)度為8個(gè)字節(jié)
    printf("%lu\n", sizeof(float));//4
    printf("%lu\n", sizeof(double));//8
    printf("%lu\n", sizeof(char));//1
    
    

    printf("%lu\n", sizeof(long long));//8

    //以下兩種聲明的方式组力,我覺得是沒有必要的,因?yàn)橐硎?個(gè)長(zhǎng)度的數(shù)據(jù)類型抖拴,直接使用 short 就好的燎字,要表8位長(zhǎng)度的數(shù)據(jù)使用 long 就行了。
    printf("%lu\n",sizeof(short int));//2
    printf("%lu\n",sizeof(long int));//8

    
    //定義一個(gè)無符號(hào)的變量a阿宅,最大值42億
    unsigned int a = 4294967295;
    
   
    
    //最高位表示符號(hào)位候衍,只能表示無符號(hào)的一半大小,默認(rèn)定義的整形類型就是有符號(hào)位的
    signed int b = 2100000000;
    
    //如果使用無符號(hào)來表示-1的話洒放,它表示的是無符號(hào)的最大值4294967295蛉鹿。
    unsigned int c = -1;
    
    
    
    printf("%u\n",a);
    
    printf("%d\n",b);
    
    printf("%u\n",c);
    
    //char只能存放一個(gè)字符,并且使用''表示
    char ch = 'b';
    
    printf("%c",ch);
    
    
    return 0;
}

指針

內(nèi)存地址

  • 內(nèi)存中每一個(gè)字節(jié)都有一個(gè)內(nèi)存地址往湿,這樣才能保證不管數(shù)據(jù)存在內(nèi)存的哪一個(gè)位置妖异,都可以通過內(nèi)存地址找到。
  • 訪問內(nèi)存的數(shù)據(jù)领追,要通過內(nèi)存地址他膳。

指針變量

  • 指針變量就是保存內(nèi)存地址的變量。
  • 指針變量通常簡(jiǎn)稱為指針绒窑。
  • int* p;定義一個(gè)int型的指針變量棕孙,用于保存內(nèi)存地址,該地址存放的值必須是int型的數(shù)據(jù)。
  • *p 獲取指針變量 p 指向的內(nèi)存地址所存放的數(shù)據(jù)蟀俊。
#include<stdio.h>
#include<stdlib.h>
int main(){
    
    int i;
    
    i = 10;
    
    //打印變量的地址分歇,注意占位符使用%#x
    //printf("%#x\n",&i);
    
    int b = 3;
    
    //定義一個(gè)int類型的指針,存放是int類型變量的地址欧漱。
    //這是一個(gè)一級(jí)指針
    int *p = &b;
    
    
    //定義一個(gè)二級(jí)指針,存放的是指針的地址葬燎。
    int **q = &p;
    
    printf("p指針?biāo)娣艃?nèi)存地址對(duì)應(yīng)的值是%d\n",*p);
    
    printf("q指針?biāo)娣艃?nèi)存地址對(duì)應(yīng)的值是%d\n",**q);
    
    
    //指針的常見錯(cuò)誤
    //常見錯(cuò)誤1:野指針
    int *pp ;
    //定義了误甚,但沒有賦值的指針,稱為野指針谱净。
    //printf("pp的內(nèi)存地址是%#x\n",&pp);
    int a = 3;
    //在這里直接將a變量賦值給一個(gè)指針變量的指向的內(nèi)存單元窑邦。這是不行的,因?yàn)檫@是野指針壕探。
    //*pp = a;
    
    //正確做法應(yīng)該是:給指針pp賦值冈钦,讓其指向一個(gè)有效的內(nèi)存地址。
    pp = &a;
    
    printf("%d\n",*pp);
    //常見錯(cuò)誤2:指針類型錯(cuò)誤
    
    double d = 3.14;
    //給指針變量賦值錯(cuò)了數(shù)據(jù)類型的地址李请。
    //pp = &d;
    
    return 0;
}

指針的長(zhǎng)度

  • 在 32 位操作系統(tǒng)中瞧筛,指針的長(zhǎng)度是 4 個(gè)字節(jié),在 64 位操作系統(tǒng)中导盅,指針的長(zhǎng)度是 8 位较幌。

  • 那為什么還要給指針分不同的類型呢?

    因?yàn)樵谧鲋羔樜灰茣r(shí)白翻,需要計(jì)算指針位移運(yùn)算乍炉。

多級(jí)指針&多級(jí)指針的訪問

多級(jí)指針的訪問

引用傳遞

#include<stdio.h>

//引用傳遞
void swap(int *a ,int *b){
    
    int temp = *a;
    
    *a = *b;
    
    *b = temp;
    
}
int main() {
    
    int a = 10;
    
    int b = 20;
    
    swap(&a,&b);
    
    printf("a = %d\n",a);
    printf("b = %d\n",b);
    return 0;
}

主函數(shù)獲取子函數(shù)的變量的內(nèi)存地址

#include<stdio.h>
//錯(cuò)誤版本
//void function(int* p){
//
//    int i = 3;
//    p = &i;
//    printf("i 的地址是%p\n",&i);
//}


//i 的地址是0x7fff4fda8994
//mainp指針存放的地址是:0x7fff4fda89e8
//int main() {
//
//
//    //定義一個(gè)可以接收地址的指針
//    int* mainp;
//
//    function(mainp);
//
//    printf("mainp指針存放的地址是:%p\n",mainp);
//    return 0 ;
//}

//正確版本
void function(int** p){
    
    int i = 3;
    *p = &i;
    printf("i 的地址是%p\n",&i);
}


//i 的地址是0x7fff5607a994
//mainp指針存放的地址是:0x7fff5607a994
int main() {
    
    
    //定義一個(gè)可以接收地址的指針
    int* mainp;
    
    function(&mainp);
    
    printf("mainp指針存放的地址是:%p\n",mainp);
    return 0 ;
}

常見錯(cuò)誤

  • 指針沒賦值就使用,沒賦值的指針叫野指針
  • 指針類型弄錯(cuò)滤馍,給int型指針指定了一個(gè)非int型數(shù)據(jù)的地址

數(shù)組

  • C語言的數(shù)組不檢測(cè)越界
  • 數(shù)組的內(nèi)存地址是連續(xù)的空間
  • 數(shù)組變量名保存的地址就是數(shù)組第0個(gè)元素的地址
  • 內(nèi)存地址可以加減運(yùn)算
  • 內(nèi)存地址+1表示右移一個(gè)單位
  • 指針的長(zhǎng)度就是4個(gè)字節(jié)
  • 不同的指針類型的長(zhǎng)度都是一樣的岛琼,分不同類型的指針是在位移時(shí)比較方便。
#include <stdio.h>


int main(){
    
    char c[] = "hello";
    
    printf("第8個(gè)元素的值是%c\n",c[8]);//c語言的數(shù)組是不檢測(cè)越界巢株。
    
    //數(shù)組每一個(gè)元素的地址都是連續(xù)的槐瑞。
    printf("c[0]的地址%#x\n",&c[0]);//c[0]的地址0xeef9f98a
    printf("c[1]的地址%#x\n",&c[1]);//c[1]的地址0xeef9f98b
    printf("c[2]的地址%#x\n",&c[2]);//c[2]的地址0xeef9f98c
    printf("c[3]的地址%#x\n",&c[3]);//c[3]的地址0xeef9f98d
    printf("c[4]的地址%#x\n",&c[4]);//c[4]的地址0xeef9f98e
    
    //打印數(shù)組變量名字的地址
    printf("c數(shù)組變量名字的地址是%#x\n",&c);//c數(shù)組變量名字的地址是0xeef9f98a
    
    int data[] = {1,2,3,4,5};
    
    //數(shù)組每一個(gè)元素的地址都是連續(xù)的。整型數(shù)據(jù)每一個(gè)元素之間相差4個(gè)字節(jié)
    printf("data[0]的地址%#x\n",&data[0]);//data[0]的地址0xe538f970
    printf("data[1]的地址%#x\n",&data[1]);//data[1]的地址0xe538f974
    printf("data[2]的地址%#x\n",&data[2]);//data[2]的地址0xe538f978
    printf("data[3]的地址%#x\n",&data[3]);//data[3]的地址0xe538f97c
    printf("data[4]的地址%#x\n",&data[4]);//data[4]的地址0xe538f980
    
    //打印數(shù)組變量名字的地址
    printf("data數(shù)組變量名字的地址是%#x\n",&data);//data數(shù)組變量名字的地址是0xe538f970
    //打印的數(shù)組變量和打印數(shù)組變量的地址是一樣的纯续,都是表示數(shù)組第一個(gè)元素的地址随珠。
    printf("data數(shù)組變量是%#x\n",data);//data數(shù)組變量名字的地址是0xe538f970
    
    //數(shù)組變量名字的地址就是數(shù)組第一個(gè)元素的地址
    
    
    //內(nèi)存地址是可以進(jìn)行加減運(yùn)算的。
    //定義一個(gè) cp 指針猬错,存放數(shù)組cy首元素的地址
    //指針+1表示內(nèi)存地址位移一位
    char* cp = &c;
    
    printf("第1個(gè)元素的值%c\n",*(cp+0));//h
    printf("第2個(gè)元素的值%c\n",*(cp+1));//e
    printf("第3個(gè)元素的值%c\n",*(cp+2));//l
    printf("第4個(gè)元素的值%c\n",*(cp+3));//l
    printf("第5個(gè)元素的值%c\n",*(cp+4));//o
    
    int* datap = &data;
    
    printf("第1個(gè)元素的值%d\n",*(datap+0));//1
    printf("第2個(gè)元素的值%d\n",*(datap+1));//2
    printf("第3個(gè)元素的值%d\n",*(datap+2));//3
    printf("第4個(gè)元素的值%d\n",*(datap+3));//4
    printf("第5個(gè)元素的值%d\n",*(datap+4));//5
    
}

數(shù)組與指針的關(guān)系

如何用指針表示數(shù)組

int a[] = {1,2,3,4};
    
//使用指針p存放數(shù)組a首個(gè)元素的地址窗看。
int *p = a;

如何通過指針訪問數(shù)組元素

//使用指針修改數(shù)組的值
*(p+0) = 10;

示例代碼

#include<stdio.h>

int main() {
    
    int a[] = {1,2,3,4};
    
    //使用指針p存放數(shù)組a首個(gè)元素的地址。
    int *p = a;
    
    printf("數(shù)組變量:%p\n",a);//0x7ffeede7d960
    printf("指針地址:%p\n",p);//0x7ffeede7d960
    
    //使用指針修改數(shù)組的值
    *(p+0) = 10;
    
    printf("指針訪問數(shù)組元素:%d\n",*(p+0));
    
    return 0;
}

常見錯(cuò)誤

  • 指針沒賦值就使用倦炒,沒賦值的指針叫野指針
  • 指針類型弄錯(cuò)显沈,給int型指針指定了一個(gè)非int型數(shù)據(jù)的地址
#include<stdio.h>
int main() {
    int * p;
    int a = 1;
    double d = 4.0;
    
    
    //printf("%p\n",&p);//指針沒有指向不能輕易使用,它是一個(gè)野指針
    
    p = &a;
    
    printf("*p = %d\n",*p);//*p = 1
    
    //指針指向地址存放的類型必須和聲明指針的類型一致
    //p = & d;
    
    return 0;
}

堆與棧

  • 棧是自動(dòng)分配,自動(dòng)釋放
  • 大小固定
  • 從棧分配的內(nèi)存空間叫靜態(tài)內(nèi)存

  • malloc或者new申請(qǐng)
  • c語言需要用free釋放
  • 從堆分配內(nèi)存空間叫動(dòng)態(tài)內(nèi)存
  • realloc 是在原來的基礎(chǔ)上再分配內(nèi)存空間

malloc

  • 動(dòng)態(tài)申請(qǐng)內(nèi)存空間
  • 一個(gè)malloc申請(qǐng)出來的內(nèi)存地址是連續(xù)的
  • malloc(需要申請(qǐng)的字節(jié)數(shù)) 返回一個(gè)指針

malloc 的圖解

malloc 的圖解

示例代碼

#include <stdio.h>
#include <stdlib.h>


int main() {
    
    int len ;
    
    printf("請(qǐng)輸入數(shù)組的長(zhǎng)度\n");
    
    scanf("%d",&len);
    
    //malloc動(dòng)態(tài)分配內(nèi)存拉讯,p指針指向首字節(jié)地址
    int *p = (int*)malloc(sizeof(int)*len);
    

    for(int i = 0;i<len;i++){
        *(p+i) = i*10;
    }
    
    
    for(int i = 0;i<len;i++){
        printf("第%d個(gè)數(shù)據(jù)是%d\n",(i+1),p[i]);
    }
    
    printf("p指針變量的地址:%p\n",p);
    printf("第1個(gè)元素的值:%d\n",*(p));
    
    
    
    int a = p[1];
    printf("malloc 分配的內(nèi)存空間指針相當(dāng)于一個(gè)數(shù)組涤浇,%d\n",a);
    
    //釋放在堆中動(dòng)態(tài)分配的內(nèi)存空間;
    //free()釋放的是指針指向的內(nèi)存魔慷。指針變量依然存在只锭,只有程序結(jié)束時(shí)才被銷毀。不過現(xiàn)在指針指向的內(nèi)容是未定義的垃圾院尔,所以現(xiàn)在指針又成為了野指針蜻展。
    //void free(void *FirstByte):該函數(shù)是將之前用malloc分配的空間還給程序或者是操作系統(tǒng),也就是釋放了這塊內(nèi)存邀摆,讓它重新得到自由纵顾。
    free(p);
    
    printf("p指針變量的地址:%p\n",p);
    printf("第1個(gè)元素的值:%d\n",*(p));
    
    for(int i = 0;i<len;i++){
        printf("第%d個(gè)數(shù)據(jù)是%d\n",(i+1),p[i]);
    }
    
    /**
     
     在 Mac OS 系統(tǒng):
     
        free(p) 之后 *P 沒有變化,p的地址沒有發(fā)生變化
     
     
     在 Linux 系統(tǒng):
     
        free(p) 之后 *p 的值不再是 free 之前的值
     */
     
           
    return 0;
}

realloc

重新分配主存

示例代碼

#include <stdio.h>
#include <stdlib.h>


int main() {
    
    int len ;
    
    printf("請(qǐng)輸入數(shù)組的長(zhǎng)度\n");
    
    scanf("%d",&len);
    
    //malloc動(dòng)態(tài)分配內(nèi)存栋盹,p指針指向首字節(jié)地址
    int *p = (int*)malloc(sizeof(int)*len);
    

    for(int i = 0;i<len;i++){
        *(p+i) = (i+1)*10;
    }
    
    
    for(int i = 0;i<len;i++){
        printf("第%d個(gè)數(shù)據(jù)是%d\n",(i+1),p[i]);
    }
    
    for(int i = 0;i<len;i++){
        printf("指針p[%d]的地址是:%p\n",(i+1),(p+i));
    }
    
    int size = 0;
    printf("請(qǐng)輸入需要補(bǔ)充的值\n");
    scanf("%d",&size);
    
    
    
    p = (int *)realloc(p,size+len);
    
    for(int i = 0;i<len+size;i++){
        *(p+i) = (i+1)*10;
    }
    
    for(int i = 0;i<len+size;i++){
        printf("第%d個(gè)數(shù)據(jù)是%d\n",(i+1),p[i]);
    }
    
    
    for(int i = 0;i<len+size;i++){
        printf("指針p[%d]的地址是:%p\n",(i+1),(p+i));
    }
    
    
    
    free(p);
    
    
    
    return 0;
}

/*
 
 realloc函數(shù)的使用
 
 函數(shù)名: realloc
 功  能: 重新分配主存
 用  法: void *realloc(void *ptr, unsigned newsize);
 
 在指針 ptr 后面分配新的內(nèi)存空間施逾。
 
 請(qǐng)輸入數(shù)組的長(zhǎng)度
 4
 第1個(gè)數(shù)據(jù)是10
 第2個(gè)數(shù)據(jù)是20
 第3個(gè)數(shù)據(jù)是30
 第4個(gè)數(shù)據(jù)是40
 指針p[1]的地址是:0x7fd4e7402ab0
 指針p[2]的地址是:0x7fd4e7402ab4
 指針p[3]的地址是:0x7fd4e7402ab8
 指針p[4]的地址是:0x7fd4e7402abc
 請(qǐng)輸入需要補(bǔ)充的值
 3
 第1個(gè)數(shù)據(jù)是10
 第2個(gè)數(shù)據(jù)是20
 第3個(gè)數(shù)據(jù)是30
 第4個(gè)數(shù)據(jù)是40
 第5個(gè)數(shù)據(jù)是50
 第6個(gè)數(shù)據(jù)是60
 第7個(gè)數(shù)據(jù)是70
 指針p[1]的地址是:0x7fd4e7402ab0
 指針p[2]的地址是:0x7fd4e7402ab4
 指針p[3]的地址是:0x7fd4e7402ab8
 指針p[4]的地址是:0x7fd4e7402abc
 指針p[5]的地址是:0x7fd4e7402ac0
 指針p[6]的地址是:0x7fd4e7402ac4
 指針p[7]的地址是:0x7fd4e7402ac8
 */

自定義類型

結(jié)構(gòu)體

  • 結(jié)構(gòu)體的定義
//1.定義一個(gè)結(jié)構(gòu)體
struct Student {
    int age;
    char *name;
    char sex;
    //eatp表示函數(shù)指針的名字
    void(*eatp)();
};
  • 結(jié)構(gòu)體成員的賦值
//方式1 
struct Student st = {        
    11,"張三",'m'
};

//方式2
//給結(jié)構(gòu)體內(nèi)的成員賦值
st.age = 12;
st.name = "李四";
st.sex = 'm';
  • 結(jié)構(gòu)體函數(shù)指針

結(jié)構(gòu)體內(nèi)指針不能定義函數(shù),只能定義函數(shù)指針例获。

//給結(jié)構(gòu)體指針賦值
st.eatp = eat;
  • 結(jié)構(gòu)體成員的使用
//用結(jié)構(gòu)體變量引用變量
 printf("年齡:%d\n名字:%s\n性別:%c\n",st.age,st.name,st.sex);
 
 //用指針變量的方式引用結(jié)構(gòu)體屬性
struct Student *p = &st;
printf("年齡:%d\n名字:%s\n性別:%c\n",(*(p)).age,(*(p)).name,(*(p)).sex);
#include<stdio.h>

void eat() {
    printf("學(xué)生吃飯\n");
}

struct Student {
    int age;
    char *name;
    char sex;
    //eatp表示函數(shù)指針的名字
    void(*eatp)();
};

int main(void){

    //定義一個(gè)結(jié)構(gòu)體變量汉额,并給結(jié)構(gòu)體成員賦值
//    struct Student st = {
//        11,"張三",'m'
//    };
    
    
    struct Student st ;

    //給結(jié)構(gòu)體內(nèi)的成員賦值
    st.age = 12;
    st.name = "李四";
    st.sex = 'm';
    //給結(jié)構(gòu)體指針賦值
    st.eatp = eat;
   //輸出結(jié)構(gòu)體成員的值

    printf("年齡:%d\n名字:%s\n性別:%c\n",st.age,st.name,st.sex);
    
    
    struct Student *p = &st;
    
    
    printf("年齡:%d\n名字:%s\n性別:%c\n",(*(p)).age,(*(p)).name,(*(p)).sex);
    
    
    printf("年齡:%d\n名字:%s\n性別:%c\n",p->age,p->name,p->sex);
    //調(diào)用結(jié)構(gòu)體指針。
    p->eatp();
    return 0;
}

文件處理

  • 文件處理流程
    • 打開文件
    • 文件的處理
      • fwrite寫入
      • fread讀取
      • rewind 將文件游標(biāo)指向文件的開頭
    • 關(guān)閉文件

示例代碼

//文件的操作
#include<stdio.h>


int main(void){
    
    //定義一個(gè)文件類型的變量
    
    FILE *file = NULL;
    
    //打開文件
    //FILE *fopen(char *filename, char *type);
    //a+ 表示 append 追加 +表示如果沒有這個(gè)文件就創(chuàng)建一個(gè)文件
    
    file = fopen("hello.txt","a+");
    
    char *str = "hello world";
    
    //int fwrite(void *ptr, int size, int nitems, FILE *stream);
    fwrite(str,1,11,file);
    
    
    //將文件指針重新指向一個(gè)流的開頭
    //int rewind(FILE *stream);
    //因?yàn)槲募拇蜷_mode是 a+ 追加的方式躏敢,所以要將處理文件的指針指向一個(gè)流的開頭闷愤。才能讀取到數(shù)據(jù)
    rewind(file);
    char buf[1024] = {};
    //讀出來
    // int fread(void *ptr, int size, int nitems, FILE *stream);
    fread(buf,1,11*2,file);
    
    printf("讀出來的數(shù)據(jù)是%s\n",buf);
    
    fclose(file);
    
    return 0;
}
/*
 "r" = "rt"
 打開一個(gè)文本文件,文件必須存在件余,只允許讀
 "r+" = "rt+"
 打開一個(gè)文本文件讥脐,文件必須存在,允許讀寫
 "rb"
 打開一個(gè)二進(jìn)制文件啼器,文件必須存在旬渠,只允許讀
 “rb+”
 打開一個(gè)二進(jìn)制文件,文件必須存在端壳,允許讀寫
 "w" = “wt”
 新建一個(gè)文本文件告丢,已存在的文件將被刪除,只允許寫
 "w+" = "wt+"
 新建一個(gè)文本文件损谦,已存在的文件將被刪除岖免,允許讀寫
 “wb”
 新建一個(gè)二進(jìn)制文件,已存在的文件將被刪除照捡,只允許寫
 “wb+”
 新建一個(gè)二進(jìn)制文件颅湘,已存在的文件將被刪除,允許讀寫
 "a" = "at"
 打開或新建一個(gè)文本文件栗精,只允許在文件末尾追寫
 "a+" = "at+"
 打開或新建一個(gè)文本文件闯参,可以讀瞻鹏,但只允許在文件末尾追寫
 “ab”
 打開或新建一個(gè)二進(jìn)制文件,只允許在文件末尾追寫
 “ab+”
 打開或新建一個(gè)二進(jìn)制文件鹿寨,可以讀新博,但只允許在文件末尾追寫
 對(duì)于文件使用方式有以下幾點(diǎn)說明:
 1) 文件使用方式由r,w,a,t,b,+六個(gè)字符拼成脚草,各字符的含義是:
 r(read): 只讀
 w(write): 只寫
 a(append): 追加
 t(text): 文本文件赫悄,可省略不寫
 b(binary): 二進(jìn)制文件
 */

C語言的編譯器

編譯命令

編譯 c 代碼,不同的操作系統(tǒng)使用的編譯工具不一樣馏慨,Mac OS 使用的 clang 涩蜘,Linux 使用的是 gcc

gcc/clang -g -o main main.c -I 關(guān)聯(lián)的頭文件位置 -L 關(guān)聯(lián)的庫(kù)位置 -l關(guān)聯(lián)的庫(kù)名字 -l關(guān)聯(lián)的庫(kù)名字2...

編譯過程

.c (預(yù)處理) -> .i 文件(編譯) -> .s(匯編) -> .o(鏈接) -> 可執(zhí)行文件

預(yù)處理

獲取預(yù)處理后的.i文件

  • 編寫一個(gè) helloworld.c 文件
  • gcc 進(jìn)行編譯
  • gcc -o helloworld.i helloworld.c -E 在當(dāng)前目錄下得到一個(gè) hellowold.i 文件

helloworld.i文件

查看這個(gè)文件可以知道,在 .c 預(yù)處理之后的 helloworld.i 文件可以看出熏纯,源碼會(huì)被保留,并且會(huì)將頭文件的內(nèi)容寫到出頭文件的內(nèi)容上面粤策。

  • 編譯關(guān)聯(lián)庫(kù)的c文件為add.out
clang -c add.c -o add.out
  • 編譯靜態(tài)庫(kù)

將 add.out 編譯為靜態(tài)庫(kù) mylib

libtool -static -o libmylib.a add.out
  • 編譯帶有main函數(shù)的main.c文件
clang -o main main.c -I . -L . -lmylib
  • 執(zhí)行最終編譯后的文件
./main

源代碼如下

  • main.c
#include<stdio.h>
#include "add.h"
int main(void){  
    int result = add(1,2);
    printf("輸出結(jié)果是%d\n",result);
    return 0;
}
  • add.h
int add(int a,int b);
  • add.c
#include<stdio.h>
#include "add.h"
int add(int a,int b){
    return a+b;
}

宏定義

就是將 #define 定義的內(nèi)容安裝字符串進(jìn)行替換樟澜。

#include<stdio.h>

//宏定義是沒有c語言語法規(guī)則的,因此可以不需要寫;
#define R 10
#define _main int main(
//傳遞參數(shù)
#define N(n) n*10
//定義一個(gè)加法運(yùn)算的宏
//對(duì)比一個(gè)函數(shù)來說叮盘,這樣定義宏的好處是什么秩贰?
//1.它的參數(shù)的類型不限制
//2.返回值類型不限制
#define ADD(a,b) a+b
_main) {
    
    int a = R;
    
    printf("a = %d\n",a);
    
    
    int b = N(5);
    printf("b = %d\n",b);
    
    
    int c = ADD(5,6);
    printf("c = %d\n",c);
    
    
    float d = ADD(5,6.3);
    printf("d = %f\n",d);
    
    //注意:宏定義只是將字符串進(jìn)行替換操作,不會(huì)考慮一些邏輯運(yùn)算符關(guān)系的柔吼,需要手動(dòng)控制毒费。
    //2+3*4+5 = 2+12+5 = 19
    int e = ADD(2,3)*ADD(4,5);
    
    int f = (ADD(2,3))*(ADD(4,5));
    
    printf("e = %d\n",e);//19
    printf("f = %d\n",f);//45 正確的
    return 0;
}

類型定義 typedef

一般會(huì)是用于給自定義類型起別名,例如在jni中愈魏,就大量的使用了typedef來將c的類型起別名為java類型觅玻。

typedef int tni;

int main() {
    //在預(yù)處理后的.i文件,這里的tni并不會(huì)像宏定義一樣被替換培漏。
    tni a = 10;

    printf("a = %d\n",a);

    return 0;
}

聯(lián)合體

  • 可以將不同類型的變量定義在同一塊內(nèi)存空間中溪厘,并且同一時(shí)間只有一個(gè)變量會(huì)被存儲(chǔ)。
  • union 關(guān)鍵字
#include<stdio.h>
//1.定義一個(gè)聯(lián)合體data
union data {
    int a;
    int b;
    char c;
};

int main() {
    
    union  data _data;
    
    _data.a = 1;
    _data.b = 2;
    _data.c = 'c';
    
    printf("a = %d\n",_data.a);
    printf("b = %d\n",_data.b);
    printf("c = %c\n",_data.c);
    
    //取出地址牌柄,每一個(gè)變量存儲(chǔ)的地址都是一樣的
    //%p打印地址
    printf("a = %p\n",&_data.a);//0x7fff54c929c8
    printf("b = %p\n",&_data.b);//0x7fff54c929c8
    printf("c = %p\n",&_data.c);//0x7fff54c929c8
    
    
    //這里只會(huì)輸出最后一個(gè)賦值的元素 也就是char c = 'c' 會(huì)被存儲(chǔ)畸悬、其他兩個(gè)會(huì)被 c 覆蓋
    printf("a = %c\n",*(&_data.a));//99
    printf("c = %c\n",_data.c);//99
    return 0;
}

鏈表

靜態(tài)鏈表

  • 預(yù)先定義好一些元素通過指針的方式連接起來的一條鏈子就是鏈表。
  • 先進(jìn)后出
#include<stdio.h>

struct weapon {
    
    int price;
    int atk;
    
    struct weapon * next;
    
};

int main() {
    
    struct weapon a,b,c,*head;
    
    a.price = 100;
    a.atk = 101;
    
    b.price = 200;
    b.atk = 201;
    
    c.price = 300;
    c.atk = 301;
    
    
    //head指向第一個(gè)元素
    head = &a;
    
    a.next = &b;
    
    b.next = &c;
    
    //最后一個(gè)元素的next屬性為空
    c.next = NULL;
    
    
    struct weapon *p;
    p = head;
    while(p!=NULL){
        printf("price = %d,atk = %d\n",p->price,p->atk);
        
        //下面兩種方式都行
        //p = (*p).next;
        p = p->next;
        
    }
    return 0;
}

動(dòng)態(tài)鏈表

動(dòng)態(tài)的往鏈表中添加數(shù)據(jù)

#include<stdio.h>
//mac下<malloc.h>頭文件找不到珊佣,具體原因未查明
#include<mm_malloc.h>

struct weapon {
    int price;
    int atk;
    struct weapon *next;
    
};


struct weapon * create() {
    struct weapon *head;//指向第一個(gè)元素
    struct weapon *p1,*p2;//p1指向當(dāng)前輸入的元素蹋宦,p2指向上一個(gè)元素
    
    int n = 0;//表示輸入的元素的次數(shù)
    
    p1 = p2 = (struct weapon*)malloc(sizeof(struct weapon));
    
    //p1->atk = 10;
    //p1指向的是一個(gè) weapon 結(jié)構(gòu)體
    //我們向往這個(gè)結(jié)構(gòu)體里面的屬性賦值,首先就需要取出結(jié)構(gòu)體的元素的地址: &(p->price)
    

    //下面兩種輸入方式都可以
    scanf("%d,%d",&(p1->price),&p1->atk);
    
    head = NULL;
    
    while (p1->price!=0) {
        n++;
        
        if(n == 1){
            //第一次輸入咒锻,保存到head中
            head = p1;
        }else{
            p2->next = p1;
        }
        //p2指向上一個(gè)元素(相對(duì)下一次循環(huán)來說的)
        p2 = p1;
        
        //給p1重新分配內(nèi)存空間
        p1 = (struct weapon*)malloc(sizeof(struct weapon));
        scanf("%d,%d",&p1->price,&p1->atk);
    }
    
    p2->next = NULL;
    return head;
    
}

int main(){
    struct weapon * head = create();
    while (head!=NULL) {
    
        printf("price = %d,atk = %d\n",head->price,head->atk);
        
        //下面兩種方式都行
        //p = (*p).next;
        head = head->next;
    }
    return 0;
}

工具

我們?cè)谑褂?c 語言開發(fā)時(shí)冷冗,不可能將所有的 API都記住,因此我們應(yīng)該常備 API文檔在身虫碉,在 Mac平臺(tái)比較好用的應(yīng)該就是 Dash 了贾惦。

Dash 可以下載不同語言的 API 文檔,非常方便,推薦大家使用.

image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末须板,一起剝皮案震驚了整個(gè)濱河市碰镜,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌习瑰,老刑警劉巖绪颖,帶你破解...
    沈念sama閱讀 217,734評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異甜奄,居然都是意外死亡柠横,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門课兄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來牍氛,“玉大人,你說我怎么就攤上這事烟阐“峥。” “怎么了?”我有些...
    開封第一講書人閱讀 164,133評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵蜒茄,是天一觀的道長(zhǎng)唉擂。 經(jīng)常有香客問我,道長(zhǎng)檀葛,這世上最難降的妖魔是什么玩祟? 我笑而不...
    開封第一講書人閱讀 58,532評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮屿聋,結(jié)果婚禮上空扎,老公的妹妹穿的比我還像新娘。我一直安慰自己润讥,他們只是感情好勺卢,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,585評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著象对,像睡著了一般黑忱。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上勒魔,一...
    開封第一講書人閱讀 51,462評(píng)論 1 302
  • 那天甫煞,我揣著相機(jī)與錄音于未,去河邊找鬼杨名。 笑死,一個(gè)胖子當(dāng)著我的面吹牛斥黑,可吹牛的內(nèi)容都是我干的弟胀。 我是一名探鬼主播楷力,決...
    沈念sama閱讀 40,262評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼喊式,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了萧朝?” 一聲冷哼從身側(cè)響起岔留,我...
    開封第一講書人閱讀 39,153評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎检柬,沒想到半個(gè)月后献联,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,587評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡何址,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,792評(píng)論 3 336
  • 正文 我和宋清朗相戀三年里逆,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片用爪。...
    茶點(diǎn)故事閱讀 39,919評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡原押,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出偎血,到底是詐尸還是另有隱情班眯,我是刑警寧澤,帶...
    沈念sama閱讀 35,635評(píng)論 5 345
  • 正文 年R本政府宣布烁巫,位于F島的核電站,受9級(jí)特大地震影響宠能,放射性物質(zhì)發(fā)生泄漏亚隙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,237評(píng)論 3 329
  • 文/蒙蒙 一违崇、第九天 我趴在偏房一處隱蔽的房頂上張望阿弃。 院中可真熱鬧,春花似錦羞延、人聲如沸渣淳。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽入愧。三九已至,卻和暖如春嗤谚,著一層夾襖步出監(jiān)牢的瞬間棺蛛,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工巩步, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留旁赊,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,048評(píng)論 3 370
  • 正文 我出身青樓椅野,卻偏偏與公主長(zhǎng)得像终畅,于是被迫代替她去往敵國(guó)和親籍胯。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,864評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 今天小編給大家?guī)韈語言學(xué)習(xí)之路--由淺入深(快速掌握c基礎(chǔ))离福。溫馨提示:亮點(diǎn)在最后杖狼! 1.第一個(gè)C程序:Hell...
    云上傘閱讀 600評(píng)論 0 1
  • 指針是C語言中廣泛使用的一種數(shù)據(jù)類型。 運(yùn)用指針編程是C語言最主要的風(fēng)格之一术徊。利用指針變量可以表示各種數(shù)據(jù)結(jié)構(gòu)本刽; ...
    朱森閱讀 3,444評(píng)論 3 44
  • 媽媽需要保胎住院,不得不讓平安提前入托托班赠涮。早上外公把小伙子送去時(shí)子寓,小家伙還沒有太大的反抗,因?yàn)檫€沒有摸清狀況笋除,以...
    陪娃黨閱讀 167評(píng)論 0 0
  • 千萬別放棄!有了第一次放棄斜友,你的人生就會(huì)習(xí)慣于知難而退,可是如果你克服過去垃它,你的人生則會(huì)習(xí)慣于迎風(fēng)破浪地前進(jìn)鲜屏,看著...
    張偉kk閱讀 115評(píng)論 0 0
  • 一:劇情簡(jiǎn)介 凱撒和他的領(lǐng)導(dǎo)的猿族為求生存與人類交戰(zhàn),在堅(jiān)守家園的同時(shí)也在尋找其它宜居的地方国拇。殘暴的“上新迨罚”領(lǐng)導(dǎo)的...
    道_DS閱讀 542評(píng)論 0 1