首先记录一下随机数吧,在编写每个学生对应的课程的时候,每个学生会从1到50的课程号中随机选出10个作为自己的课程,分数也是由60到100之间随机
unsigned int times = (unsigned int)time(NULL);
void connect(int start,int x) //start为起始学号
{
int i,j=0,x_1,x_2,temp,k,num=0;
int a, b;
conncet* p1, * p2;
p1 = p2 = (conncet*)malloc(sizeof(conncet));
for (i = 0; i < control; i++)
{
p1->num_1 = i + 1;
if (i == 0)
{
head_2=head_3= p1;
}
for (j = 0; j < 10; j++) //生成10个关于课程和成绩的随机数,课程为1到50,成绩为60到100
{
a = *(suiji(10, 1, 50, i) + j);
p1->num_2[j] = a;
srand(times * ((i + 1) * (j + 1)));
x_2 = rand() % 40 + 60;
p1->grade[j] = x_2;
}
p2->next = p1;
p2 = p1;
p1 = (conncet*)malloc(sizeof(conncet));
}
主要看第18行的重新播种,一开始我是用srand(0)这样的结构的,想着是每次循环中以秒为基准,重新播种种子,从而生成不同的随机数。
遇到的第一个问题自然是for循环执行的时间太快了,小于秒级别从而使以秒为级别的播种失效,每次都是生成同一个随机数,类似于:
学生1,课程:1,课程:1,课程:1,课程:1,课程:1,课程:1,课程:1,课程:1这样
后来参考了别人的播种方法,在第一行定义了一个times变量,为unsinged int格式的,从而使得int型数字与其相乘符合srand函数的内置要求,第二次类似于srand(i*times)这种写法,问题又来了,我发现每个学生随机的课程序号都是一样的,但起码每个学生的课程不一样了。
类似:
学生1,课程:1,课程:1,课程:1,课程:1,课程:1,课程:1,课程:1,课程:1
学生二是课程:2,课程:2,课程:2,课程:2,课程:2,课程:2,课程:2,课程:2
第一个问题是由于每个学生的每个课程都需要重新播种一次,所以一开始我只在第一层for循环内编写srand(i*times)的时候只能以学生为单位而不能以课程为单位,并且一个小细节是i=0时候×times还是0,所以要写完i+1这种形式,并且在第二层循环内编写成(i+1)*(j+1)这种形式才能达到想要的效果。
解决了随机数的问题,第二个问题是怎么生成不同的课程号,因为一个学生不可能选两门相同的课程呀,经过查询c暂时也没查到特别好的方法,目前是参考别人的使用一个数组,储存已经出现过的随机数,如果数组里已经有这个随机数便重新生成,如果没有,便将它存入数组中。遍历的效率目前还是有点低,但对于较小的数字也够用了
int* suiji(int x,int x_1,int x_2,int x_3) //生成x个不重复的随机数,需要规定整数范围x_1,x_2,考虑到需要多次调用该函数生成随机数,最后传入一个循环中会改变的x_3用于每次重新播种
{
int i, a, j;
int* list;
list = (int*)calloc(x, sizeof(int));
for (i = 0; i < x; i++)
{
srand(times * (x_3 + 1)*(i+1));
while (1)
{
a = rand() % x_2 + x_1; //获取一个x_1到x_2之间的随机数。
for (j = 0; j < i; j++)
if (list[j] == a) break;//检查重复。
if (j == i)//没有重复值,保存到list中。
{
list[i] = a;
break;
}
}
}
return list;
}
目前编写的生成不重复的随机数,仅用于课程号,因为成绩是可以是相同的
第三个问题是对课程号进行排序,本来只是比较简单的冒泡排序法,但是由于我不小心少了一层遍历每个学生的步骤,在这卡壳了一晚上,看到数组越界一直不知所措,后来回头看当初写的实在是不知所云
也先记录在这,还有冒泡排序的遍历次数是n-1,如果写成n也会数组越界,当初也被这卡了一下
for (k = 0; k < x; k++)
{
printf("学号为:%-3d\n", head_3->num_1);
for (i = 0; i < 10-1; i++)
{
for (j = 0; j < 10 - i - 1; j++)
{
if (head_3->num_2[j] > head_3->num_2[j + 1]) //相邻元素之间比较
{ //大的元素向右移动
temp = head_3->num_2[j]; //每一轮比较最大的元素在最后
head_3->num_2[j] = head_3->num_2[j + 1];
head_3->num_2[j + 1] = temp;
}
}
}
x为传入学生的数量,之前少了第一行导致一直报错,现在一看的确是不该犯的错误
第四个问题是使用初始化后的函数,里面的头指针是一个局部变量,在调用例如增查删改的函数的功能需要调用这个头指针,后来也是比较简单的直接将其定义为全局变量,其中一个储存永久的头指针,另一个用于调用给各个函数的头指针,以便对数据进行操作
Student1* head; //永久的学生信息的头指针
Student1* head_1; //各函数用来引用的学生信息的头指针
conncet* head_2; //永久的学生-课程信息的头指针
conncet* head_3; //各函数用来引用的学生-课程信息的头指针
增查删的函数都比较简单,输入起始学号,然后使用头指针移动到相应位置进行操作就可以了
顺便记录下生成随机名字和每个人随机学院的方式
char* sex[] = {"男","女"};
char* lesson_1[] = { "人工智能","国际商学院","包装工程","翻译学院","金融工程" };
//百家姓
char* NA1[444] = { "赵", "钱", "孙", "李", "周", "吴", "郑", "王", "冯", "陈", "褚", "卫", "蒋", "沈", "韩", "杨", "朱", "秦", "尤", "许", "何", "吕", "施", "张", "孔", "曹", "严", "华", "金", "魏", "陶", "姜", "戚", "谢", "邹", "喻", "柏", "水", "窦", "章", "云", "苏", "潘", "葛", "奚", "范", "彭", "郎", "鲁", "韦", "昌", "马", "苗", "凤", "花", "方", "俞", "任", "袁", "柳", "酆", "鲍", "史", "唐", "费", "廉", "岑", "薛", "雷", "贺", "倪", "汤", "滕", "殷", "罗", "毕", "郝", "邬", "安", "常", "乐", "于", "时", "傅", "皮", "卞", "齐", "康", "伍", "余", "元", "卜", "顾", "孟", "平", "黄", "和", "穆", "萧", "尹", "姚", "邵", "湛", "汪", "祁", "毛", "禹", "狄", "米", "贝", "明", "臧", "计", "伏", "成", "戴", "谈", "宋", "茅", "庞", "熊", "纪", "舒", "屈", "项", "祝", "董", "梁", "杜", "阮", "蓝", "闵", "席", "季", "麻", "强", "贾", "路", "娄", "危", "江", "童", "颜", "郭", "梅", "盛", "林", "刁", "钟", "徐", "邱", "骆", "高", "夏", "蔡", "田", "樊", "胡", "凌", "霍", "虞", "万", "支", "柯", "昝", "管", "卢", "莫", "经", "房", "裘", "缪", "干", "解", "应", "宗", "丁", "宣", "贲", "邓", "郁", "单", "杭", "洪", "包", "诸", "左", "石", "崔", "吉", "钮", "龚", "程", "嵇", "邢", "滑", "裴", "陆", "荣", "翁", "荀", "羊", "於", "惠", "甄", "麴", "家", "封", "芮", "羿", "储", "靳", "汲", "邴", "糜", "松", "井", "段", "富", "巫", "乌", "焦", "巴", "弓", "牧", "隗", "山", "谷", "车", "侯", "宓", "蓬", "全", "郗", "班", "仰", "秋", "仲", "伊", "宫", "宁", "仇", "栾", "暴", "甘", "钭", "厉", "戎", "祖", "武", "符", "刘", "景", "詹", "束", "龙", "叶", "幸", "司", "韶", "郜", "黎", "蓟", "薄", "印", "宿", "白", "怀", "蒲", "邰", "从", "鄂", "索", "咸", "籍", "赖", "卓", "蔺", "屠", "蒙", "池", "乔", "阴", "郁", "胥", "能", "苍", "双", "闻", "莘", "党", "翟", "谭", "贡", "劳", "逄", "姬", "申", "扶", "堵", "冉", "宰", "郦", "雍", "舄", "璩", "桑", "桂", "濮", "牛", "寿", "通", "边", "扈", "燕", "冀", "郏", "浦", "尚", "农", "温", "别", "庄", "晏", "柴", "瞿", "阎", "充", "慕", "连", "茹", "习", "宦", "艾", "鱼", "容", "向", "古", "易", "慎", "戈", "廖", "庾", "终", "暨", "居", "衡", "步", "都", "耿", "满", "弘", "匡", "国", "文", "寇", "广", "禄", "阙", "东", "殴", "殳", "沃", "利", "蔚", "越", "夔", "隆", "师", "巩", "厍", "聂", "晁", "勾", "敖", "融", "冷", "訾", "辛", "阚", "那", "简", "饶", "空", "曾", "毋", "沙", "乜", "养", "鞠", "须", "丰", "巢", "关", "蒯", "相", "查", "後", "荆", "红", "游", "竺", "权", "逯", "盖", "益", "桓", "公", "仉", "督", "晋", "楚", "闫", "法", "汝", "鄢", "涂", "钦", "归", "海", "岳", "帅", "缑", "亢", "况", "后", "有", "琴", "商", "牟", "佘", "佴", "伯", "赏", "墨", "哈", "谯", "笪", "年", "爱", "阳", "佟", "言", "福" };
//男性常用名
char* ME1m[140] = { "伟", "刚", "勇", "毅", "俊", "峰", "强", "军", "平", "保", "东", "文", "辉", "力", "明", "永", "健", "世", "广", "志", "义", "兴", "良", "海", "山", "仁", "波", "宁", "贵", "福", "生", "龙", "元", "全", "国", "胜", "学", "祥", "才", "发", "武", "新", "利", "清", "飞", "彬", "富", "顺", "信", "子", "杰", "涛", "昌", "成", "康", "星", "光", "天", "达", "安", "岩", "中", "茂", "进", "林", "有", "坚", "和", "彪", "博", "诚", "先", "敬", "震", "振", "壮", "会", "思", "群", "豪", "心", "邦", "承", "乐", "绍", "功", "松", "善", "厚", "庆", "磊", "民", "友", "裕", "河", "哲", "江", "超", "浩", "亮", "政", "谦", "亨", "奇", "固", "之", "轮", "翰", "朗", "伯", "宏", "言", "若", "鸣", "朋", "斌", "梁", "栋", "维", "启", "克", "伦", "翔", "旭", "鹏", "泽", "晨", "辰", "士", "以", "建", "家", "致", "树", "炎", "德", "行", "时", "泰", "盛" };
//女性常用名
char* ME1f[165] = { "秀", "娟", "英", "华", "慧", "巧", "美", "娜", "静", "淑", "惠", "珠", "翠", "雅", "芝", "玉", "萍", "红", "娥", "玲", "芬", "芳", "燕", "彩", "春", "菊", "兰", "凤", "洁", "梅", "琳", "素", "云", "莲", "真", "环", "雪", "荣", "爱", "妹", "霞", "香", "月", "莺", "媛", "艳", "瑞", "凡", "佳", "嘉", "琼", "勤", "珍", "贞", "莉", "桂", "娣", "叶", "璧", "璐", "娅", "琦", "晶", "妍", "茜", "秋", "珊", "莎", "锦", "黛", "青", "倩", "婷", "姣", "婉", "娴", "瑾", "颖", "露", "瑶", "怡", "婵", "雁", "蓓", "纨", "仪", "荷", "丹", "蓉", "眉", "君", "琴", "蕊", "薇", "菁", "梦", "岚", "苑", "筠", "柔", "竹", "霭", "凝", "晓", "欢", "霄", "枫", "芸", "菲", "寒", "欣", "滢", "伊", "亚", "宜", "可", "姬", "舒", "影", "荔", "枝", "思", "丽", "秀", "飘", "育", "馥", "琦", "晶", "妍", "茜", "秋", "珊", "莎", "锦", "黛", "青", "倩", "婷", "宁", "蓓", "纨", "苑", "婕", "馨", "瑗", "琰", "韵", "融", "园", "艺", "咏", "卿", "聪", "澜", "纯", "毓", "悦", "昭", "冰", "爽", "琬", "茗", "羽", "希" };
char* temp = (char*)malloc(strlen(NA1[0]) + strlen(ME1m[0]) + 1);
if (i == 0)
{
head = head_1 = p2;
}
srand(times * (i + 1));
x_1 = rand() % 5;
x_2 = rand() % 2;
x_3 = rand() % 4 + 18;
NA1Roll = rand() % 443;//单姓
ME1mRoll = rand() % 139;//男名
ME1fRoll = rand() % 120;//女名
rand_1 = rand() % 2; //性别
if (rand_1)
{
strcat(strcpy(temp, NA1[NA1Roll]), ME1m[ME1fRoll]);
}
else
{
strcat(strcpy(temp, NA1[NA1Roll]), ME1f[ME1fRoll]);
}
p1->name = temp;
p1->num = i + 1;
p1->sex = sex[x_2];
p1->age = x_3;
p1->college = lesson_1[x_1];
大致思路如上,比较简单粗暴的把前人写好的姓和名数组复制过来了
第五个问题在这里,应该如何将char*的指针指向的字符串连起来呢
我一开始比较简单的使用strcat(p1,p2)这种形式,报错了
strcat这种函数是将2个char[]型的字符串,将p2接到p1的后面,将p1最后面的\0删除并接上p2部分,p2最后已经有了\0所以一起复制过来,最后p1为处理后的字符串,以后直接用就行了
查询了其他人的博客后知道也有人发现了不能将两个指针这样简单的用函数相连接,但可以采用p1为数组,然后p2为指针的方式,查询了官方文档后发现 假设p2是一个char*的指针,其指向的内容是不可以写入仅可以读写的,但是char[]数组是可以进行写入和读写,所以如果要进行将两个指针相连的方式的话,只能动态创立一个新的指针给其分配动态内存空间,然后使用strcpy和strcat实现效果,如下
注意分配空间的时候要在最后+1,以便储存\0
char* temp = (char*)malloc(strlen(NA1[0]) + strlen(ME1m[0]) + 1);
if (rand_1) //rand_1为一个0和1的随机数,用于决定是将姓和男名连接在一起还是女名
{
strcat(strcpy(temp, NA1[NA1Roll]), ME1m[ME1fRoll]);
}
else
{
strcat(strcpy(temp, NA1[NA1Roll]), ME1f[ME1fRoll]);
}
写完了增查删,到最后一个改的功能了,到这里的时候突然就尴尬了
上文已经提过char*指向的内容是仅可以读取而不能写入的,由于增查删都没有设计对原本数据的变动,增和删只是简单的改变链表中的节点就可以了,前者需要用户录入数据。
但是改需要变动原本学生的数据呀
我的学生结构体变量是这么定义的
struct Student1
{
int num; //学号
char *name; //姓名
char *sex; //性别
int age; //年龄
char* college; //院系
struct Student1* next; //指向下一个学生的指针
};
学号和年龄是int型可以改变,但是name和sex和college这3个char *型的该怎么办呢?
像上面说的当然把这两个改成char[]类型就可以了,但是我前面初始化学生数据形式的时候使用的是char *的形式呀,名字啊,院系啊这些都是用一个数组来储存char*的内容
char* sex[] = {"男","女"};
像这样,然后用sex=char[n]的这种形式,如果前面更改成char[]型的话后面全都要改
char*这种指向的是字符串的首地址,并不是将字符串全部储存在这个指针里。也就是说并没有为这个指针分配储存字符串的内存空间,其大小为4个字节,而是在调用它的时候类似于%s的话,就会逐个读取直到\0为止,大概就是因为这样才不可更改其内容,因为它并没有储存完整的内容
像char[]这种分配了足够的内存空间才可以更改其内容
除了更改的功能都写好了,到这时候如果更改最基本的结构体变量的储存方式的话,后面全部都要更改,也是个不小的工程,先记录到这里把,等我想到有什么办法再进行更新
以下为第二次更新,经过论坛的问答已经得到了方法,上面写的无法更改内容应该是我写错了,对指针的理解还不够透彻,我们在给指针再次赋值的时候并不是更改其指向的内容,而是直接将一个新的地址赋给了他,所以上面的理解应该是错的
之所以会出现类似于这种情况,之前查询根据别人经验我以为是类似于数组越界之类的情况从而以为是我更改了指针的内容,但毕竟具体情况需要具体分析
我是在change()这个函数里面定义的变量,想着用户输入了数据赋给这个变量,然后指针指向这个地址,结果当然是很显而易见的,这是个局部变量,调用完就没了,输入的内容没有保存下来,指向其的指针设置断点后也显示无法读取内存。如果是main函数里面应该就可以这样做,但因为这并不是主函数所以不行
实现改的功能如下,每次用户输入前都分配一块动态内存空间,这样就不会因为调用完输入的字符串就没了,然后用指针指向这个字符串
printf("请输入更改后学生的性别为:");
head_1->sex = (char*)malloc(3 * sizeof(char));
scanf("%s", head_1->sex);
printf("请输入更改后学生的年龄为:");
scanf("%d", &head_1->age);
printf("请输入更改后学生的院系为:");
head_1->college = (char*)malloc(20 * sizeof(char));
scanf("%s", head_1->college);
malloc前要指针类型化其便于以后使用
目前为止,增查删改的功能已经全部实现。写下此笔记以记录过程,也是处女文