知識(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