C語(yǔ)言復(fù)習(xí)(二)

字符串

在C語(yǔ)言中,字符串實(shí)際上是使用null結(jié)尾的以為字符數(shù)組,因此,一個(gè)以null結(jié)尾的字符串,包含了組成字符串夫人字符,

char greeting[6] = {'H','E','L','L','O','\0'};
char greetin[] = "hello";

在內(nèi)存中的表示如圖:


char

字符串操作函數(shù):

strcpy(s1,s2) //復(fù)制字符串s2到s1
strcat(s1,s2) //鏈接s2到s1的末尾
strlen(s1) //返回字符串的長(zhǎng)度

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

定義結(jié)構(gòu):

struct tag {
member-list
member-list
...
} variable-list;

tag是結(jié)構(gòu)體標(biāo)簽,member-list是標(biāo)準(zhǔn)的變量定義,例如int i, variable-list結(jié)構(gòu)變量,

//此聲明聲明了擁有3個(gè)成員的結(jié)構(gòu)體,分別為整型的a,字符型的b和雙精度的c
//同時(shí)又聲明了結(jié)構(gòu)體變量s1
//這個(gè)結(jié)構(gòu)體并沒(méi)有標(biāo)明其標(biāo)簽
struct 
{
    int a;
    char b;
    double c;
} s1;
//此聲明聲明了擁有3個(gè)成員的結(jié)構(gòu)體,分別為整型的a,字符型的b和雙精度的c
//結(jié)構(gòu)體的標(biāo)簽被命名為SIMPLE,沒(méi)有聲明變量
struct SIMPLE
{
    int a;
    char b;
    double c;
};
//用SIMPLE標(biāo)簽的結(jié)構(gòu)體,另外聲明了變量t1、t2、t3
struct SIMPLE t1, t2[20], *t3;
//也可以用typedef創(chuàng)建新類(lèi)型
typedef struct
{
    int a;
    char b;
    double c; 
} Simple2;
//現(xiàn)在可以用Simple2作為類(lèi)型聲明新的結(jié)構(gòu)體變量
Simple2 u1, u2[20], *u3;

在上面的聲明中,第一個(gè)和第二聲明被編譯器當(dāng)作兩個(gè)完全不同的類(lèi)型,即使他們的成員列表是一樣的,如果令 t3=&s1,則是非法的。
結(jié)構(gòu)體的成員可以包含其他結(jié)構(gòu)體,也可以包含指向自己結(jié)構(gòu)體類(lèi)型的指針,而通常這種指針的應(yīng)用是為了實(shí)現(xiàn)一些更高級(jí)的數(shù)據(jù)結(jié)構(gòu)如鏈表和樹(shù)等。

//此結(jié)構(gòu)體的聲明包含了其他的結(jié)構(gòu)體
struct COMPLEX
{
    char string[100];
    struct SIMPLE a;
};
//此結(jié)構(gòu)體的聲明包含了指向自己類(lèi)型的指針
struct NODE
{
    char string[100];
    struct NODE *next_node;
};

把結(jié)構(gòu)體作為參數(shù)

把結(jié)構(gòu)作為函數(shù)參數(shù),傳參方式與其他類(lèi)型的變量或指針類(lèi)似

struct tag
{
...
} ;
void function(struct tag var_name); //引用結(jié)構(gòu)體作為參數(shù)
 struct tag myData;
function(myData);  //函數(shù)

指向結(jié)構(gòu)體體的指針

結(jié)構(gòu)體指針的聲明:

struct tag *stu_ptr;
struct tag var;  //聲明一個(gè)結(jié)構(gòu)體變量
stu_ptr = &var; //得到這個(gè)變量的地址,現(xiàn)在stu_ptr指向了var
stu_ptr->data; //通過(guò)->來(lái)訪(fǎng)問(wèn)結(jié)構(gòu)體的變量

位域

有些信息存儲(chǔ)時(shí),并不需要占用一個(gè)完整的字節(jié),而只需要占用幾個(gè)二進(jìn)制位,可用位域來(lái)處理。
位域的定義和結(jié)構(gòu)體相類(lèi)似:

struct Tag_name
{
//類(lèi)型說(shuō)明符 位域名稱(chēng):位域長(zhǎng)度
int a:8;
in  b:2;
...
} var_name;

位域的儲(chǔ)存

  • 一個(gè)位域儲(chǔ)存在同一個(gè)字節(jié),如果一個(gè)字節(jié)剩下的空間不夠儲(chǔ)存另一個(gè)位域時(shí),則會(huì)從下一個(gè)單元儲(chǔ)存該位域,也可以有意使得從某位域儲(chǔ)存,例如
struct bs{
    unsigned a:4;
    unsigned  :4;    /* 空域 ,作為填充或者調(diào)整位置 */
    unsigned b:4;    /* 從下一單元開(kāi)始存放 */
}
//a占用4第一字節(jié)的前四位,后四位填充0表示不使用,b從第二個(gè)字節(jié)開(kāi)始占用4位
  • 由于位域不允許跨兩個(gè)字節(jié),因此位域的長(zhǎng)度不能大于一個(gè)字節(jié)的長(zhǎng)度,也就是說(shuō)不能超過(guò)8位二進(jìn)位。如果最大長(zhǎng)度大于計(jì)算機(jī)的整數(shù)字長(zhǎng),一些編譯器可能會(huì)允許域的內(nèi)存重疊,另外一些編譯器可能會(huì)把大于一個(gè)域的部分存儲(chǔ)在下一個(gè)字中
  • 位域的使用與結(jié)構(gòu)體類(lèi)似,也可以用指針,看demo:
#include<stdlib.h>
struct bs 
{
    int flag:4;
    int b:2;
};
int main()
{
    struct bs data,*ptr;
    data.flag = 15;
    data.b = 1;
    printf(" before %d %d\n",data.flag,data.b);
    ptr = &data;
    ptr->flag = 5;
    ptr->b = 0;
    printf("after %d %d\n",data.flag,data.b);
    return 0;
}

共用體

共用體是一種特殊的數(shù)據(jù)結(jié)構(gòu),允許在相同的內(nèi)存位置儲(chǔ)存不同的數(shù)據(jù)類(lèi)型,一個(gè)共用體帶有多個(gè)成員,但是只有一個(gè)成員帶有值,定義如下:

union tag
{
member definition;
...
member definition;
}   var;
//a example
union Data
{
int i;
float f;
char str[20];
} data;

在這個(gè)共用體中,Data類(lèi)型的變量可以?xún)?chǔ)存一個(gè)整數(shù),一個(gè)浮點(diǎn)數(shù),或者一個(gè)字符串,該共用體占用的內(nèi)存應(yīng)該足夠儲(chǔ)存共用體最大的成員,即char str[20],dta數(shù)據(jù)將占用20個(gè)字節(jié)

輸入和輸出

scanf和printf時(shí)最基礎(chǔ)的,還有g(shù)etchar,putchar,gets,puts等。
int getchar(void) 函數(shù)從屏幕讀取下一個(gè)可用的字符,并把它返回為一個(gè)整數(shù)。這個(gè)函數(shù)在同一個(gè)時(shí)間內(nèi)只會(huì)讀取一個(gè)單一的字符。您可以在循環(huán)內(nèi)使用這個(gè)方法,以便從屏幕上讀取多個(gè)字符。
int putchar(int c) 函數(shù)把字符輸出到屏幕上,并返回相同的字符。這個(gè)函數(shù)在同一個(gè)時(shí)間內(nèi)只會(huì)輸出一個(gè)單一的字符。您可以在循環(huán)內(nèi)使用這個(gè)方法,以便在屏幕上輸出多個(gè)字符。
char *gets(char *s) 函數(shù)從 stdin 讀取一行到 s 所指向的緩沖區(qū),直到一個(gè)終止符或 EOF。
int puts(const char *s) 函數(shù)把字符串 s 和一個(gè)尾隨的換行符寫(xiě)入到 stdout。

遞歸

遞歸指的是在函數(shù)的定義中使用函數(shù)自身的方法,語(yǔ)法格式如下:

void recursion()
{
statement;
...
recusion();  //函數(shù)調(diào)用自身
statement;
}
int main()
{
recursion();
}
#include<stdio.h>
#include<stdlib.h>
int recursion(int dt)
{
    if(dt == 1)
        return 1;
    else 
        return dt*recursion(dt-1);
}
int main()
{
    printf("%d \n",recursion(3));
    return 0;
}

在使用遞歸的時(shí)候,一定要注意函數(shù)退出的條件!
遞歸是一個(gè)簡(jiǎn)潔的概念,同時(shí)也是一種很有用的手段。但是,使用遞歸是要付出代價(jià)的。與直接的語(yǔ)句(如while循環(huán))相比,遞歸函數(shù)會(huì)耗費(fèi)更多的運(yùn)行時(shí)間,并且要占用大量的棧空間。遞歸函數(shù)每次調(diào)用自身時(shí),都需要把它的狀態(tài)存到棧中,以便在它調(diào)用完自身后,程序可以返回到它原來(lái)的狀態(tài)。未經(jīng)精心設(shè)計(jì)的遞歸函數(shù)總是會(huì)帶來(lái)麻煩。

可變參數(shù)

有時(shí),可能會(huì)碰到這樣的情況,希望函數(shù)帶有可變數(shù)量的參數(shù),而不是預(yù)定義數(shù)量的參數(shù)。C 語(yǔ)言為這種情況提供了一個(gè)解決方案:

int func(int num,...)//num代表要傳遞的參數(shù)的個(gè)數(shù)
{
>...
}
int main()
{
func(2,3);
func(2,3,4);
}

實(shí)現(xiàn)可變參數(shù),需要使用stdarg.h頭文件,步驟如下:

  • 定義一個(gè)函數(shù),最后一個(gè)參數(shù)為省略號(hào),省略號(hào)之前可以設(shè)置自定義參數(shù)
  • 在函數(shù)中創(chuàng)建一個(gè)va_list類(lèi)型變量,該類(lèi)型實(shí)在stdarg.h中定義的。
  • 使用int參數(shù)和va_start宏來(lái)初始化va_list變量為一個(gè)參數(shù)列表,宏va_start是在stdarg.h頭文件定義的
  • 使用va_arg和va_list變量來(lái)訪(fǎng)問(wèn)參數(shù)列表的每個(gè)項(xiàng)
  • 使用va_end來(lái)清理賦予va_list的變量的內(nèi)存
#include<stdlib.h>
#include<stdarg.h>
double ave(int num, ...)
{
    va_list valist;
    double sum = 0.0;
    int i;
    //為num個(gè)參數(shù)初始化
    va_start(valist,num);
    for(i = 0 ;i<num;i++)
    {
        sum+=va_arg(valist,int);
    }
    va_end(valist);
    return sum/num;
}
int main()
{
    printf("ave : %f\n",ave(2,3,4));
    printf("ave : %f\n",ave(3,3,4,5));
    return 0;
}

內(nèi)存管理

C語(yǔ)言為內(nèi)存的分配和管理提供了幾個(gè)函數(shù),定義在stdlib.h

void calloc(int num,int size);
//在內(nèi)存中動(dòng)態(tài)地分配 num 個(gè)長(zhǎng)度為 size 的連續(xù)空間,并將每一個(gè)字節(jié)都初始化為 0。所以它的結(jié)果是分配了 num
size 個(gè)字節(jié)長(zhǎng)度的內(nèi)存空間,并且每個(gè)字節(jié)的值都是0。
void free(void *address);
//該函數(shù)釋放 address 所指向的內(nèi)存塊,釋放的是動(dòng)態(tài)分配的內(nèi)存空間。
void *malloc(int num);
//在堆區(qū)分配一塊指定大小的內(nèi)存空間,用來(lái)存放數(shù)據(jù)。這塊內(nèi)存空間在函數(shù)執(zhí)行完成后不會(huì)被初始化,它們的值是未知的
void *realloc(void *address, int newsize);
//該函數(shù)重新分配內(nèi)存,把內(nèi)存擴(kuò)展到 newsize。
注意:void * 類(lèi)型表示未確定類(lèi)型的指針. void * 類(lèi)型可以通過(guò)類(lèi)型轉(zhuǎn)換強(qiáng)制轉(zhuǎn)換為任何其它類(lèi)型的指針

命令行參數(shù)

在執(zhí)行程序的時(shí)候,可以從命令行傳值給C程序,從main( int argc, char *argv[ ] ),其中argc是傳入?yún)?shù)的個(gè)數(shù),argv[] 是一個(gè)指針數(shù)組,指向傳遞給程序的每個(gè)參數(shù),argv[0]是程序的名稱(chēng),argv[1]是指向第一個(gè)參數(shù)的指針,argv[n]是最后一個(gè)參數(shù)

#include<stdio.h>
int main(int argc,char *argv[])
{
    if(argc ==2 )
        printf("get a argument %s\n",argv[1]);
    else if(argc > 2)
        printf("more than 2 argment ");
    else
        printf("exit");
    return 0;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容