1、定义结构体
结构体像子函数一样,在int mian()外定义
①定义结构
struct Mp3Song(结构体名称)
{
char singer[32]; // 歌手名字
char title[128]; // 歌名
int hits; // 下载量
}
这里的字符串数组用的是char ,但是输出用的%s,这一点怎么理解?
定义结构体不能进行初始化赋值操作,下面这种情况是错误的:
struct ABC
{
int a = 10;
int b = 11;
};
②结构体中元素的赋值
结构体中字符串赋值(数组保存字符串)
Object obj;
strcpy(obj.name,"xiaoshun");
用指针字符串时
需要注意对象复制的问题
Object obj1=obj;
浅拷贝存在的问题:当obj所指向的内存被free,则obj1无法使用了,obj1应该拥有一块自己的内存,深拷贝的方式如下:
void Copy(char* dst,char* scr)
{
dst->name=(char*)malloc(strlen(scr->name)+1);
strcpy(dst->name,scr->name);
dst->id=src->id;
}
③main中结构体的调用
int main()
{
struct Mp3Song mp3;
strcpy_s(mp3.title, 128, "起风了");
strcpy_s(mp3.singer, 32, "大神慧");
mp3.hits = 1293940;
printf("歌手: %s \n", mp3.singer);
printf("歌名: %s \n", mp3.title);
printf("点击量: %d \n", mp3.hits);
return 0;
}
结构体的重命名,main中重命名任然需要加上关键字struct
使用strcpy函数进行重新赋值,主要是下面两种情况:
字符串赋值:第一个参数为结构体中的元素(重命名名称.元素名称),第二个参数为定义数组的长度(长度根据情况去适当值即可,没有一个固定的标准),第三个参数为赋值的内容,printf中使用的%s,直接用重命名结构体名.元素名的方式取出具体值
整数赋值:重命名名称.元素名称=赋值内容,printf中使用的%d
2、结构体的使用
①main中可以定义多个重命名结构体,只需要结构体不重复即可
#include <stdio.h>
#include <string.h>
struct Color
{
int red;
int green;
int blue;
};
int main()
{
struct Color r;
r.red = 255;
r.green = 0;
r.blue = 0;
struct Color white;
white.red = 255;
white.green = 255;
white.blue = 255;
getchar();
return 0;
}
②结构体中调用结构体
用于两种不同类型的元素能很好的划分开
#include <stdio.h>
#include <string.h>
struct Color
{
int red;
int green;
int blue;
};
struct Window
{
int x;
int y;
int width;
int height;
char title[100];
struct Color bg_color; // 背景色
};
int main()
{
struct Window w;
strcpy_s(w.title, 100, "控制台");
w.x = 50;
w.y = 50;
w.width = 800;
w.height = 600;
// 设置背景色
w.bg_color.red = 255;
w.bg_color.green = 255;
w.bg_color.blue = 255;
return 0;
}
定义时直接在一个结构体中调用另一个结构体
调用时,通过两个 . 来取出元素
③结构体赋给结构体
#include <stdio.h>
#include <string.h>
struct Point
{
int x;
int y;
};
int main()
{
struct Point pt1;
pt1.x = 8;
pt1.y = 12;
struct Point pt2 = pt1;
printf("%d, %d \n", pt2.x, pt2.y);
getchar();
return 0;
}
struct Point pt2 = pt1; 则 pt2 的各个字段的值与 pt1 的值相同
④结构体中调用结构体
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <math.h>
struct Point
{
int x;
int y;
};
struct Line
{
struct Point start;
struct Point end;
};
double line_length(struct Line* line)
{
int dx = line->start.x - line->end.x;
int dy = line->start.y - line->end.y;
return sqrt((double)dx*dx + dy * dy); // sqrt求平方根
}
int main()
{
struct Line line;
// 起点 (0, 10)
line.start.x = 0;
line.start.y = 10;
// 终点 (10, 0)
line.end.x = 10;
line.end.y = 0;
// 长度
double len = line_length(&line);
printf("线长: %.2lf \n", len);
getchar();
return 0;
}
结构体中调用结构体:这里Point和start可以看作是等价的,在去结构体中的坐标时直接用:
line->start.x ,不需要line->Point->start.x
3、结构体指针(用箭头)
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
struct Student
{
char name[100]; // 姓名
bool sex; // 性别(true,男, false, 女)
int score; // 考试成绩 (0-100)
};
int main()
{
struct Student s;
struct Student* ps = &s;
strcpy_s(ps->name,100, "shao fa");
ps->sex = true;
ps->score = 97;
return 0;
}
结构体中的字符元素的赋值必须要函数strcoy_s实现
输出bool类型:本质上是一种整数类型,输出直接用%d。
4、结构体中的传值和传地址
主要观察:传入的是一个对象的值还是对象的地址
struct Object
{
int id;
char name[256];
};
void Test1(Object a)
{
printf("id:%d,name:%s",a.id,a.name);
}
void Test2(Object* p)
{
printf("id:%d,name:%s", p->id, p->name);
}
int main()
{
Object obj = {123,"shaofa"};
Test1(obj);
Test2(&obj);
return 0;
}
传值:Test1被调用时,有两个Object对象,一个是重名的结构体obj,另一个是Test1的形参a,在传值调用时,将obj的值赋值给了形参a
Object a=obj
Test2被调用时,传入对象obj的地址,用Object*指针表示对象obj的地址
Object* p=&obj
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
struct Student
{
int id; // 学号
char name[32]; // 姓名
bool sex; // 性别
};
void st_set(struct Student* st, int id, char* name, bool sex)
{
st->id = id;
strcpy_s(st->name, 32, name);
st->sex = sex;
}
int main()
{
struct Student stu;
// 设置stu的各个字段
st_set(&stu, 20180001, "shaofa", true);
getchar();
return 0;
}
mian中调用子函数时,传入地址用&
子函数的形参用*,任意命名,取结构体中的元素时用箭头
①通过传地址实现值的交换
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
void swap(int* p1, int* p2)
{
int t = *p1;
*p1 = *p2;
*p2 = t;
}
int main()
{
int a = 10;
int b = 12;
swap(&a, &b);
printf("a=%d, b=%d\n", a, b);
getchar();
return 0;
}
②通过传地址实现交通灯(结构体中元素的切换)
实现颜色的显示:不知道对light->color怎么赋值?还是对题目不是很理解,这题已经给出了color的三个值,所以直接用if条件判断是否为0,1,2
实现颜色的切换:从结构体中取值,然后加1实现
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
struct TrafficLight
{
int color; // 0, 表示红色, 1 表示黄 , 2表示绿
};
// 切到下一颜色
void change(struct TrafficLight* light)
{
printf("切换 ...\n");
light->color += 1;
if (light->color >= 3)
{
light->color = 0;
}
}
// 显示当前颜色
void show(struct TrafficLight* light)
{
printf("当前颜色:");
if (light->color == 0)
{
printf("红色\n");
}
else if (light->color == 1)
{
printf("黄色\n");
}
else if (light->color == 2)
{
printf("绿色\n");
}
}
int main()
{
struct TrafficLight tl;
tl.color = 0; // 初始为红色
change(&tl); // 切换到下一颜色
show(&tl); // 显示
change(&tl); // 切换到下一颜色
show(&tl); // 显示
getchar();
return 0;
}
③当子函数需要返回值是直接用return
int rect_area(struct Rectangle* r)
{
return r->width * r->height;
};
直接返回条件判断的值
bool is_right(struct Triangle* tr)
{
int aa = tr->a * tr->a;
int bb = tr->b * tr->b;
int cc = tr->c * tr->c;
return aa + bb == cc || aa + cc == bb || bb + cc == aa;
}
自己:用if条件判断,然后返回true和falese,这两句可以合并为上面一句return语句
main中写成如下:
if (is_right(&tr))
{
printf("是直角三角形!\n");
}
else
{
printf("不是!\n");
}