第四節(jié)(結(jié)構(gòu)體、typedef指令、union共用體、enum枚舉)

知識(shí)點(diǎn)

struct Student{
    char name[20];
    int age;
    int classId;
};
int main(int argc, const char * argv[]) {
    
    struct Student student;

    return 0;
    
}

還可以在定義結(jié)構(gòu)體的時(shí)候直接聲明結(jié)構(gòu)體變量:

struct Student{
    char name[20];
    int age;
    int classId;
}s1,s2;

也可以定義匿名結(jié)構(gòu)體:

struct {
    char name[20];
    int age;
    int classId;
}s1;

但是這樣的話就不能在其他地方再定義結(jié)構(gòu)體變量了。

結(jié)構(gòu)體變量初始化(三種方式)

    s1={"abcd",20};
    printf("name=%s,age=%d,classId=%d\n",s1.name,s1.age,s1.classId);

輸出結(jié)果:

name=abcd,age=20,classId=0
    strcpy(s1.name, "defg");
    s1.age=30;
    printf("name=%s,age=%d,classId=%d\n",s1.name,s1.age,s1.classId);

輸出結(jié)果:

name=defg,age=30,classId=0

為什么不能直接s1.name="defg";呢?因?yàn)樽址赾語(yǔ)音中表示的是一個(gè)地址,例如我們一般只樣寫(xiě):char *p="abcd";所以說(shuō)s1.name="defg";就相當(dāng)于是把一個(gè)地址賦值給了一個(gè)字符串,肯定是行不通的。

struct {
    char name[20];
    int age;
    int classId;
}s1={"ab",32};

輸出結(jié)果:

name=ab,age=32,classId=0

結(jié)構(gòu)體數(shù)組

初始化:

 struct Student students[3] ={{"ab",20},{"cd",10},{"ef",5}};

struct可以省略。

    int i=0;
    Student stu[5];
    for(int i=0;i<5;i++)
    {
        strcpy(stu[i].name, "abc");
        stu[i].age=i;
    }

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

使用方法跟普通類(lèi)型沒(méi)什么區(qū)別

    struct Student s1={"abcd",20};
    printf("name=%s,age=%d,classId=%d\n",s1.name,s1.age,s1.classId);
    
    struct Student *p;
    p=&s1;
    printf("name=%s,age=%d,classId=%d\n",p->name,p->age,p->classId);

輸出結(jié)果:

name=abcd,age=20,classId=0
name=abcd,age=20,classId=0

結(jié)構(gòu)體指針表示數(shù)組

先看一段程序以及運(yùn)行結(jié)果:

    struct Student *p1;
    int i;
    p1=(Student *)malloc(sizeof(Student)*5);//必須先分配內(nèi)存
    //memset(p1, 0,sizeof(Student)*5);
    for(i=0;i<5;i++)
    {
        (p1+i)->age=10;
        strcpy((p1+i)->name, "lucy");
    }
    
    for(int i=0;i<5;i++)
    {
        printf("name=%s,age=%d,classId=%d\n",(p1+i)->name,(p1+i)->age,(p1+i)->classId);

    }

運(yùn)行結(jié)果:

name=lucy,age=10,classId=-1431310072
name=lucy,age=10,classId=0
name=lucy,age=10,classId=0
name=lucy,age=10,classId=0
name=lucy,age=10,classId=0

如果放開(kāi)

memset(p1, 0,sizeof(Student)*5);//初始化操作

運(yùn)行結(jié)果:

name=lucy,age=10,classId=0
name=lucy,age=10,classId=0
name=lucy,age=10,classId=0
name=lucy,age=10,classId=0
name=lucy,age=10,classId=0

結(jié)果體指針變量使用前必須初始化(不同于普通類(lèi)型指針變量)結(jié)構(gòu)體內(nèi)部的普通類(lèi)型指針變量是不用初始化的(看到網(wǎng)上有人說(shuō)必須初始化,這個(gè)是錯(cuò)誤的)。

(這個(gè)后來(lái)發(fā)現(xiàn)是錯(cuò)誤的啊,最下面有解釋?zhuān)?/h4>

驗(yàn)證:

struct Student{
    char *p;
    char name[20];
    int age;
    int classId;
};

    struct Student s1;
    
    s1.p="aaa";
    
    printf("p=%s,name=%s,age=%d,classId=%d\n",s1.p,s1.name,s1.age,s1.classId);

輸出結(jié)果:

p=aaa,name=,age=0,classId=1606416144

結(jié)構(gòu)體包含函數(shù)指針

struct Student{
    char *p;
    char name[20];
    int age;
    int classId;
    int (*s)(char *,int);

};

int fun(char *p,int i)
{
    printf("p=%s,i=%d\n",p,i);
    return 0;
}

int main(int argc, const char * argv[]) {
    struct Student s1;
    s1.s=fun;
    s1.s("abcd",10);
    return 0;
}

輸出結(jié)果:

p=abcd,i=10

結(jié)構(gòu)體包含結(jié)構(gòu)體指針(鏈表的原理)

模擬單行鏈表,在鏈表的末尾添加一個(gè)節(jié)點(diǎn):

struct Node{
    int data;
    Node *next;
};

void insertNode(Node *head,int data)
{
    //先根據(jù)data創(chuàng)建一個(gè)Node
    Node *node=(Node *)malloc(sizeof(Node));
    node->data=data;
    node->next=NULL;
    
    //遍歷到原鏈表的末尾
    Node *temp=head;
    while(temp->next!=NULL)
    {
        temp=temp->next;//不要用head直接操作,這樣的話就找不到鏈表首地址了
    }
    temp->next=node;
   
    
}

int main(int argc, const char * argv[]) {
    
    Node node;
    node.data=10;
    node.next=NULL;
    insertNode(&node, 20);
    
    Node *head=&node;
    while (head->next!=NULL) {
        printf("%d\n",head->data);
        head=head->next;
    }
     printf("%d\n",head->data);
    
}

輸出結(jié)果:

10
20

疑惑

為什么定義一個(gè)結(jié)構(gòu)體變量可以直接使用,但是定義一個(gè)結(jié)構(gòu)體指針卻必須要?jiǎng)討B(tài)分配內(nèi)存?
看這兒:http://blog.csdn.net/dreamzuora/article/details/54377197
摘抄其中的一段文字:

struct data
{
    int i;
    int j;
};

void main(void)
{
    struct data dat1; //定義一個(gè)struct data類(lèi)型的變量,和int i同理。
    printf("%d\n", sizeof(struct data)); //8個(gè)字節(jié)
    printf("%d\n", sizeof(dat1));        //8個(gè)字節(jié)

    struct data* pdat1;//定義一個(gè)struct data類(lèi)型的指針,和int *pi 同理。
    printf("%d\n", sizeof(pdat1));        //4個(gè)字節(jié),就是一個(gè)指針的空間,pdat1并沒(méi)有結(jié)構(gòu)體變量的信息。

    pdat1 = (struct data*)malloc(sizeof(struct data)); //申請(qǐng)一個(gè)空間,把該空間地址給pdat1.
    printf("%d\n", sizeof(*pdat1));      //8個(gè)字節(jié)

    struct data dats1[2]; 
    printf("%d\n", sizeof(dats1));     //16個(gè)字節(jié),兩個(gè)data變量,不是data指針。
    dats1[0].i = 20;  //可以直接使用數(shù)組里面的結(jié)構(gòu)體變量
    dats1[0].j = 30;
    
    struct data* dats2[2]; //指針數(shù)組,包含兩個(gè)指針,而不是結(jié)構(gòu)體變量
    printf("%d\n", sizeof(dats2));  //8個(gè)字節(jié),兩個(gè)指針的大小
    dats2[0]->i = 20; //錯(cuò)誤!還沒(méi)有給dats2[0] 指針?lè)峙淇臻g
    dats2[0]->i = 20; //錯(cuò)誤!還沒(méi)有給dats2[0] 指針?lè)峙淇臻g
    dats2[0] = (struct data*)malloc(sizeof(struct data)); //分配空間
    dats2[0]->i = 20; //ok
    dats2[0]->i = 20; //ok
}
一直以為普通類(lèi)型的指針是不需要?jiǎng)討B(tài)分配內(nèi)存就可以使用的,但是也不行。
    int *aa;
    aa=(int *)malloc(sizeof(int));//沒(méi)有這個(gè)語(yǔ)句報(bào)錯(cuò)
    *aa=10;

calloc、malloc

    Node *node1=(Node *)malloc(sizeof(Node)*10);//分配10塊空間,這10塊空間是連續(xù)的(塊內(nèi)和塊間都連續(xù))。
    Node *node2=(Node *)calloc(10,sizeof(Node));//分配10塊空間,這10塊空間是不連續(xù)的(塊內(nèi)是連續(xù)的,塊間是不連續(xù)的,并非一定不連續(xù),看內(nèi)存使用情況,這個(gè)是有當(dāng)時(shí)的系統(tǒng)內(nèi)存使用情況決定的)。

typedef指令

就是定義別名

typedef char* String;

int main(int argc, const char * argv[]) {
    String str="abcde";
    printf("%s\n",str);
    return 0;
}

輸出結(jié)果:

abcde

大大的疑問(wèn)

還是關(guān)于指針的:

int main(int argc, const char * argv[]) {
    int *p;
    int a=10;
    p=&a;
    printf("%d\n",*p);
    return 0;
}

輸出結(jié)果:

10
    int *aa;
    aa=(int *)malloc(sizeof(int));//沒(méi)有這個(gè)語(yǔ)句報(bào)錯(cuò)
    *aa=10;

這樣寫(xiě)就必須分配內(nèi)存,解釋下這兩種情況:
第一種:定義了一個(gè)int類(lèi)型的變量和一個(gè)int類(lèi)型的指針,然后把int變量的地址存到了int類(lèi)型的指針中。
第二種:定義了一個(gè)int類(lèi)型的指針,然后分配一塊int類(lèi)型的空間并把這塊空間的地址存到int類(lèi)型的指針中,然后把10存到這塊空間中。

這樣的話上面關(guān)于結(jié)構(gòu)體中的普通類(lèi)型的指針變量不需要分配空間的描述就是錯(cuò)誤的。

union共用體

union xn{
    int a;
    char b;
    float c;

};

int main(int argc, const char * argv[]) {
    xn temp;
    temp.a=10;
    temp.b='a';
    temp.c=1.0;
    printf("a=%d,b=%c,c=%f\n",temp.a,temp.b,temp.c);
    return 0;
}

union中所有變量共享內(nèi)存,也就是a、b、c內(nèi)存的首地址都是相同的,可以自己驗(yàn)證,所以在給a、b、c分別賦值之后,會(huì)進(jìn)行值覆蓋,只能取到最后一次賦值的變量的值。

enum枚舉

enum en{
    one,
    two,
    three
};

int main(int argc, const char * argv[]) {
    printf("one=%d,two=%d,three=%d\n",one,two,three);
    return 0;
}

輸出結(jié)果:

one=0,two=1,three=2
最后編輯于
?著作權(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)容