C語言學習筆記--基礎語法二

C語言基礎部分二

1、函數

函數,可以稱爲方法、子例程或程序等等。定義一個函數需要聲明函數名稱、返回類型和參數。函數就是一組執行特定任務和邏輯的代碼語句。C程序至少有一個函數—main();
main函數要有返回值,void類型或者int,float等,有的編譯器要求必須int,需注意這點,有的竟然還可以不寫返回類型,編譯器標準不同,c89,c99,c11之類的,好吧,最好寫上吧。

  • 定義函數

    return_type function_name(parameter list){
    body of the function;
    }

    函數的構成:

    • 返回類型,若有則是返回數據的數據類型,若無則是void,或者不寫。
    • 函數名稱,也就是函數的實際名,與參數列表一起構成函數簽名。
    • 參數,參數類似與佔位符,用於接收傳遞過來的參數,在函數內部調用使用,參數可選,函數可無參數。
    • 函數主體,也就是執行一定的任務邏輯的代碼語句。
    /*
    * 函數返回兩個數字中較大的那個數。
    */
    int max(int num1,int num2){
    //聲明局部變量
    int result;
    if(num1>num2){
      result = num1;
    }esle{
      result = num2;
    }
    return result;
    }

    Note:函數聲明包含返回類型、函數名、參數列表。而不必有函數主體。

    C語言中,函數聲明參數列表中的參數名並不重要,只要有參數類型亦可。

    //如此也是合法的
    int max(int,int);

    函數參數多類似爲形式參數,調用者需要傳遞實際參數。

調用類型 描述
傳值調用 調用方將數值傳遞給形參,如果形參在函數內修改數值,但不會形象到外部的實際參數值。C 語言多用此方式。
引用調用 調用方將參數的地址複製給形參,此時在函數內形參修改數值,會同步影響到外部實際參數的。
指針形式 通過指針傳遞的方式,形參爲實參的指針,操作會影響到實際參數的數據。

- 作用域

任何一個編程語言中,定義的變量都應有其作用範圍,稱爲作用域

  • 局部變量,作用與函數內。
  • 全局變量,作用與函數外部所有範圍。
  • 形式參數,在函數的參數定義中,也就在函數內有效。類似局部變量了。

    C語言中,函數的局部參數可以和全局參數同名稱,但是內部僅使用局部變量的值。局部變量需要手動初始化,全局變量會自動初始化。

    • 數組

    C語言數組和Java的數組類似,用於存儲一類相同類型的數值,聲明一個變量,用序列編號指定元素數據。

元素 元素 元素 元素
numbers[0] numbers[1] …… numbers[n]

聲明與初始化:

  //聲明
  type arrayName[arraySize]
  double balance[10];
  double balance[3] = {12.0,3.5,8.8};
  double balance[] = {7.9,0.1,3.2}
  //單個元素賦值
  balacne[0] = 8.9;

數組的訪問使用數組下標,從左至右依次爲0—-n,某個元素則爲arrayName[i];

概念 描述
多維數組 即數組的元素又是數組,常見的爲二維數組。
傳遞數組函數 通過指定不帶索引的數組名稱,來給函數傳遞一個數組的指針。也就是作爲形參。
從函數返回數組 函數的返回類型。
指向數組的指針 通過指定不帶索引的數組名稱,來生成一個指向數組中第一個元素的指針。

2、指針

C語言指針是簡單而有趣的一個概念,便於簡化程序任務,比如動態內存分配等。

每一個變量都有一個內存地址,這個地址是有一個編號的。

#include <stdio.h>
void main(){
  int var1;
  char var2[10];
  //printf函數參數爲可變參數,必有string哦,不然會報錯。和java不同。
  printf("var1變量的地址:%x \n",&var1);
  printf("varsb變量的地址:%x \n",&var2);
}
  • 指針

    是一個特殊變量,它的值是另一個變量的地址,內存位置的直接地址。類似其他變量和常量,在使用指針存儲其他變量的地址之前,需要聲明和存儲。

    //type爲指針的基類型,var-name爲指針變量的名稱。星號用於標示一個變量是指針。
    type *var-name;
    //指針示例
    int *ip;
    double *dp;
    float *fp;
    char *cp;
    //不管基類型爲何種類型,指針的實際數據類型,都是一個代表內存地址的十六進制數。
  • 如何使用指針

    使用指針涉及以下操作:

    • 定義指針變量
    • 把另一變量地址賦值給指針
    • 訪問指針變量中可用地址的值

    *用來返回位於操作數所指定的地址的變量的值。

    
    #include <stdio.h>
    
    void main(){
    int var  = 20;//實際變量的聲明
    int *ip;//指針變量的聲明
    
    ip = &var;//在指針變量中存儲var變量的地址,也就是給指針變量賦值
    printf("var變量的地址:%x\n",&var);//C語言printf函數不會換行,所以習慣都是內部加上\n,初學者可別弄混了哦。
    //在指針變量中存儲的地址
    printf("在ip中存儲的地址:%x \n",ip);
    //使用指針方位實際變量的值,也就用指針指向的內存地址,讀取地址裏面的數值。
    printf("指針所指向地址的存儲數據:%d \n",*ip);//使用*ip格式來獲取指針對應的實際數值。
    }

    使用*符號來作用與指針,便可得到指針所指向地址內的實際數值。

  • Null指針

    變量聲明的時候,如果沒有明確賦值,最好給指針賦值一個NULL值,如此爲空指針。

    NULL指針是定義在標準庫中值爲零的常量。

    
    #include <stdio.h>
    
    void main(){
    int *ip=null;
    //輸出ip的值,就是0
    printf("ip的值是:%x \n",ip);
    }

    Note:弄清幾個概念,&var表示var的地址,*var是指var指針所指向地址的儲存的數值。

    多數操作系統都不允許訪問地址爲0的內存,其爲系統保留內存,有特殊含義,表明指針不指向可訪問的內存位置。依據慣例指針包含空值,則認爲它不指向任何地址。

    if(ptr)//表示,如果ptr非空,則完成
    if(!ptr)//表示,如果ptr爲空,則完成。
  • 指針詳解

概念 描述
指針的算數運算 指針可以進行四種算術運算++、–、+、-
指針數組 可以定義用來存儲指針的數組
指向指針的指針 C語言允許指向指針的指針
傳遞指針給函數 通過引用過地址傳遞參數,使傳遞的參數在調用的函數中被改變
從函數返回指針 C允許函數返回指針到局部變量、靜態變量和動態內存分配
  • 字符串

    C語言中字符串實際上是使用null字符\0終止的一維字符數組。

  char cs[6] = {'H','e','l','l','o','\0'};
  //這就是hello字符串,用的是null字符'\0'結尾的一個字符數組,所以數組長度比字符串數字多1,因爲末尾是null的字符標記。也可以寫作:
  char cs[] = "Hello";

C/C++中定義的字符串的內存表示:

string

其實可以不必寫出null標記,C編譯器會自動追加,在初始化時候。

常用的C語言字符串操作函數:

函數 描述
strcpy(s1,s2) 複製字符串s2到s1
strcat(s1,s2) 連接字符串s2到s1末尾
strlen(s1) 返回字符串s1的長度
strcmp(s1,s2) s1==s2則返回0,s1<s2則返回小於0,s1>s2則返回大於0
strchr(s1,ch) 返回一個指針,指向字符串s1中字符ch的第一次出現的位置
strstr(s1,s2) 返回一直指針,指向字符串s1中字符串s2的第一次出現的位置

3、結構體

C語言中數組是存儲一類相同類型的數據變量,而結構則可以存儲不同類型的數據項。有點類似面向對象的編程語言中的實體類bean的封裝。

  • 定義結構

    struct語句,可以定義一個包含多個成員的數據類型。

    struct [structure tag]{
    member definition;
    member definition;
    ...
    member definition;
    }[one or more structure variables]

    其中structure tag是可選的,每個member definition是標準的變量定義,比如int i;double d;如下示例,定義一個Book結構的方式

    struct Books{
    char title[50];
    char author[50];
    char subject[100];
    int book_id;
    } book;
  • 訪問結構成員

    使用成員運算符.示例:

    
    #include <stdio.h>
    
    
    #include <string.h>
    
    //定義結構體
    struct Books{
      char title[50];
    char author[50];
    char subject[100];
    int book_id;
    };
    //main函數
    void main(){
    //聲明結構體的變量,使用關鍵詞struct
    struct Books Book1;
    struct Books Book2;
    //初始化變量的內部數據,結構體成員,用變量名.成員名
    strcpy(Book1.title,"C語言編程");
    strcpy(Book1.author,"譚浩強");
    strcpy(Book1.subject,"C語言編程入門");
    Book1.book_id = 10086;
    //輸出Book1信息
    printf("Book1的標題:%s \n",Book1.title);
    printf("Book1的作者:%s \n",Book1.author);
    printf("Book1的副標題:%s \n",Book1.subject);
    printf("Book1的編號:%d \n",Book1.book_id);
    //Book2類似
    ...
    }
  • 結構體作爲函數參數

    結構體也可以作爲參數傳遞給函數調用,類似變量和指針。不同與Java語言的方法函數,這裏需要先聲明結構函數,然後實現,在調用。

    
    #include <stdio.h>
    
    
    #include <string.h>
    
    
    struct Books
    {
     char  title[50];
     char  author[50];
     char  subject[100];
     int   book_id;
    };
    
    /* 函數聲明 */
    void printBook( struct Books book );
    int main( )
    {
     struct Books Book1;        /* 聲明 Book1,類型爲 Book */
     struct Books Book2;        /* 聲明 Book2,類型爲 Book */
    
     /* Book1 詳述 */
     strcpy( Book1.title, "C Programming");
     strcpy( Book1.author, "Nuha Ali"); 
     strcpy( Book1.subject, "C Programming Tutorial");
     Book1.book_id = 6495407;
    
     /* Book2 詳述 */
     strcpy( Book2.title, "Telecom Billing");
     strcpy( Book2.author, "Zara Ali");
     strcpy( Book2.subject, "Telecom Billing Tutorial");
     Book2.book_id = 6495700;
    
     /* 輸出 Book1 信息 */
     printBook( Book1 );
    
     /* 輸出 Book2 信息 */
     printBook( Book2 );
    
     return 0;
    }
    void printBook( struct Books book )
    {
     printf( "Book title : %s\n", book.title);
     printf( "Book author : %s\n", book.author);
     printf( "Book subject : %s\n", book.subject);
     printf( "Book book_id : %d\n", book.book_id);
    }
  • 指向結構的指針

    可以定義結構體的指針,類似變量和指針,

    //聲明指針
    struct Books *struct_pointer;
    //將變量的地址,賦值給指針
    struct_pointer = &Book1;
    //要想讓這個指針能夠訪問到結構體中的某個成員,就需要用->運算符
    struct_pointer->title;//指針訪問結構體中的title變量的值

    上例使用指針模式:

    //其他不變
    ...
    printBook(&Book1);//這裏傳入的是指針
    ...
    void printBook(struct Books *book){//結構體的指針,作爲參數,傳遞給函數
    printf("Book title:%s \n",book->title);//使用->運算符訪問結構體成員
    ...
    }
  • 位域

    又稱”位段”,爲了節省空間,僅存儲佔用一個或者幾個二進制位的數據字節,滿足一些特殊需要,如開關變量0和1,只用一個二進制位即可滿足。

    所謂位域,就是吧一個字節中的二進制位,劃分爲幾個不同的區域,位域有域名,可以在程序中用域名來操作,從而可以把不同的對象用一個字節的二進制位域來表示。

    位域定義和變量說明

    struct 位域結構名{
     位域列表
    };

    其中位域列表的形式:

    類型說明符 位域名:位域長度

    示例:

    struct bs{
    int a:8;
    int b:2;
    int c:6;
    };

    位域變量的說明與結構變量的說明方式相同,可採用先定義後說明,同時定義說明或者直接說明三種方式。

    struct bs{
    int a:8;//佔用的二進制位數8個
    int b:2;
    int c:6;
    } data;

    如上則是同時定義和說明一個bs的變量data,佔用兩個字節(兩個8位)。

    struct packed_stuct{
    unsigned int f1:1;
    unsigned int f2:1;
    unsigned int f3:1;
    unsigned int f4:1;
    unsigned int type:4;
    unsigned int my_int:9;//注意此處,前面有int,和下面的注意事項中不能超過一個字節的要求,並不矛盾,
    } pack;

    這裏pack_struct就包含了6個成員,四個1位的標識符,一個4位的type,還有一個9位的my_int。

  • 位於定義的注意事項

    • 一個位域必須存儲在同一個字節中,不能跨兩個字節,但是可以指定位域的開始位置:
    struct bs{
      unsigned a:4;
      unsigned  :4;//空域
      unsigned b:4;//從下一單元開始存放,而不是使用上面空的那4個
      unsigned c:4;
    }
    • 位域不恩你個跨兩個字節,所以位域長度不能超過8,超過了的話,可能會被重疊,或者放入下一個字節了。

    • 位域可以是無名位域,之用來佔位,其不能使用。

    struct k{
      int a:1;
      int  :2;//佔位的,無名位域,不可用
      int b:3;
      int c:2;
    }

    其實,位域也算是一種結構類型,只不過成員是按照二進制位表示而已。

  • 位域的使用

    類似與結構成員的使用

    位域變量名.位域名

    位域允許各種格式輸出,示例:

    void main(){
    //定義了一個位域,並聲明瞭一個變量bit,和它的指針變量*pbit
    struct bs{
      unsigned a:1;
      unsigned b:3;
      unsigned c:4;
    }bit,*pbit;
    //給位域賦值,注意不要超過位域的值的範圍。
    bit.a = 1;//就只能是0或1,因爲定義佔1個二進制位
    bit.b = 7;//0--7,因爲佔用3個二進制位
    bit.c = 15;
    //以整型量輸出
    printf("%d,%d,%d \n",bit.a,bit.b,bit.c);
    //使用位域指針訪問成員
    pbit = &bit;//給指針賦值
    pbit->a = 0;//指針訪問成員,並賦值給成員
    pbit->b&=3;//使用了&=運算符,相當與pbit->b = pbit->b&3;
    pbit->c|=1;//使用了|=運算符,相當與pbit-> = pbit->b|3;
    printf("%d,%d,%d \n",pbit->a,pbit->b,pbit-c);
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章