复习
什么是指针变量
存放地址的变量
地址运算
第一 偏移 ±
偏移一个单位是地址的类型长度
第二 间接 * 一元运算 在操作数左边
间接运算是针对地址的运算,间接运算得到的结果不是值,而是一个变量本身。its self
定义指针变量
指向整型的指针变量
int* p;//*说明p是指针变量,*在这里不是运算符,只要是出现在声明的语句中的符号都不是运算符,都是用来说 明标识符身份的。
[]
()
int a;
int* p = &a;//初始化
int b;
p = &b;//赋值
在不是针对硬件编程时,不要自己写地址常量,因为我们自己写的地址常量不合法。
指针变量的意义
可以再被调函数中直接使用主调函数的变量。
指针与数组的关系
数组名就是数组的首元素地址,地址的类型是数组的元素类型,数组名是地址常量;
数组的元素是连续的。所以可以通过地址偏移,访问每个数组的元素。
C语言字符串的两个要素
首地址 和 ‘\0’ %s无论是输入输出还将来我们要学的格式化字符串,%s都需要字符串的首地址,到’\0’
作业1:
编写函数fun:从n个学生的成绩中统计出低于平均分的学生人数,
由返回值返回,平均分存放在形参 ptr_aver 所指的存储单元中(即平均分由参数返回)。
函数最终会有两个结果,人数通过返回值给主调函数,平均分通过形参里的指针变量ptr_aver 给主调函数。
函数原型为:int fun( float *s, int n, float *ptr_aver );
例如:若输入8名学生的成绩如下 : 80.5 60 72 90.5 98 51.5 88 64
则低于平均分的学生人数为:4 (平均分:75.5625)。
#include <stdio.h>
int fun(float* s, int len, float* ptr_aver);
int main()
{
float scores[] = {80.5,60, 72, 90.5, 98, 51.5, 88, 64};
float avg;
//将得到的平均值 给avg
//返回值给 count
int count = fun(scores, 8, &avg);
printf("%d %f\n", count, avg);
return 0;
}
int fun(float* s, int len, float* ptr_aver)
{
int i;
float sum = 0;
for(i = 0;i < len;i++)
{
sum += s[i];//s[i]等价于*(s+i)
}
*ptr_aver = sum/len;
int count = 0;
for(i = 0;i < len;i++)
{
if(s[i] < *ptr_aver)
{
count++;
}
}
return count;
}
作业2:
编写一个函数,将数组中n个数按反顺序存放
假设主调函数中有数组int a[8] = {3,4,5,6,7,9,9,2};
执行完被调函数,数组变成2 9 9 7 6 5 4 3
#include <stdio.h>
void reverse(int* p, int len);
int main()
{
int arr[] = {1,2,3,4,5,6,7,8,9};
reverse(arr, 9);
int i;
for(i = 0;i < 9;i++)
{
printf("%d ", arr[i]);
}
printf("\n");
return 0;
}
void reverse(int* p, int len)
{
int start = 0;
int end = len-1;
while(start<end)
{
int t = p[start];
p[start] = p[end];
p[end] = t;
start++;
end--;
}
}
作业3:
编写函数,实现字符串追加 功能。但不能调用字符串函数;
char s1[20] = “hello ”;
char s2[] = “world”;
调用函数后,将world放到s1数组的”hello ”后面
知识点:当数组存放字符串时,作为函数的参数只需要传递首地址,因为字符串有’\0’作为结尾。
实现strcat的功能,但是不能调用strcat
#include <stdio.h>
void myStrcat(char* buf, char* str);
int main()
{
char buf[11] = "hello ";
*(buf+12) = 12;
//使用字符串常量作为参数,是将字符串常量的首地址传给形参
myStrcat(buf, "world");
printf("%s\n", buf);
return 0;
}
void myStrcat(char* buf, char* str)
{
//找到buf的\0位置
int i = 0;
while(buf[i] != '\0')
{
i++;
}
int j = 0;
while(str[j] != '\0')
{
buf[i++] = str[j++];
}
//第二个循环,并不能把\0写入buf
//buf[i] = str[j];//在循环结束时str[j]就是\0
}
1、结构体
1. 什么是结构体
是我们自定义的类型。
格斗游戏
人物用什么类型表示?
人物
名字 性别 年龄 身材 功 防 血
char name[100];
char gender;
int age;
身材(身高 int high 体重 weight)
int act;
int def;
int hp;
结构体可以将无数的属性封装成一个类型。
结构体的本质是类型。
2. 如何定义变量
//struct是定义结构体的关键字
//student是结构体的名字
struct student //定义了一个结构体类型叫 student
{
char name[20]; //结构体的成员
char number[20]; //结构体的成员
int grade; //结构体的成员
float score; //结构体的成员
}; //{}中包含结构体类型的成员 注意,定义结构体类型,结尾有;
int main()
{
//struct student是定义结构体变量时的完成的类型名
struct student xiaoming;//xiaoming是一个结构体变量
return 0;
}
3.访问成员变量
成员运算符 .
成员运算符的运算结果,不是值,而是成员变量本身。
结构体变量名.成员名
给成员变量赋值的方式,取决于成员变量类型。
strcpy(xiaoming.name, "Alice"); //xiaoming.name得到的是xiaoming里的name数组名,是常量
strcpy(xiaoming.number,"17001001001");
xiaoming.grade = 90;//xiaoming.grade得到的是成员变量grade本身。
xiaoming.score= 6000.00;
4. 输出
不能直接把结构体变量格式化,只能一个一个属性单独进行格式化。
printf("name:%s,number:%s,grade:%d,score:%f\n", xiaoming.name, xiaoming.number, xiaoming.grade, xiaoming.price);
示例1:
#include <stdio.h>
#include <string.h>
struct student
{
char name[20];
char number[20];
int grade;
float score;
};
int main()
{
struct student s1;
strcpy(s1.name, "Alice");
strcpy(s1.number,"17001001001");
s1.grade = 90;
s1.score= 6000.00;
printf("%s : %s, %d, %f\n", s1.name, s1.number, s1.grade, s1.score);
}
练习1:
构建一个学生结构体,包含成员:姓名、年龄、学号、专业(major/professor)
定义变量用来保存自己的学生信息、赋值、并输出。
#include <stdio.h>
#include <string.h>
struct Student
{
char name[20];
int age;
char number[20];
char major[20];
};
int main()
{
struct Student xiaoming;
strcpy(xiaoming.name, "xiaoming");
xiaoming.age = 18;
strcpy(xiaoming.number, "2022114");
strcpy(xiaoming.major, "计算机");
printf("name:%s\nage:%d\nnumber:%s\nmajor:%s\n",
xiaoming.name,
xiaoming.age,
xiaoming.number,
xiaoming.major);
return 0;
}
练习2:
在上题基础上,请将输出的功能。 用一个函数 来实现: void print_info(struct Student stu);
#include <stdio.h>
#include <string.h>
struct Student
{
char name[20];
int age;
char number[20];
char major[20];
};
void print_info(struct Student stu);
int main()
{
struct Student xiaoming;
strcpy(xiaoming.name, "xiaoming");
xiaoming.age = 18;
strcpy(xiaoming.number, "2022114");
strcpy(xiaoming.major, "计算机");
print_info(xiaoming);
return 0;
}
void print_info(struct Student stu)
{
printf("name:%s\nage:%d\nnumber:%s\nmajor:%s\n",
stu.name,
stu.age,
stu.number,
stu.major);
}
5. 结构体指针
指针访问成员: 结构体指针名->成员名称。
-> 成员运算符 和 . 有一个区别, ->左值是结构体指针变量 .左值是结构体变量
int main()
{
//定义结构体变量,并赋值
struct Student xiaoming;
strcpy(xiaoming.name, "xiaoming");
xiaoming.age = 18;
xiaoming.number = 10010;
strcpy(xiaoming.major, "huaqing");
struct Student* p = &xiaoming;//使用结构体变量小明初始化结构体变量p
//因为p是结构体指针变量,所以使用p访问结构体变量的成员,需要使用成员运算符->
printf("%s %d %d %s\n", p->name, p->age, p->number, p->major);
return 0;
}
练习3:
编写函数setStudent,实现功能:设置学生信息
1.在main函数中定义一个结构体变量
2.在setStudent函数中调用scanf给结构体的每一个成员赋值
3.需要把main函数中的结构体变量的地址传给setStudent
#include <stdio.h>
#include <string.h>
struct Student
{
char name[20];
int age;
char number[20];
char major[20];
};
void setStudent(struct Student* p);
int main()
{
struct Student xiaoming;
setStudent(&xiaoming);
printf("%s %d %s %s\n", xiaoming.name,
xiaoming.age, xiaoming.number,
xiaoming.major);
return 0;
}
void setStudent(struct Student* p)
{
scanf("%s%d%s%s", p->name, &p->age, p->number, p->major);
}
6. 结构体数组
struct student s[10];//结构体数组,10个元素,每个元素是结构体类型
s[0];//数组中的第一个元素,结构体类型
s[0].name;//得到的是第一个元素的name成员,是一个数组名
结构体初始化:
struct Student xiaoming = {"xiaoming", //初始化xiaoming的name成员,使用字符串常量初始化字符数组
18, //用整型常量初始化xiaoming的age成员
"10010",
"huaqing"};
数组初始化:
//完全初始化:
struct Student students[2] = {
{"xiaoming", 18, 10010, "huaqing"},
{"xiaoqiang", 19, 10011, "huaqing"}
};
//部分初始化:
struct Student students[3] = {
{"xiaoming", 18, 10010, "huaqing"},
{"xiaoqiang", 19, 10011, "huaqing"}
};
//默认初始化:
struct Student students[] = {
{"xiaoming", 18, 10010, "huaqing"},
{"xiaoqiang", 19, 10011, "huaqing"}
};
示例2:
struct Student
{
char name[20];//字符数组具备存放字符串的能力
//char* name;//指针不具备存放字符串的能力,它只能指向一个字符串
int age;
char number[20];
char major[20];
};
int main()
{
struct Student students[2] = {
{"xiaoming", 18, "10010", "huaqing"},
{"xiaoqiang", 19, "10011", "huaqing"}
};
int i;
for(i = 0;i < 2;i++)
{
printf("%s %d %s %s\n",
students[i].name, students[i].age, students[i].number, students[i].major);
}
return 0;
}
int main()
{
//字符数组可以存放字符串,我们可以对数组中的字符进行任意修改
char name[20] = "hello world";
//指针指向字符串常量,不能通过字符指针修改字符串常量。
char* str = "hello world";
name[0] = 'a';
str[0] = 'a';
printf("%s\n%s\n", name, str);
return 0;
}
练习4:
写一个函数print_all,功能是打印所有学生信息,在main里定义学生结构体数组,
然后调用print_all,打印
#include <stdio.h>
#include <string.h>
struct Student
{
char name[20];
int age;
char number[20];
char major[20];
};
void print_all(struct Student* arr, int len);
int main()
{
struct Student students[3] = {
{"xiaolan", 18, "10010", "c++"},
{"xiaolv", 18, "10086", "java"},
{"xiaohong", 17, "10000", "c#"}
};
print_all(students, 3);
return 0;
}
void print_all(struct Student* arr, int len)
{
int i;
for(i = 0;i < len;i++)
{
printf("%s %d %s %s\n",arr[i].name,
arr[i].age, arr[i].number, arr[i].major);
}
}
练习5:
编写函数,实现功能: 查询打印: 年龄 > 25 的学生信息。
#include <stdio.h>
#include <string.h>
struct Student
{
char name[20];
int age;
char number[20];
char major[20];
};
void print_all(struct Student* arr, int len);
int main()
{
struct Student students[3] = {
{"xiaolan", 18, "10010", "c++"},
{"xiaolv", 26, "10086", "java"},
{"xiaohong", 17, "10000", "c#"}
};
print_all(students, 3);
return 0;
}
练习6:
编写函数,实现功能: 查询打印:“xiaoli” 的学生信息。
int main()
{
char name1[20] = "hello world";
char name2[20] = "hello world";
printf("%d\n", name1==name2);//数组名是数组的首地址,两个数组的首地址不可能相等。输出0
return 0;
}
#include <stdio.h>
#include <string.h>
struct Student
{
char name[20];
int age;
char number[20];
char major[20];
};
void print_all(struct Student* arr, int len);
int main()
{
struct Student students[3] = {
{"xiaolan", 18, "10010", "c++"},
{"xiaoli", 26, "10086", "java"},
{"xiaohong", 17, "10000", "c#"}
};
print_all(students, 3);
return 0;
}
void print_all(struct Student* arr, int len)
{
int i;
for(i = 0;i < len;i++)
{
if(strcmp("xiaoli", arr[i].name)==0)
{
printf("%s %d %s %s\n",arr[i].name,
arr[i].age, arr[i].number, arr[i].major);
}
}
}
7.结构体嵌套
struct date
{
int year;
int month;
int day;
};
struct id_card
{
char name[20];
struct date birthday;//结构体成员可以是其他的结构体类型
};
示例3:
struct date
{
int year;
int month;
int day;
};
struct id_card
{
char name[20];
struct date birthday;//结构体成员可以是其他的结构体类型
};
int main()
{
struct id_card id;
strcpy(id.name, "Kayla");//对结构体变量id的name成员赋值
id.birthday.year = 2000;//对id的birthday成员的year成员赋值
id.birthday.month = 6;
id.birthday.day = 1;
printf("%s : %d-%d-%d\n", id.name, id.birthday.year, id.birthday.month, id.birthday.day);
}
2、结构体大小计算
结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节
示例4:
#include <stdio.h>
struct student
{
char a;
char c;
short b;
};
int main()
{
printf("%d\n", sizeof( struct student) );//4
}
示例5:
#include <stdio.h>
struct student
{
char a;
short age;
char c;
};
int main()
{
printf("%d\n", sizeof( struct student) );
}
对齐方式,结构体的“一行”有几个字节。“一行”的字节数取决于结构体成员中最大的成员的字节数。
示例6:
#include <stdio.h>
struct student
{
int x;
char a;
short b;
char c;
};
一个成员,要么自己占一行,如果不能自己占一行,要么全在左边,要么全在右边。
示例7:
struct Node
{
char c;
double d;
};
int main()
{
printf("%d\n", sizeof(struct Node));
return 0;
}
Linux 32位操作系统: 最长的对齐字节数:是4. double 占2个4.
不同的操作系统,最长的对齐字节数不同。
作业1:
1 定义时间结构体: 包含年、月、日成员
2 完成set_date函数
函数声明如下: void set_date(struct date *p, int y, int m, int d);
3 完成print_date函数
函数声明如下: void print_date(struct date *p);
4 完成main函数,
实现如下功能:
1) 定义 时间结构体变量 d1
2) 输入时间,并使用set_date函数设置给变量d1
3) 使用print_date函数输出设置的时间
作业2:
ar a;
short age;
char c;
};
int main()
{
printf("%d\n", sizeof( struct student) );
}
对齐方式,结构体的“一行”有几个字节。“一行”的字节数取决于结构体成员中最大的成员的字节数。
[外链图片转存中...(img-Xgsl4n60-1645663529865)]
## 示例6:
```C
#include <stdio.h>
struct student
{
int x;
char a;
short b;
char c;
};
一个成员,要么自己占一行,如果不能自己占一行,要么全在左边,要么全在右边。
[外链图片转存中…(img-teVpcuy8-1645663529866)]
示例7:
struct Node
{
char c;
double d;
};
int main()
{
printf("%d\n", sizeof(struct Node));
return 0;
}
Linux 32位操作系统: 最长的对齐字节数:是4. double 占2个4.
不同的操作系统,最长的对齐字节数不同。
作业1:
1 定义时间结构体: 包含年、月、日成员
2 完成set_date函数
函数声明如下: void set_date(struct date *p, int y, int m, int d);
3 完成print_date函数
函数声明如下: void print_date(struct date *p);
4 完成main函数,
实现如下功能:
1) 定义 时间结构体变量 d1
2) 输入时间,并使用set_date函数设置给变量d1
3) 使用print_date函数输出设置的时间
作业2:
定义学生结构体数组,编写函数对这个数组根据学生成绩进行降序排序,编写函数输出排序后的学生信息