结构体和类
需要说明的是,C 语言本身没有类和对象的概念,类和对象是 C++ 面向对象编程中的特性。不过可以使用结构体来模拟实现题目要求的部分功能。
KiKi定义电子日历类

#include <stdio.h>
//定义电子日历结构体
typedef struct TDate{
int Month;
int Day;
int Year;
}TDate;
//带有默认值的初始化函数,模拟构造函数
void initDate(TDate *date,int year,int month,int day)
{
if(year==0 && month==0 && day==0)
{
date->Year=0;
date->Month=0;
date->Day=0;
}
else
{
date->Year=year;
date->Month=month;
date->Day=day;
}
}
//输出日期函数
void printDate(TDate date)
{
printf("%d/%d/%d\n",date.Day,date.Month,date.Year);
}
//设置日期函数
void setDate(TDate *date)
{
int year,month,day;
scanf("%d %d %d",&year,&month,&day);
date->Year=year;
date->Month=month;
date->Day=day;
}
int main() {
TDate date;
//初始化日期
initDate(&date, 0, 0, 0);
//设置日期
setDate(&date);
//输出日期
printDate(date);
return 0;
}
结构体成员排序qsort的使用(★)
使用步骤
- 定义结构体:明确结构体的成员,确定要依据哪个成员进行排序。
- 定义比较函数:这个函数的参数是两个
const void*类型的指针,在函数内部把它们转换为结构体指针,然后比较指定的结构体成员。- 调用
qsort函数:传入结构体数组的起始地址、元素数量、每个元素的大小以及比较函数。
示例 1:按整数成员排序
#include <stdio.h>
#include <stdlib.h>
// 定义结构体
typedef struct {
int id;
char name[20];
} Person;
// 比较函数,按 id 升序排序
int compareById(const void *a, const void *b) {
const Person *personA = (const Person *)a;
const Person *personB = (const Person *)b;
return personA->id - personB->id;
}
int main() {
Person people[] = {
{3, "Alice"},
{1, "Bob"},
{2, "Charlie"}
};
int n = sizeof(people) / sizeof(people[0]);
// 使用 qsort 排序
qsort(people, n, sizeof(Person), compareById);
// 输出排序后的结果
for (int i = 0; i < n; i++) {
printf("ID: %d, Name: %s\n", people[i].id, people[i].name);
}
return 0;
}
代码解释:
- 定义了
Person结构体,包含id和name两个成员。compareById函数将传入的void*指针转换为Person*指针,比较id成员,返回它们的差值,以此实现按id升序排序。- 在
main函数中,定义了一个Person结构体数组,调用qsort函数进行排序,最后输出排序后的结果。
示例 2:按字符串成员排序
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 定义结构体
typedef struct {
int id;
char name[20];
} Person;
// 比较函数,按 name 升序排序
int compareByName(const void *a, const void *b) {
const Person *personA = (const Person *)a;
const Person *personB = (const Person *)b;
return strcmp(personA->name, personB->name);
}
int main() {
Person people[] = {
{3, "Alice"},
{1, "Bob"},
{2, "Charlie"}
};
int n = sizeof(people) / sizeof(people[0]);
// 使用 qsort 排序
qsort(people, n, sizeof(Person), compareByName);
// 输出排序后的结果
for (int i = 0; i < n; i++) {
printf("ID: %d, Name: %s\n", people[i].id, people[i].name);
}
return 0;
}
代码解释:
- 同样定义了
Person结构体。compareByName函数将传入的void*指针转换为Person*指针,使用strcmp函数比较name成员,根据比较结果返回相应的值,实现按name升序排序。- 在
main函数中,调用qsort函数进行排序并输出结果。
示例 3:按浮点数成员排序(易错)
#include <stdio.h>
#include <stdlib.h>
// 定义结构体
typedef struct {
float score;
char name[20];
} Student;
// 比较函数,按 score 升序排序
int compareByScore(const void *a, const void *b) {
const Student *studentA = (const Student *)a;
const Student *studentB = (const Student *)b;
if (studentA->score < studentB->score) {
return -1;
} else if (studentA->score > studentB->score) {
return 1;
} else {
return 0;
}
}
int main() {
Student students[] = {
{85.5, "Alice"},
{90.0, "Bob"},
{78.3, "Charlie"}
};
int n = sizeof(students) / sizeof(students[0]);
// 使用 qsort 排序
qsort(students, n, sizeof(Student), compareByScore);
// 输出排序后的结果
for (int i = 0; i < n; i++) {
printf("Score: %.2f, Name: %s\n", students[i].score, students[i].name);
}
return 0;
}


代码解释:
- 定义了
Student结构体,包含score和name两个成员。compareByScore函数将传入的void*指针转换为Student*指针,比较score成员,根据比较结果返回 -1、0 或 1,实现按score升序排序。- 在
main函数中,调用qsort函数进行排序并输出结果。
通过以上示例,你可以掌握如何对结构体成员使用 qsort 函数进行排序。只需根据实际需求修改结构体定义和比较函数即可。
CC15 牛牛的书

#include <stdio.h>
#include <stdlib.h>
typedef struct books
{
char bookname[20];
int bookval;
}books;
int int_compare(const void* e1,const void* e2)
{
//将void*指针转化为book*指针
const books* book1=(const books*)e1;//要在结构体定义之后写
const books* book2=(const books*)e2;
//比较两个books结构体的bookval成员
return (book1->bookval)-(book2->bookval);
}
int main() {
int n=0;//书的数量
books book;
scanf("%d",&n);
//定义结构体数组来存储多本书的信息
books book_array[100];
for(int i=0;i<n;i++)
{
scanf("%s %d",book_array[i].bookname,&book_array[i].bookval);
}
//把书名按照价格升序输出。
qsort(book_array,n,sizeof(books),int_compare);
//输出书名
for(int j=0;j<n;j++)
{
printf("%s\n",book_array[j].bookname);
}
return 0;
}
链表
CC7 牛牛的单向链表

#include <stdio.h>
#include <stdlib.h>
//定义链表节点结构体
typedef struct Node
{
int data;
struct Node* next;
}Node;
//创建新节点
Node* createNode(int data)
{
Node* newNode=(Node*)malloc(sizeof(Node));
if(newNode==NULL)
{
printf("内存分配失败\n");
exit(1);
}
newNode->data=data;
newNode->next=NULL;
return newNode;
}
//将数组元素构建成链表
Node* arrayToLinkedList(int arr[],int n)
{
if(n==0) return NULL;
Node* head=createNode(arr[0]);
Node* current=head;
for(int i=1;i<n;i++)
{
current->next=createNode(arr[i]);
current=current->next;
}
return head;
}
//遍历链表并输出节点值
void printLinkedList(Node* head)
{
Node* current=head;
while(current!=NULL)
{
printf("%d",current->data);
if(current->next != NULL)
{
printf(" ");
}
current=current->next;
}
printf("\n");
}
//释放链表内存
void freeLinkedList(Node* head)
{
Node* temp;
while(head!=NULL)
{
temp=head;
head=head->next;
free(temp);
}
}
int main() {
int n;
scanf("%d",&n);
int arr[n];
for(int i=0;i<n;i++)
{
scanf("%d",&arr[i]);
}
Node* head=arrayToLinkedList(arr, n);
printLinkedList(head);
freeLinkedList(head);
return 0;
}

从键盘读取一个长度为 n 的数组,然后将数组元素构建成一个链表,并顺序输出链表每个节点的值。
#include <stdio.h>
#include <stdlib.h>
struct arr {
int data;
struct arr *next;
};
int main() {
int n;
scanf("%d", &n);
/*
定义了三个指向 struct arr 类型的指针:
head:指向链表的头节点,初始化为 NULL,表示链表为空。
tail:指向链表的尾节点,初始化为 NULL。
p:用于临时存储新创建的节点。
*/
struct arr *head, *tail, *p;
head = NULL;
tail = NULL; // 初始化 tail 指针
for (int i = 0; i < n; i++) {
//使用 malloc 函数为新节点分配内存,将分配的内存地址赋值给 p。
p = (struct arr *)malloc(sizeof(struct arr));
//检查内存分配是否成功,如果 p 为 NULL,说明内存分配失败,输出错误信息并返回 1 终止程序。
if (p == NULL) {
printf("内存分配失败\n");
return 1;
}
scanf("%d", &p->data);//从标准输入读取一个整数,并将其存储到新节点的 data 成员中。
p->next = NULL;//将新节点的 next 指针初始化为 NULL,表示该节点是链表的最后一个节点。
if (head == NULL) {//如果 head 为 NULL,说明链表为空,将 head 和 tail 都指向新节点。
head = p;
tail = p; // 第一个节点时,tail 指向头节点
} else {
//如果链表不为空,将 tail 的 next 指针指向新节点,然后更新 tail 指针指向新节点,使其成为新的尾节点。
tail->next = p;
tail = p; // 更新 tail 指针指向新的尾节点
}
}
for (p = head; p != NULL; p = p->next) {
printf("%d ", p->data);
}
// 释放链表内存
while (head != NULL) {
p = head;
head = head->next;
free(p);
}
return 0;
}
SSE刷题
数组
1、查找对应学号成绩(善用flag标识)

#include <stdio.h>
#define MAX_STUDENTS 40
int main() {
long ids[MAX_STUDENTS];
int scores[MAX_STUDENTS];
int student_count = 0;
long id;
int score;
// 输入学生的学号和成绩
while (student_count < MAX_STUDENTS) {
printf("Input student's ID and score:");
scanf("%ld%d", &id, &score);
if (id < 0 || score < 0) {
break;
}
ids[student_count] = id;
scores[student_count] = score;
student_count++;
}
// 输出学生总数
printf("Total students are %d\n", student_count);
// 输入要查找的学号
printf("Input the searching ID:");
long search_id;
scanf("%ld", &search_id);
// 查找该学号学生的成绩
int found = 0;
for (int i = 0; i < student_count; i++) {
if (ids[i] == search_id) {
printf("score = %d\n", scores[i]);
found = 1;
break;
}
}
// 如果未找到该学号的学生
if (!found) {
printf("Not found!\n");
}
return 0;
}
2、计算学生/每门课程总分平均分

#include <stdio.h>
#define MAX_STUDENTS 40
int main() {
int n;
long student_id[MAX_STUDENTS];
int mt_score[MAX_STUDENTS];
int en_score[MAX_STUDENTS];
int ph_score[MAX_STUDENTS];
int i;
// 输入学生总数
printf("Input the total number of the students(n<40):");
scanf("%d", &n);
// 输入每个学生的学号和成绩
printf("Input student’s ID and score as: MT EN PH:\n");
for (i = 0; i < n; i++) {
scanf("%ld %d %d %d", &student_id[i], &mt_score[i], &en_score[i], &ph_score[i]);
}
// 计算每个学生的总分和平均分
int sum_student[MAX_STUDENTS];
float aver_student[MAX_STUDENTS];
for (i = 0; i < n; i++) {
sum_student[i] = mt_score[i] + en_score[i] + ph_score[i];
aver_student[i] = (float)sum_student[i] / 3;
}
// 计算每门课程的总分和平均分
int sum_mt = 0, sum_en = 0, sum_ph = 0;
for (i = 0; i < n; i++) {
sum_mt += mt_score[i];
sum_en += en_score[i];
sum_ph += ph_score[i];
}
float aver_mt = (float)sum_mt / n;
float aver_en = (float)sum_en / n;
float aver_ph = (float)sum_ph / n;
// 输出结果
printf("Counting Result:\n");
printf("Student’s ID\t MT \t EN \t PH \t SUM \t AVER\n");
for (i = 0; i < n; i++) {
printf("%12ld\t%4d\t%4d\t%4d\t%4d\t%5.1f\n", student_id[i], mt_score[i], en_score[i], ph_score[i], sum_student[i], aver_student[i]);
}
printf("SumofCourse \t%4d\t%4d\t%4d\n", sum_mt, sum_en, sum_ph);
printf("AverofCourse\t%4.1f\t%4.1f\t%4.1f\n", aver_mt, aver_en, aver_ph);
return 0;
}
3、判断闰年输出相应月份天数

#include <stdio.h>
// 判断是否为闰年的函数
int isLeapYear(int year) {
return ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0));
}
// 获取指定年份和月份的天数
int getDaysInMonth(int year, int month) {
int days[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
// 如果是闰年且是 2 月,天数为 29
if (month == 2 && isLeapYear(year)) {
return 29;
}
return days[month - 1];
}
int main() {
int year, month;
while (1) {
printf("Input year,month:");
if (scanf("%d,%d", &year, &month) != 2) {
// 清除输入缓冲区
while (getchar() != '\n');
continue;
}
if (month >= 1 && month <= 12) {
int days = getDaysInMonth(year, month);
printf("The number of days is %d\n", days);
break;
}
}
return 0;
}
4、计算n阶矩阵对角线元素之和


int AddDiagonal(int n,int a[n][n]);//先声明n再写变长数组,不能反过来
#include <stdio.h>
// 输入矩阵元素的函数
void InputMatrix(int n, int a[n][n]) {
int i, j;
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++) {
scanf("%d", &a[i][j]);
}
}
}
// 计算主副对角线元素和的函数
int AddDiagonal(int n, int a[n][n]) {
int sum = 0;
int i;
// 计算主对角线元素和
for (i = 0; i < n; i++) {
sum += a[i][i];
}
// 计算副对角线元素和
for (i = 0; i < n; i++) {
sum += a[i][n - 1 - i];
}
// 若 n 为奇数,减去重复计算的中间元素
if (n % 2 == 1) {
sum -= a[n / 2][n / 2];
}
return sum;
}
int main() {
int n = 0;
printf("Input n:");
scanf("%d", &n);
int a[n][n];
printf("Input %d*%d matrix:\n", n, n);
InputMatrix(n, a);
int sum = AddDiagonal(n, a);
printf("sum = %d\n", sum);
return 0;
}
5、矩阵乘法(二维数组)

#include <stdio.h>
#define ROW 7
#define COL 7
//利用矩阵相乘公式cij= aik*bkj,编程计算并输出m×n阶矩阵A和n×m阶矩阵B之积。
//其中,m和n从键盘输入,m和n的值不超过6,否则提示用户重新输入,如果输入非法字符也提示用户重新输入。
/* 函数功能:计算m×n阶矩阵A和n×m阶矩阵B之积,结果存于二维数组c中 */
void MultiplyMatrix(int a[ROW][COL], int b[COL][ROW], int c[ROW][ROW],int m, int n)
{
//cij= aik*bkj
//因为c是m行m列
for(int i=0;i<m;i++)
{
for(int j=0;j<m;j++)
{
c[i][j]=0;
for(int k=0;k<n;k++)
{
c[i][j]+=a[i][k]*b[k][j];
}
}
}
}
/* 函数功能:输出m×m阶矩阵a中的元素 */
void PrintMatrix(int a[ROW][ROW],int m)
{
for(int i=0;i<m;i++)
{
for(int j=0;j<m;j++)
{
printf("%6d",a[i][j]);
}
printf("\n");
}
}
int main()
{
int m=0,n=0;//计算并输出m×n阶矩阵A和n×m阶矩阵B之积
int a[ROW][COL],b[COL][ROW],c[ROW][ROW];
while(1)
{
printf("Input m, n:");
if(scanf("%d,%d",&m,&n)!=2 || m<1 || m>6 || n<1 || n>6)
{
while(getchar()!='\n');//清空缓冲区
//printf("输入不合法,请重新输入m和n的值,范围在1到6之间。\n");
}else{
break;
}
}
printf("Input %d*%d matrix a:\n",m,n);//m×n阶矩阵A
for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++)
{
scanf("%d",&a[i][j]);
}
}
printf("Input %d*%d matrix b:\n",n,m);//n×m阶矩阵B
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
scanf("%d",&b[i][j]);
}
}
MultiplyMatrix(a,b,c,m,n);
printf("Results:\n");
PrintMatrix(c,m);
return 0;
}
6、矩阵转置/水平or垂直翻转(二维数组传参)

#include <stdio.h>
void InputMatrix(int Matrix[][10], int m, int n);
void OutputMatrix(int Matrix[][10], int m, int n);
void shuipingfz(int Matrix[][10], int m, int n);
void chuizhifz(int Matrix[][10], int m, int n);
void zhuanzhi(int Matrix[][10], int tempMatrix[][10], int m, int n);
int main() {
int m = 0, n = 0;
int Matrix[10][10];
int tempMatrix[10][10];
printf("Input m,n:\n");
scanf("%d,%d", &m, &n);
printf("Input %d*%d array:\n", m, n);
InputMatrix(Matrix, m, n);
int mode = 0;
printf("Input operation mode:\n");
scanf("%d", &mode);
switch (mode) {
case 0:
shuipingfz(Matrix, m, n);
break;
case 1:
chuizhifz(Matrix, m, n);
break;
case 2:
zhuanzhi(Matrix, tempMatrix, m, n);
break;
}
printf("After operation:\n");
//转置的话输出m和n要对调
if(mode==2)
OutputMatrix(Matrix, n, m);
else
OutputMatrix(Matrix, m, n);
return 0;
}
void InputMatrix(int Matrix[][10], int m, int n) {
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
scanf("%d", &Matrix[i][j]);
}
}
}
void OutputMatrix(int Matrix[][10], int m, int n) {
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
printf("%4d", Matrix[i][j]);
}
printf("\n");
}
}
void shuipingfz(int Matrix[][10], int m, int n) {
for (int i = 0; i < m; i++) {
int start = 0, end = n - 1;
int temp = 0;
while (start < end) {
temp = Matrix[i][end];
Matrix[i][end] = Matrix[i][start];
Matrix[i][start] = temp;
start++;
end--;
}
}
}
void chuizhifz(int Matrix[][10], int m, int n) {
for (int i = 0; i < n; i++) {
int start = 0, end = m - 1;
while (start < end) {
int temp = Matrix[end][i];
Matrix[end][i] = Matrix[start][i];
Matrix[start][i] = temp;
start++;
end--;
}
}
}
void zhuanzhi(int Matrix[][10], int tempMatrix[][10], int m, int n) {
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
tempMatrix[j][i] = Matrix[i][j];
}
}
// 把 tempMatrix 复制给 Matrix
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
Matrix[i][j] = tempMatrix[i][j];
}
}
}
指针
1、两数组元素交换(利用指针)


#include <stdio.h>
#define N 10
void ReadData(int a[], int n);
void PrintData(int a[], int n);
void Swap(int *x, int *y);
main()
{
int a[N]={0}, b[N]={0}, i=0, n=0;
printf("Input array size(n<=10):");
scanf("%d",&n);
printf("Input array a:");
ReadData(a, n);
printf("Input array b:");
ReadData(b, n);
for(i=0;i<n;i++)
{
Swap(&a[i], &b[i]);
}
printf("Output array a:");
PrintData(a, n);
printf("Output array b:");
PrintData(b, n);
}
/* 函数功能:输入数组a的n个元素值 */
void ReadData(int a[], int n)
{
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
}
}
/* 函数功能:输出数组a的n个元素值 */
void PrintData(int a[], int n)
{
for(int i=0;i<n;i++)
{
printf("%5d",a[i]);
}
printf("\n");
}
/* 函数功能:两整数值互换 */
void Swap(int *x, int *y)
{
int tmp=0;
tmp=*x;
*x=*y;
*y=tmp;
}
2、计算并打印每个学生各门课的总分和平均分(改错题)



#include <stdio.h>
#define STUD 30 // 最多可能的学生人数
#define COURSE 5 // 最多可能的考试科目数
// 函数声明
void Total(int pScore[][COURSE], int sum[], float aver[], int m, int n);
void Print(int pScore[][COURSE], int sum[], float aver[], int m, int n);
int main() {
int i, j, m, n, score[STUD][COURSE], sum[STUD];
float aver[STUD];
// 输入学生人数
printf("How many students? (max %d): ", STUD);
scanf("%d", &m);
if (m > STUD || m <= 0) {
printf("Invalid number of students!\n");
return 1;
}
// 输入课程数
printf("How many courses? (max %d): ", COURSE);
scanf("%d", &n);
if (n > COURSE || n <= 0) {
printf("Invalid number of courses!\n");
return 1;
}
// 输入成绩
printf("Input scores:\n");
for (i = 0; i < m; i++) {
for (j = 0; j < n; j++) {
scanf("%d", &score[i][j]);
}
}
// 计算总分和平均分
Total(score, sum, aver, m, n);
// 打印结果
Print(score, sum, aver, m, n);
return 0;
}
// 计算每个学生的总分和平均分
void Total(int pScore[][COURSE], int sum[], float aver[], int m, int n) {
int i, j;
for (i = 0; i < m; i++) {
sum[i] = 0;
for (j = 0; j < n; j++) {
sum[i] += pScore[i][j];
}
aver[i] = (float)sum[i] / n;
}
}
// 打印每个学生的成绩、总分和平均分
void Print(int pScore[][COURSE], int sum[], float aver[], int m, int n) {
int i, j;
printf("Result:\n");
for (i = 0; i < m; i++) {
for (j = 0; j < n; j++) {
printf("%4d\t", pScore[i][j]);
}
printf("%5d\t%6.1f\n", sum[i], aver[i]);
}
}
传递二维数组给函数的方式
方法1:固定列数的二维数组
如果二维数组的列数是固定的,可以直接将数组作为参数传递给函数。函数参数中需要指定列数。
#include <stdio.h>
#define ROWS 3
#define COLS 4
// 函数参数中指定列数
void printArray(int arr[][COLS], int rows) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < COLS; j++) {
printf("%d\t", arr[i][j]);
}
printf("\n");
}
}
int main() {
int arr[ROWS][COLS] = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
// 传递二维数组给函数
printArray(arr, ROWS);
return 0;
}

方法2:将二维数组展开为一维数组
如果二维数组的大小是固定的,可以将其展开为一维数组,并在函数中通过计算索引访问元素。
#include <stdio.h>
#define ROWS 3
#define COLS 4
// 将二维数组展开为一维数组
void printArray(int *arr, int rows, int cols) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
printf("%d\t", arr[i * cols + j]);
}
printf("\n");
}
}
int main() {
int arr[ROWS][COLS] = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
// 传递二维数组的首地址给函数
printArray(&arr[0][0], ROWS, COLS);
return 0;
}

方法3:使用结构体传递二维数组
可以将二维数组封装在结构体中,然后传递结构体给函数
#include <stdio.h>
#define ROWS 3
#define COLS 4
// 定义结构体
typedef struct {
int arr[ROWS][COLS];
} Matrix;
// 传递结构体给函数
void printArray(Matrix mat) {
for (int i = 0; i < ROWS; i++) {
for (int j = 0; j < COLS; j++) {
printf("%d\t", mat.arr[i][j]);
}
printf("\n");
}
}
int main() {
Matrix mat = {
{
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
}
};
// 传递结构体给函数
printArray(mat);
return 0;
}
如果二维数组的列数是固定的,推荐使用 方法1(固定列数的二维数组)。
如果二维数组的大小是固定的,且希望简化代码,可以使用 方法2(将二维数组展开为一维数组)或 方法3(使用结构体传递二维数组)。
3、交换数组中的最大最小值(用指针)

#include <stdio.h>
void ReadData(int a[], int n);
void PrintData(int a[], int n);
void MaxMinExchang(int a[], int n);
void Swap(int *x, int *y);
//编程实现计算数组a中n个整数的最大值和最小值,并互换它们在数组中的位置。
int main()
{
int a[10];
printf("Input 10 numbers:");
ReadData(a, 10);
MaxMinExchang(a, 10);
printf("Exchange results:");
PrintData(a, 10);
return 0;
}
/* 函数功能:输入数组a的n个元素值 */
void ReadData(int a[], int n)
{
int i;
for (i = 0; i < n; i++)
{
scanf("%d", &a[i]);
}
}
/* 函数功能:输出数组a的n个元素值 */
void PrintData(int a[], int n)
{
int i;
for (i = 0; i < n; i++)
{
printf("%5d", a[i]);
}
printf("\n");
}
/* 函数功能:将数组a中的最大数与最小数位置互换 */
void MaxMinExchang(int a[], int n)
{
int maxValue = a[0], minValue = a[0], maxPos = 0, minPos = 0;
int i,j;
for (i = 1; i < n; i++)
{
if (a[i] > maxValue)
{
maxValue = a[i];
maxPos = i;
}
}
for (j = 1; j < n; j++)
{
if (a[j] < minValue)
{
minValue = a[j];
minPos = j;
}
}
Swap(&a[maxPos],&a[minPos]);
}
/* 函数功能:两整数值互换 */
void Swap(int *x, int *y)
{
int temp;
temp=*x;
*x=*y;
*y=temp;
}
字符串
1、统计一行字符串中单词数量(strtok单词切割)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int CountWords(char str[])
{
//单词之间用空格隔开
char *token=strtok(str," ");
char vocabulary[100][80];//MAX_WORDS=100,MAX_WORD_LENGTH=80
int i=0;
while(token !=NULL && i<100)
{
if(strlen(token)<80)
{
strcpy(vocabulary[i],token);
}
i++;
token=strtok(NULL," ");
}
int vocabularynum=i;
return vocabularynum;
}
int main()
{
char str[80];
printf("Input a string:");
gets(str);
int num = CountWords(str);
printf("Numbers of words = %d\n",num);
return 0;
}

DeepSeek的代码
#include <stdio.h>
#include <string.h>
// 函数声明
int CountWords(char str[]);
int main() {
char str[80]; // 定义字符串数组,最大长度为80
// 输入提示信息
printf("Input a string: ");
gets(str); // 使用 gets() 输入字符串
// 调用函数统计单词数量
int num = CountWords(str);
// 输出结果
printf("Numbers of words = %d\n", num);
return 0;
}
// 统计字符串中的单词数量
int CountWords(char str[]) {
int wordCount = 0; // 初始化单词计数器
char *token; // 用于存储 strtok() 返回的单词
// 使用 strtok() 分割字符串
token = strtok(str, " "); // 第一次调用 strtok()
while (token != NULL) {
wordCount++; // 每找到一个单词,计数器加1
token = strtok(NULL, " "); // 继续查找下一个单词
}
return wordCount; // 返回单词数量
}
不使用strtok,常规方法
#include <stdio.h>
// 统计字符串中单词个数的函数
int CountWords(char str[]) {
int wordCount = 0;
int inWord = 0;
for (int i = 0; str[i] != '\0'; i++) {
if (str[i] == ' ') {
inWord = 0;
} else {
if (inWord == 0) {
wordCount++;
inWord = 1;
}
}
}
return wordCount;
}
int main() {
char str[81];
printf("Input a string:");
gets(str);
int wordCount = CountWords(str);
printf("Numbers of words = %d\n", wordCount);
return 0;
}

2、字符串逆序(2种思路)
思路1、第一个字符和最后一个对调,以此类推
//用字符数组作函数参数编程实现字符串逆序存放功能
#include <stdio.h>
#include <string.h>
void Swap(char *x,char *y)
{
char tmp=*x;
*x=*y;
*y=tmp;
}
void Inverse(char str[])
{
int n=strlen(str);
//{1,2,3,4,5} 第一个和最后一个对调 奇数个元素对调n/2次 偶数也是n/2
//str[0]=str[4]、str[1]=str[3]、str[2]=str[2]
int re=n/2;
for(int i=0;i<re;i++)
{
Swap(&str[i],&str[n-1-i]);
}
}
int main()
{
char str[100];
printf("Input a string:");
gets(str);
Inverse(str);
printf("Inversed results:%s\n",str);
return 0;
}
思路2、逆序存放到一个数组
#include <stdio.h>
#include <string.h>
void Inverse(char str[]) {
char tmp[100];
int n = strlen(str);
int j = 0;
// 正确的索引范围是从 n - 1 到 0
for (int i = n - 1; i >= 0; i--) {
tmp[j] = str[i];
j++;
}
// 添加字符串结束符
tmp[j] = '\0';
// 将 tmp 赋值给 str
strcpy(str, tmp);
}
int main() {
char str[100];
printf("Input a string:");
// 使用 fgets 函数替代 gets 函数
fgets(str, sizeof(str), stdin);
// 去除 fgets 可能读取到的换行符
if (str[strlen(str) - 1] == '\n') {
str[strlen(str) - 1] = '\0';
}
Inverse(str);
printf("Inversed results: %s\n", str);
return 0;
}

3、统计输入中一共有多少个三个字母及以上的单词(★)

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
int CountWords(char str[]); // 返回值为包含三个字母以上的单词个数
// 字符数组 str 用于存储用户输入的一行字符
int main() {
char str[80];
printf("Input a string:\n");
// 使用 fgets 代替 gets 避免缓冲区溢出
fgets(str, sizeof(str), stdin);
// 去除 fgets 可能读取到的换行符
if (str[strlen(str) - 1] == '\n') {
str[strlen(str) - 1] = '\0';
}
int n = CountWords(str);
printf("Numbers of words (include 3 or more letters) = %d\n", n);
return 0;
}
int CountWords(char str[]) {
// 单词切割保存到一个数组
char *token = strtok(str, " ");
int count = 0;
while (token != NULL) {
if (strlen(token) >= 3) {//直接判断token是不是>=3,就不用存入一个新的数组再去比较
count++;
}
// 正确调用 strtok 继续分割
token = strtok(NULL, " ");
}
return count;
}
我的思路就多了一步:单词切割后放入新数组,再去比较每个单词长度
//统计用户的输入中一共有多少个包含三个字母以上的单词(包括三个字母)
//单词之间以空格分开。
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
int CountWords(char str[]);//返回值为包含三个字母以上的单词个数
//字符数组str用于存储用户输入的一行字符
int main()
{
char str[80];
printf("Input a string:\n");
gets(str);
int n=CountWords(str);
printf("Numbers of words (include 3 or more letters) = %d\n",n);
return 0;
}
int CountWords(char str[])
{
//单词切割保存到一个数组
char *token=strtok(str," ");
char vocabulary[100][80];
int i=0;
while(token!=NULL && i<100)
{
if(strlen(token)<80)
{
strcpy(vocabulary[i],token);
}
i++;
//第二次调用 strtok 时应该传入 NULL 以继续从上次分割的位置开始,如果又传入了 str,这会导致每次都从字符串开头重新分割
token=strtok(NULL," ");
}
//看新数组中有几个单词字母数大于等于3
int count=0;
//使用i作为实际存储的单词量进行遍历
for(int j=0;j<i;j++)
{
if(strlen(vocabulary[j])>=3)
{
count++;
}
}
return count;
}
4、输入一个字符串包含五个国家名字,输出字典序最前面的国家名字

我理解错了,我以为是一次性输入一个字符串包括所有国家,原来是一个一个循环输入
我思路的代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int char_cmp(const void *e1,const void *e2)
{
return strcmp((const char*)e1,(const char*)e2);
}
int main()
{
char str[500];
printf("Input five countries' names:\n");
gets(str);
//单词切割
char *token=strtok(str," ");//第一次调用要赋值给token
char vocabulary[5][80];
int i=0;
while(token!=NULL && i<5)
{
if(strlen(token)<=80)
{
strcpy(vocabulary[i],token);
}
i++;
//更新token
token=strtok(NULL," ");//每次调用 strtok(NULL, " ") 后,若没有将返回值赋给 token,这会使其值不会更新,造成无限循环或者提前结束循环的问题。
}
//对五个国名排序,输出最前面的国名
//qsort 函数的第三个参数应该是每个元素的大小,而 sizeof(vocabulary[0][0]) 得到的是一个字符的大小
//正确的应该是 sizeof(vocabulary[0]),也就是一个国名的大小。
qsort(vocabulary,5,sizeof(vocabulary[0]),char_cmp);
printf("The minimum is:%s\n",vocabulary[0]);
return 0;
}
题意代码:(★)跟找最小值的思路是一样的
#include <stdio.h>
#include <string.h>
#define MAX_COUNTRIES 5
#define MAX_LENGTH 80
int main() {
char countries[MAX_COUNTRIES][MAX_LENGTH];
char min_country[MAX_LENGTH];
// 提示用户输入五个国名
printf("Input five countries' names:\n");
for (int i = 0; i < MAX_COUNTRIES; i++) {
// 使用 gets 输入每个国名
gets(countries[i]);
}
// 假设第一个国名是字典序最前的
strcpy(min_country, countries[0]);
// 遍历其余国名,找出字典序最前的
for (int i = 1; i < MAX_COUNTRIES; i++) {
if (strcmp(countries[i], min_country) < 0) {
strcpy(min_country, countries[i]);
}
}
// 输出字典序最前的国名
printf("The minimum is:%s\n", min_country);
return 0;
}
5、将string的第m个字符开始的n个字符逆序(start/end★)

#include <stdio.h>
#include <string.h>
void inverse(char str[],int m,int n)//将字符数组中的字符串的第m个字符开始的n个字符逆序存放
{
//abcdefgcascvcda,将第m=3个字符(c)开始的n=5个字符逆序存放:ab-gfedc-cascvcda【就是从下标m-1到下标(m+n-2)的数逆序】
int len=strlen(str);
//检查输入的m和n是否有效
if(m<1||n<1||m+n-1>len)
{
return;
}
//善于运用start和end(☆)
int start=m-1;
int end=m+n-2;
char temp;
while(start<end)
{
temp=str[start];
str[start]=str[end];
str[end]=temp;
start++;
end--;
}
}
int main()
{
int m,n;
char str[100];
printf("input m,n:");
scanf("%d,%d",&m,&n);
getchar();
printf("input the string:");
//用gets,用scanf指定了输入类型,不会输入数字空格之类的
gets(str);//abcdefgcascvcda,将第m=3个字符(c)开始的n=5个字符逆序存放:ab-gfedc-cascvcda【就是从下标m-1到下标(m+n-2)的数逆序】
inverse(str,m, n);//字符串的第m个字符开始的n个字符逆序存放
printf("the inverse string:%s",str);
return 0;
}
6、实现strcat的功能(字符串拼接)

#include <stdio.h>
// 自定义 strcat 函数
char* my_strcat(char* dest, const char* src) {
// 找到 dest 字符串的末尾
char* ptr = dest;
while (*ptr != '\0') {
ptr++;
}
// 将 src 字符串复制到 dest 末尾
while (*src != '\0') {
*ptr = *src;
ptr++;
src++;
}
// 添加字符串结束符
*ptr = '\0';
return dest;
}
int main() {
char str1[100];
char str2[100];
printf("Input the first string:");
scanf("%s", str1);
printf("Input the second string:");
scanf("%s", str2);
my_strcat(str1, str2);
printf("The result is: %s\n", str1);
return 0;
}
7、读入的国家名称按字典顺序排序

#include<stdio.h>
#include <string.h>
void Input(char p[][40], int n);
void Sort(char p[][40], int n);
void Print(char p[][40], int n);
int main()
{
char str[20][40];//最多20个国名,且长度不超过40
int i=0, n;
printf("Input n(n<=20):\n");
scanf("%d", &n);
getchar();//消耗scanf遗留的换行符(容易忘记)
Input(str, n);
Sort(str, n);
printf("Results:\n");
Print(str, n);
return 0;
}
void Input(char p[][40], int n)
{
int i;
for (i = 0; i < n; i++)
{
gets(p[i]);
}
}
void Sort(char p[][40], int n)
{
char t[100];
int i, j;
for (i = 0; i < n - 1; i++)
{
for (j =i+1; j < n; j++)
{
if (strcmp(p[j] , p[i])<0)
{
strcpy(t , p[i]);
strcpy(p[i] , p[j]);
strcpy(p[j] , t);
}
}
}
}
void Print(char p[][40], int n)
{
int i;
for (i = 0; i < n; i++)
{
printf("%s\n", p[i]);
}
}

结构体
1、姓名查找

#include <stdio.h>
#include <string.h>
#define N 5
struct Employee
{
int id;
char name[20];
int salary;
};
//查找函数
void searchEmployee(struct Employee emp[],int count,char *Search_name)
{
int found=0;
for(int i=0;i<count;i++)
{
if(strcmp(Search_name,emp[i].name)==0)
{
printf("%d,%s,%d\n",emp[i].id,emp[i].name,emp[i].salary);
found=1;
break;
}
}
if(!found)
{
printf("NOT FOUND!");
}
}
int main()
{
struct Employee emp[50];//结构体数组
printf("please input id,name,salary:\n");
int count=0;
int id,salary;
int name[20];
while(scanf("%d%s%d",&id,name,&salary)==3 && count<N)
{
emp[count].id=id;
strcpy(emp[count].name,name);//emp[i] 是结构体类型,应该使用 emp[i].name 来进行比较
emp[count].salary=salary;
count++;
}
printf("please input name to search:\n");
char Search_name[20];
scanf("%s",Search_name);
searchEmployee(emp,count,Search_name);
return 0;
}
2、统计某作者编写了几本书

#include <stdio.h>
#include <string.h>
struct book
{
char name_of_book[100];//书名
char author[25];//作者
};
//编写函数实现:统计某一作者编写了几本书
int writebookcount(struct book books[50],int n,char author[25])
{
int count=0;
for(int i=0;i<n;i++)
{
if(strcmp(author,books[i].author)==0)//books[i].author来访问数组中第i个结构体的author成员
{
count++;
}
}
return count;
}
int main()
{
int n=0;
char name_of_book[100];
char author[25];
printf("请输入书的数量:\n" );
scanf("%d",&n);
getchar();//读取并丢弃换行符
struct book books[50];//结构体数组
for(int i=0;i<n;i++)
{
printf("Please input %d name_of_book and author:\n",i+1);
scanf("%s %s",books[i].name_of_book,books[i].author);
getchar();//读取并丢弃换行符
}
printf("请输入作者的姓名并统计他编写书的数量:\n");
gets(author);
int count=writebookcount(books, n,author);
printf("作者%s编写了%d本书\n",author,count);
return 0;
}
3、统计候选人得票

#include <stdio.h>
#include <string.h>
//要求用结构体数组candidate表示3个候选人的姓名和得票结果
struct candidate
{
char name[10];
int vote;//结构体成员不能初始化
};
//自定义函数将字符串转换为小写(strlwr是非标准库函数)
void str_to_lower(char *str)
{
for(int i=0;str[i]!='\0';i++)
{
if(str[i]>='A'&&str[i]<='Z')
{
str[i]+=32;
}
}
}
int main()
{
//创建结构体数组
struct candidate candidates[3]={{"li",0},{"zhang",0},{"wang",0}};//三个候选人
char name[10];
//10个选民,选民每次输入一个得票的候选人的名字
//选民输错候选人姓名,则按废票处理。投票结束后程序自动显示各候选人的得票结果和废票信息
int waste=0;//废票
for(int i=0;i<10;i++)
{
printf("Input vote %d:",i+1);
scanf("%s",name);
str_to_lower(name);//输入的名字全部转小写
int found=0;//标记是否找到候选人
for(int j=0;j<3;j++)
{
if(strcmp(name,candidates[j].name)==0)//不区分大小写
{
candidates[j].vote++;
found=1;
break;
}
}
if(!found)
{
waste++;//没有找到就是废票
}
}
printf("Election results:\n");
for(int p=0;p<3;p++)
{
printf("%8s:%d\n",candidates[p].name,candidates[p].vote);
}
printf("Wrong election:%d\n",waste);
return 0;
}

函数
1、求最大公约数GCD和最小公倍数LCM




4和8的最大公约数是2,最小公倍数是(4*8)/2=16

#include <stdio.h>
int Gcd(int a, int b)//10,5
{
int temp=0;
while(b!=0)
{
temp=b;//temp=5
b=a%b;//b=0
a=temp;//a=5
}
return a;//5
}
int main()
{
int a=0,b=0;
printf("Input a,b:");
scanf("%d,%d",&a,&b);
if(a<0 || b<0)
{
printf("Input number should be positive!\n");
return -1;
}
else
{
int gcd=Gcd(a,b);
printf("Greatest Common Divisor of %d and %d is %d\n",a,b,gcd);
}
return 0;
}
理论知识
结构体
结构体是将不同数据类型的数据成员组织到同一的名字之下,适合于关系紧密、逻辑相关、具有相同或者不同属性的数据进行处理,尤其在数据库管理中得到广泛应用。
定义结构体及其变量
struct student
{
long studentID;
char studentName[10];
char studentSex;
int yearOfBirth;
int score[4];
};//最后的分号不能省略!是结构体声明结束的标志
运行按如下两种方法定义结构体变量:
(1)先声明结构体模板,再定义结构体变量
struct student stu1;
(2)在声明结构体模板的同时定义结构体变量
struct student
{
long studentID;
char studentName[10];
char studentSex;
int yearOfBirth;
int score[4];
}stu1;
当将结构体模板和结构体变量放在一起定义时,结构体标记是可选的,即也可以不出现结构体名
struct
{
long studentID;
char studentName[10];
char studentSex;
int yearOfBirth;
int score[4];
}stu1;
typedef为自定义数据类型定义别名
如:typedef int INTEGER; 为int定义了一个新名字INTEGER,也就是说int和INTEGER是同义词
typedef struct student STUDENT; //STUDENT是别名【struct student = STUDENT】
与
typedef struct student
{
long studentID;
char studentName[10];
char studentSex;
int yearOfBirth;
int score[4];
}STUDENT;
等价
结构体变量初始化
STUDENT stu1={10021313,"王刚",'M',1991,{72,83,90,82}};
等价于
struct student stu1={10021313,"王刚",'M',1991,{72,83,90,82}};
结构体变量的引用
访问结构体变量的成员必须使用成员选择运算符(也叫做圆点运算符)
结构体变量名 . 成员名
stu1.studentID=100310121;
当结构体出现嵌套,要通过成员选择运算符逐级找到最底层的成员时再引用
stu1.birthday.year=1991;
C语言允许具有相同结构体类型的变量进行整体赋值(★)
可以通过结构体对数组进行直接赋值(★)
typedef struct{
int member[5];
}ARRAY;
ARRAR a={1,2,3,4,5};
ARRAY b;
b=a; //通过结构体的方式将数组a直接赋值给数组b;
(字符串可以通过strcpy(str1,str2)将str2赋值给str)
并非所有的结构体成员都可以使用赋值运算符来赋值,对于字符数组类型的结构体成员进行赋值,必须使用字符串处理函数strcpy();
不能使用“==”和“!=”来判定两个结构体是否相等,要逐个比较结构体的每一个字段。
if(strcmp(a.name,b.name)==0 && a.age==b.age) { printf("结构体a和b相等\n"); }
结构体数组的定义及初始化
STUDENT stu[30];
定义了有30个元素的结构体数组,每个元素的类型为STUDENT。
该数组所占内存字节数为30*sizeof(STUDENT)
此时访问第一个学生学号用stu[0].studentID
访问第四个学生出生年用stu[3].birthday.year
结构体数组的初始化:
STUDENT stu[30]={
{10021313,"王刚",'M',{1991,5,9},{72,83,90,82}},
{10021353,"李晓明",'M',{1992,8,10},{71,80,70,82}},
{10021342,"王立勇",'M',{1992,3,22},{90,87,80,92}},
{10021322,"萧红",'F',{1991,10,6},{82,93,92,72}}
};
结构体指针的定义和初始化
指向结构体变量的指针
STUDENT *pt;/*定义指向STUDENT结构体的指针变量*/
这里只是定义了一个指向STUDENT结构体类型的指针变量pt,但是此时的pt并没有指向一个确定的存储单元,其值是一个随机值。
初始化:
pt=&stu1; 使得指针pt指向结构体变量stu1所占内存空间的首地址,即pt是指向结构体变量stu1的指针
当然也可以STUDENT *pt = &stu1;
访问结构体指针变量所指向的结构体成员
指向结构体的指针变量名 --> 成员名
要访问结构体指针变量pt指向的结构体studentID成员 pt->studentID=100310121; 与 (*pt).studentID=100310121;【不常用】 等价 先将(*pt)作为一个整体,取出pt指向的结构体的内容,再将其看成一个结构体变量,利用圆点(成员选择)运算符访问它的成员 若要访问结构体指针变量pt指向的结构体的birthday成员要用下面语句: pt->birthday.year=1991; pt->birthday.month=5; pt->birthday.day=19;
共用体
共用体虽然也可以表示逻辑相关的不同类型的数据集合,但其数据成员是情形互斥的,每一时刻只有一个数据成员起作用。
例如,添加“婚姻状况”,只能用共用体数据类型来表示,因为未婚、已婚和离婚这几种情形是互斥的。
动态数据结构——链表


结构体类型link当中,成员变量next的类型也是结构体link类型,编译器读到“struct link next;”的时候,没有办法确定next所占的内存空间大小,也就没有办法完成这个定义。因为在定义next的时候link这个结构体类型还没有定义完成,所以也就没办法知道next的具体类型是什么(而第二种写法“struct link *next;”,指针的大小是固定的)

单向链表的基本概念
编译器在定义结构体所做的主要 工作是确定这个结构体类型所占内存空间大小

已经知道pt是一个指针变量(所占内存空间大小确定)


链表的首尾相连是指,第一个节点的指针域存的是第二个节点的地址,以此类推




913

被折叠的 条评论
为什么被折叠?



