程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C >> C語言入門知識 >> C語言基礎

C語言基礎

編輯:C語言入門知識

原碼、反碼、補碼(只跟負數相關)

正數的原碼、反碼、補碼都相同(也就是說原碼、反碼、補碼只跟負數相關) 原碼:把數字轉換成二進制 反碼:除最高位,其他位依次取反 補碼:反碼+1

注意:計算機中使用補碼來表示數據的!!!(由於正數的原碼、反碼、補碼相同,所以在計算機中顯示的二進制(補碼)和我們通過計算把數字轉碼成二進制(原碼)相同)


java基本數據類型

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

C基本數據類型(可通過sizeof函數查看大小)

short:2 int:4 long:4 float:4 double:8 char:1 注:long long 占8個字節,但是並不屬於基本數據類型

有符號(signed)、無符號(unsigned)

int類型,占4個字節(一個字節由八個二進制組成),32位 int類型能表示 2^32 個數字 無符號int類型,取值范圍是:0 ~ (2^32 - 1)
所有32位都表示數值位 有符號int類型,取值范圍是:-2^31 ~ (2^31 - 1)
最高位為符號位,剩下31位作為數值位 當最高位為0時,剩下的31位都表示一個正數 當最高位為1時,剩下的31位都表示一個負數 所以int能表示的最大值是 (2^32 -1) signed:有符號,最高位表示符號位 unsigned:無符號,最高位表示數值位

在c語言中沒有字符串,只能使用字符數組來表示字符串;每個字符數組最後面都有一個結束符\0,所以字符數組的長度都+1;

char c[] = "你好啊hello";

輸入輸出函數

%d  -  int  
%ld – long int  
%lld - long long  
%hd – 短整型  
%c  - char  
%f -  float  
%lf – double  
%u – 無符號數  
%x – 十六進制輸出 int 或者long int 或者short int  
%o -  八進制輸出  
%s – 字符串  
c語言中數組不檢測越界

指針

內存地址

是用十六進制的數字來表示內存地址的 內存中的每一個字節都會有一個地址,地址相當於內存的門牌號

32位系統的地址總線長度是32位的,也就是說系統能分配給內存地址的數量是 2的32次方 個

為什麼32位系統最大只支持4G內存?
因為:系統最多能分配給內存地址的數量是:2^32 個,而每個地址對應一個字節,也就是總共 2^32 b(字節),2^32/1024/1024/1024 = 4G

內存修改器:找到變量所在的地址,然後修改地址上的值

指針變量是用來存儲地址的

一級指針

int* p;// 定義一個 int* 型的指針變量,這個變量只能保存地址,而且保存的地址上存放的數據必須是一個int型(因為:如果你存放其他數據類型,那麼你取那個指針存放的的值時,會取不到值) int i = 3; p = &i;// 將整數3的地址存放到指針p中 *p:引用這個指針所指向的地址上保存的數據

二級指針

int** q;// 定義一個二級指針,二級指針保存的是一級指針的地址

指針如果沒有賦值,那麼就不能使用,此時指針指向的地址是一個隨機值,這種指針叫野指針

值傳遞和引用傳遞

引用傳遞,本質上也是值傳遞,只不過傳遞的這個值是一個地址值

一個函數返回多個值

由於c語言是面向過程的,java是面向對象的,在java中,如果想要讓一個函數返回多個值的話,可以將函數中要返回的數據封裝成對象,然後就可以返回多個值了。 而在c語言中,一個函數只能返回一個值,

        #include
        #include
        void function(int* p,int* q){
            *p += 5;
            *q += 5;
        }
        main(){
            int i = 3;
            int j = 5;
            function(&i,&j);

            printf("%d\n",i);// 8 直接修改內存地址保存的數據值
            printf("%d\n",j);// 10

            system("pause");
        }

子函數獲取主函數變量的地址

#include
    #include 

    void function(int* p){
         printf("%#x\n",p);// 0x28ff44
    }

    main(){
        int i = 3;
        function(&i);
        printf("%#x\n",&i);// 0x28ff44
        system("pause");
    }

主函數獲取子函數變量的地址

#include
    #include 

    void function(int** p){
         int i = 3;
         *p = &i;
         printf("i的地址為%#x\n",&i);// 0x28ff44
    }

    main(){
        int* mainp;
        function(&mainp);
        printf("主函數獲取到i的地址為:%#x\n",mainp);// 0x28ff14,這裡打印的是mainp的值,而mainp是一個指針,所以它的值是一個地址
        printf("主函數獲取到i的值為:%d\n",*mainp);//這裡獲取不到正確的值,因為函數中的變量,在函數結束之後會被銷毀。但是當注釋掉前面兩個打印語句之後,可以打印出3這個值,這是因為那個函數中的變量還沒來得及銷毀,所以你取出的值是一個"幻值",這種做法是不正確的
        system("pause");
    }
int i = 3; 那麼i的值就是3;int* p = &i; p的值是一個地址值(i的地址)

數組

數組每一個元素的地址都是連續的,數組是一個連續的內存空間 數組名保存的其實是第0個元素的地址 通過首地址的運算,就可以拿到每一個數組中每一個元素

指針的運算

    int i[] ={1,2,3};
    int* p = &i;
    *P   // 1
    *(p+1) // 2
    char* q = &i;
    *q // 1
    *(q+4) // 2  注意:這裡如果寫成*(q+1)是錯誤的!!!因為數組中存儲的是int型,每個元素占4個字節,指針應該向右位移4個字節才能拿到下一個元素
+1表示向右位移一個單位,一個單位是多少個字節,看指針類型而定;如果指針式int型的,那麼位移一個單位是4個字節,而如果指針類型是char型的,那麼位移一個單位是1個字節!

指針的長度

32位操作系統 指針長度4個字節,跟類型無關 64位操作系統 指針長度8個字節,跟類型無關 int* p和double* q的指針長度相同

堆和棧的區別:

(1) 在棧上分配的內存,叫靜態內存
(2) 在堆上分配的內存,叫動態內存

區別:

申請方式

棧: 由系統自動分配,後進先出,由系統釋放這個空間 堆: 需要程序員自己申請,並指明大小,在c中用malloc函數
如char* p1 = (char*) malloc(10); //14byte (雖然程序員申請了10個字節,但是由於p1是一個指針,指針的長度是4個字節,也就是占用4個字節,指針是保存在棧內存中,所以那句語句總共占用14個字節的空間)
但是注意p1本身是在棧中的

系統申請後的反應

棧:只要棧的剩余空間大於所申請空間,系統將為程序提供內存,否則將報異常提示棧溢出。 堆:首先應該知道操作系統有一個記錄空閒內存地址的鏈表,當系統收到程序的申請時,會遍歷該鏈表,尋找第一個空間大於所申請空間的堆結點,然後將該結點從空閒結點鏈表中刪除,並將該結點的空間分配給程序,另外,對於大多數系統,會在這塊內存空間中的首地址處記錄本次分配的大小,這樣,代碼中的delete語句才能正確的釋放本內存空間。另外,由於找到的堆結點的大小不一定正好等於申請的大小,系統會自動的將多余的那部分重新放入空閒鏈表中。

申請大小的限制

棧:在Windows下,棧是向低地址擴展的數據結構,是一塊連續的內存的區域。棧頂的地址和棧的最大容量是系統預先規定好的,在WINDOWS下,棧的大小是2M,如果申請的空間超過棧的剩余空間時,將提示overflow。因此,能從棧獲得的空間較小。

堆:堆是向高地址擴展的數據結構,是不連續的內存區域。大小跟硬件有關

申請效率的比較

棧:由系統自動分配,速度較快。但程序員是無法控制的。 堆:由malloc/new分配的內存,一般速度比較慢,而且容易產生內存碎片,不過用起來最方便.

堆和棧中的存儲內容

棧:函數的各個參數、局部變量等。注意靜態變量是不入棧的。 堆:堆中的具體內容有程序員安排。

內存的回收

棧上分配的內存,編譯器會自動收回 堆上分配的內存,要通過free來顯式地收回,否則會造成內存洩漏。

堆內存申請

使用malloc函數申請堆內存
int* p = malloc(4 * 10);// 申請了40個字節大小的空間,並且申請的這40個空間是連續的,返回的是堆內存地址(用一個指針p接收)

釋放申請的堆內存
free(p);

realloc函數的使用

#include    
    #include      

     main(){
     printf("請輸入班級人數:");
     int count;
     scanf("%d", &count);

     int* p = malloc(count * sizeof(int));

     int i;
     for(i = 1; i <= count; i++){
           printf("請輸入第%d個學生的學號:", i);
           scanf("%d", p + i - 1);
     }

     printf("請輸入插班人數:");
     int newCount;
     scanf("%d", &newCount);

     //現在原來舊的堆內存後面,擴展新的空間 
     //如果舊堆內存後面的空間已經被別的程序占用了,那麼就無法擴展 
     //如果不能擴展,就會尋找一個塊足夠大的內存區域,申請新的堆內存 ,並且會把舊堆內存的數據復制到新的堆內存中 
     //釋放舊的堆內存 
     p = realloc(p , (count + newCount) * sizeof(int));

     for(i = count + 1; i <= count + newCount; i++){
           printf("請輸入第%d個學生的學號:", i);
           scanf("%d", p + i - 1);
     }    

     for(i = 1; i <= count + newCount; i++){
           printf("第%d個學生的學號為%d\n", i, *(p + i - 1));      
     }

      system("pause");
    }

結構體

struce 關鍵字 定義結構體
第一種
struct Student
{
  int age;
  float score;
  char sex;
}

第二種

struct Student2
{
 int age;
 float score;
 char sex;
} st2;

第三種

struct
{
 int age;
 float score;
 char sex;
} st3
結構體中不能定義函數,但是可以定義函數指針 函數也是保存在棧內存中,就像定義變量一樣 結構體長度不固定,具體長度通過sizeof()得到
    #include 
        #include 

        void study(){
             printf("天天打怪獸\n");    
        } 

        // 定義結構體 
        // 結構體中不能定義函數,但是可以定義函數指針 
        struct student{
              int age;
              int height;
              char sex;       
                      void(*studyp)();//studyp 函數指針名 
        };
        main(){
              struct student std = {20,180,'f',study};// std 結構體變量
              printf("芳齡%d\n",std.age); 
              std.studyp();// 第一種方法 
              struct student* stdp = &std;
              (*stdp).studyp(); // 第二種方法 
              // ->左邊必須是結構體的一級指針,右邊是函數指針名字 
              stdp->studyp();// 第三種方法(開發中一般使用這種 ) 

              system("pause");
        }

聯合體

聯合體作用就是:聯合體變量可以被賦值聯合體定義的任意類型
    #include
    #include
    main(){
        union{int i; char c; short s} un;
        un.i = 30;
        un.s = 20;         
        printf("%d\n",un.i);
       // 20 聯合體同時只能有一個值,後面的值會把前面賦給聯合體變量的值覆蓋掉 
        printf("%d\n",sizeof(un));
        // 4個字節 聯合體長度取變量中的最大值 int 
           system("pause");      
    }

枚舉

#include 

    enum WeekDay
    {
    Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday
    };

    int main(void)
    {
      //int day;
      enum WeekDay day = Sunday;// 只能從定義中的內容取,否則報錯 
      printf("%d\n",day); // 6
      system("pause");
      return 0;
    }

自定義類型

typedef newName oldType;

    #include
    #include

    // hehe這個時候跟int的作用一樣,相當於給int起了個別名 
    typedef int hehe;
    main(){
           hehe i = 3;
           printf("%d\n", i);// 3 
           system("pause");
    } 
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved