一、结构体
由不同类型的数据组合成一个整体,以便引用,这些组合在一个整体中的数据是互相联系的,这样的数据结构称为结构体。
#include <stdio.h>
struct student//student是结构体名字
{
char name[100];
int age;
int sex;
}; //说明了结构体的数据成员类型.不能直接用student,需要在主函数中定义变量
int main()
{
/**********定义结构体的方法1**************/
/*struct student st;//定义了一个结构体变量,名字叫st,在栈里
st.age = 20;
st.sex = 1;
strcpy(st.name, "BoBo");*/
/**********定义结构体的方法2**************/
struct student st = {"BoBo", 25, 0}; //定义了一个结构体变量,名字叫st
/**********初始化结构体**************/
// struct student st = { 0 }; //定义了一个结构体变量,名字叫st,同时将所有成员值初始化为0
printf("name = %s\n", st.name);
printf("age = %d\n", st.age);
if(st.sex == 0)
{
printf("sex = 男\n");
}
else
{
printf("sex = 女\n");
}
return 0;
}
1.1 定义结构体struct与成员初始化的几种方法
法1: struct student st;//定义了一个结构体变量,名字叫st,在栈里.注:定义时各变量顺序要跟声明顺序一致。st是结构体变量名称 st.age = 20; st.sex = 1; strcpy(st.name, "BoBo"); |
法2:定义并初始化 struct student st = {"BoBo", 25, 0}; //定义了一个结构体变量,名字叫st。注:定义时各变量顺序要跟声明顺序一致 |
法3:定义并初始化 struct student st = {.name = "BoBo", .age = 25, .sex = 0}; //“.成员变量名”的形式可以不用按声明顺序赋值。 |
初始化为0的方法
法4: struct student st = { 0 }; 法5: memset(&st, 0, sizeof(st)); |
1.2 结构体的访问
.操作符
结构体变量名字.成员变量名字
eg: printf("name = %s\n", st.name); |
1.3 结构体的内存对其方式
编译器在编译一个结构的时候采用内存对齐模式。
比如结构声明有一个int,一个char,则有8个字节。
1.4 指定结构体元素的位字段
定义一个结构体的时候可以指定具体元素的位长。1字节 = 8bit
struct text { char a : 2; //定义一个成员类型为char,但这个成员只使用2个bit。指定元素为2位长,不是2个字节长 }; |
struct A { int x : 4; char a : 2; char b : 1; } |
则A的长度为8个字节。因为int型有4个字节,char a,b只能在下一行,尽管它俩只用了3bit,但根据内存对齐方式,结构A共占了8字节
struct man{ char name[20];char score; }; int main() { struct man m[10] = { {"tom", 12}, {"marry", 10}, {"jack", 9} }; //在栈中定义数组,有10个成员,m【0】-m【9】 // struct student *p = malloc(sizeof(struct student) * 3);//在堆中定义了3个成员的数组 int i;for(i = 0; i < 3; i++) { printf("名字 = %s, 分数 = %d\n", m[i].name, m[i].score); } return 0; } |
*在堆、栈中分别定义数组及访问数组成员
在栈中 定义数组: struct man m[10] = { {"tom", 12}, {"marry", 10}, {"jack", 9} }; //在栈中定义数组,有10个成员,m【0】-m【9】 访问数组: m[2].age = 5; //将j结构体变量m中第三个成员的age项赋值5. |
在堆中 定义数组: struct student *p = malloc(sizeof(struct student) * 3);//在堆中定义了3个成员的数组 访问数组: p[0].age = 100;//将结构体变量p的第一个成员的age项赋值为100 或者 p -> age = 100; //此方法只适用于指针 |
结构赋值:将数组中某一元素跟另一元素交换位置。比如将下面的程序放到上面结构体定义的下面,可以将结构体中 {"tom", 12}, {"marry", 10}这两元素换位显示。
struct student tmp = m[0]; m[0] = m[1]; m[1] = tmp; |
结构体数组排序:采用冒泡算法将数组成员按年龄从小到大排序,年龄一样的,按成绩由小到大排
struct man{
char name[20];
char age;
char score;
}; //结构体说明
void swap(struct man *p, struct man *a) //函数定义
{
struct man tmp = *p;
*p = *a;
*a = tmp;
}
int main()
{
struct man m[10] = { {"tom", 36, 12}, {"marry", 15, 10}, {"jack", 100, 9}, {"jj", 20, 12} };
int i, j;
for(j = 0; j < 4; j++)
{
for(i = 1; i < 4 - j; i++)
{
if(m[i].age > m[i - 1].age)
{
swap(&m[i], &m[i - 1]);
}
else
if((m[i].age == m[i - 1].age) && (m[i].score > m[i - 1].score))
{
swap(&m[i], &m[i - 1]);
}
}
}
for(i = 0; i < 4; i++)
{
printf("名字 = %s, 年龄 = %d, 分数 = %d\n", m[i].name, m[i].age, m[i].score);
}
return 0;
}
1.6 嵌套结构
一个结构的成员还可以是另一个结构类型
struct A
{
int a;
char b;
};
struct B
{
struct A a;
char c;
};
int main()
{
printf("%d\n", sizeof(struct B));
return 0;
}
1.7 结构体的赋值
struct name a = b;
结构赋值:将数组中某一元素跟另一元素交换位置。比如将下面的程序放到上面1.5例子中结构体定义的下面,可以将结构体中 {"tom", 12}, {"marry", 10}这两元素换位显示。
struct A a1, a2; a1.a = 10; a2.b = 20; a2 = a1;//结构体赋值,其实就是结构体之间内存的拷贝 |
1.8 指向结构体的指针
“->”操作符:表示指针访问一个结构体的成员
struct A
{
int a;
int b;
};
int main()
{
struct A a;
struct A *p = &a;
p ->a = 2;
p ->b = 6;
printf("a = %d, b = %d\n", a.a, a.b);
}
1.9 指向结构体数组的指针
struct A
{
int a;
int b;
};
int main()
{
struct A array[10] = { 0 };//栈里创建数组
struct A *p = &array; //定义一个指针指向结构体地址
p -> a = 1; //数组的第0个元素分别设置为1和2.指针访问一个结构体的成员
p -> b = 2;
p++;//设置数组的下一个元素
p -> a = 3;
p -> b = 4;
int i;
for(i = 0; i < 10; i++)
{
printf("a = %d, b = %d\n", array[i].a, array[i].b);
}
return 0;
}
1.10 结构中的数组成员和指针成员
一个结构中可以有数组成员,也可以有指针成员。若是指针成员,结构体成员在初始化和赋值时就需要提前为指针成员分配内存
结构中的数组成员例子:
struct child
{
char name[30];
int age;
};
struct child_a
{
char *name;
int age;
};
int main()
{
struct child st;
st.age = 30;
strcpy(st.name, "liudehua");
printf("%d, %s\n", st.age, st.name);
free(st.name);
return 0;
}
结构中的指针成员例子:
struct child
{
char name[30];
int age;
};
struct child_a
{
char *name;
int age;
};
int main()
{
struct child_a st = {NULL, 0};//因为child_a中name是指针,所以结构体定义这要对结构成员初始化
st.age = 30;
//因为*name的地址为NULL,所以下面要给name重新分配内存
st.name = malloc(100);
strcpy(st.name, "liudehua");
printf("%d, %s\n", st.age, st.name);
free(st.name);
return 0;
}
1.11 结构作为函数的参数
将结构作为函数参数,将结构指针作为函数参数
#include <stdio.h>
struct student
{
char name[10];
int age;
};
//不建议用结构体作为函数的参数使用
void print_student(const struct student s) //为防止内容被修改,所以加const
{
printf("name = %s, age = %d\n", s.name, s.age);
}
void set_student(struct student s, const char *name, int age)//指针作为参数,只需要传递一个地址,所以代码效率高。因此当一个结构作为函数的参数时,尽量使用指针,而不是使用结构变量
{
strcpy(s.name, name);
s.age = age;
}
int main(void)
{
struct student st = {"tom", 20};
set_student(st, "mike", 100); //加上set_student以及这一句后,运行的结果仍然是name = tom, age = 20.
print_student(st);
return 0;
}
set_student(st, "mike", 100);//这个函数的作用是将它的值复制到s.name中输出,但它忽略了set_student的参数是指针形式的,其内存关系如下: |
所以要采用指针的形式
#include <stdio.h>
struct student
{
char name[1000];//栈中数量很大时,函数入栈时要消耗很多资源,采用指针的话,由于只需要传一个地址,所以效率会很高
int age;
};
void print_student(const struct student *s) //为防止值在传递过程过程被修改,所以要加const
{
printf("name = %s, age = %d\n", s->name, s->age);
}
void set_student(struct student *s, const char *name, int age)
{
strcpy(s->name, name);
s->age = age;
}
int main(void)
{
struct student st = {"tom", 20};
set_student(&st, "mike", 100);
print_student(&st);
return 0;
}
1.12 结构,还是指向结构的指针
在定义一个和结构有关的函数时,是使用结构还是结构的指针?
指针作为参数,只需要传递一个地址,所以代码效率高。因此当一个结构作为函数的参数时,尽量使用指针,而不是使用结构变量,这样代码效率很高。