第四节(结构体、typedef指令、union共用体、enum枚举)

知识点

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

    return 0;
    
}

还可以在定义结构体的时候直接声明结构体变量:

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

也可以定义匿名结构体:

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

但是这样的话就不能在其他地方再定义结构体变量了。

结构体变量初始化(三种方式)

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

输出结果:

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);

输出结果:

name=defg,age=30,classId=0

为什么不能直接s1.name="defg";呢?因为字符串在c语音中表示的是一个地址,例如我们一般只样写:char *p="abcd";所以说s1.name="defg";就相当于是把一个地址赋值给了一个字符串,肯定是行不通的。

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

输出结果:

name=ab,age=32,classId=0

结构体数组

初始化:

 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;
    }

结构体指针

使用方法跟普通类型没什么区别

    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);

输出结果:

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

结构体指针表示数组

先看一段程序以及运行结果:

    struct Student *p1;
    int i;
    p1=(Student *)malloc(sizeof(Student)*5);//必须先分配内存
    //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);

    }

运行结果:

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

如果放开

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

运行结果:

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

结果体指针变量使用前必须初始化(不同于普通类型指针变量)结构体内部的普通类型指针变量是不用初始化的(看到网上有人说必须初始化,这个是错误的)。

(这个后来发现是错误的啊,最下面有解释)

验证:

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);

输出结果:

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

结构体包含函数指针

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;
}

输出结果:

p=abcd,i=10

结构体包含结构体指针(链表的原理)

模拟单行链表,在链表的末尾添加一个节点:

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

void insertNode(Node *head,int data)
{
    //先根据data创建一个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);
    
}

输出结果:

10
20

疑惑

为什么定义一个结构体变量可以直接使用,但是定义一个结构体指针却必须要动态分配内存?
看这儿:http://blog.csdn.net/dreamzuora/article/details/54377197
摘抄其中的一段文字:

struct data
{
    int i;
    int j;
};

void main(void)
{
    struct data dat1; //定义一个struct data类型的变量,和int i同理。
    printf("%d\n", sizeof(struct data)); //8个字节
    printf("%d\n", sizeof(dat1));        //8个字节

    struct data* pdat1;//定义一个struct data类型的指针,和int *pi 同理。
    printf("%d\n", sizeof(pdat1));        //4个字节,就是一个指针的空间,pdat1并没有结构体变量的信息。

    pdat1 = (struct data*)malloc(sizeof(struct data)); //申请一个空间,把该空间地址给pdat1.
    printf("%d\n", sizeof(*pdat1));      //8个字节

    struct data dats1[2]; 
    printf("%d\n", sizeof(dats1));     //16个字节,两个data变量,不是data指针。
    dats1[0].i = 20;  //可以直接使用数组里面的结构体变量
    dats1[0].j = 30;
    
    struct data* dats2[2]; //指针数组,包含两个指针,而不是结构体变量
    printf("%d\n", sizeof(dats2));  //8个字节,两个指针的大小
    dats2[0]->i = 20; //错误!还没有给dats2[0] 指针分配空间
    dats2[0]->i = 20; //错误!还没有给dats2[0] 指针分配空间
    dats2[0] = (struct data*)malloc(sizeof(struct data)); //分配空间
    dats2[0]->i = 20; //ok
    dats2[0]->i = 20; //ok
}
一直以为普通类型的指针是不需要动态分配内存就可以使用的,但是也不行。
    int *aa;
    aa=(int *)malloc(sizeof(int));//没有这个语句报错
    *aa=10;

calloc、malloc

    Node *node1=(Node *)malloc(sizeof(Node)*10);//分配10块空间,这10块空间是连续的(块内和块间都连续)。
    Node *node2=(Node *)calloc(10,sizeof(Node));//分配10块空间,这10块空间是不连续的(块内是连续的,块间是不连续的,并非一定不连续,看内存使用情况,这个是有当时的系统内存使用情况决定的)。

typedef指令

就是定义别名

typedef char* String;

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

输出结果:

abcde

大大的疑问

还是关于指针的:

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

输出结果:

10
    int *aa;
    aa=(int *)malloc(sizeof(int));//没有这个语句报错
    *aa=10;

这样写就必须分配内存,解释下这两种情况:
第一种:定义了一个int类型的变量和一个int类型的指针,然后把int变量的地址存到了int类型的指针中。
第二种:定义了一个int类型的指针,然后分配一块int类型的空间并把这块空间的地址存到int类型的指针中,然后把10存到这块空间中。

这样的话上面关于结构体中的普通类型的指针变量不需要分配空间的描述就是错误的。

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中所有变量共享内存,也就是a、b、c内存的首地址都是相同的,可以自己验证,所以在给a、b、c分别赋值之后,会进行值覆盖,只能取到最后一次赋值的变量的值。

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;
}

输出结果:

one=0,two=1,three=2
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,905评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,140评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,791评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,483评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,476评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,516评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,905评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,560评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,778评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,557评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,635评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,338评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,925评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,898评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,142评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,818评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,347评论 2 342

推荐阅读更多精彩内容