目录
结构体的基础知识
① 结构体是一些值的集合,这些值称为成员变量;
② 结构体的每个成员可以是不同类型得变量;
结构体的声明

注意事项:
① 成员变量之间用分号隔开,全局变量之间用逗号隔开;
② 结构体末大括号后 必须加上分号(即使不写全局变量也要加上);
结构体的声明:使用结构体描述一个学生
描述一个学生需要一些数据:姓名、年龄、性别、学号
/* struct 结构体关键字 Stu - 结构体标签 struct Stu - 结构体类型 */
struct Stu
{
/* 成员变量 */
char name[20]; // 定义一个结构体类型
int age;
char sex[10];
char id[20];
} s1, s2, s3; //创建三个全局的结构体变量(可以不创建),再次提醒,分号不能丢!
int main()
{
struct Stu s; // 创建局部的结构体变量
return 0;
}
结构成员的类型
结构的成员可以是标量、数组、指针,甚至是其他结构体。
#include<stdio.h>
struct Stu
{
char name[20];
int age;
char sex[10];
char id[20];
};
struct School
{
char school_name[30]; // 数组
struct Stu s; // 结构体
char* pc; // 地址
};
int main()
{
char arr[] = "地球\n";
struct School bili = { "哔哩大学", {"小明", 19, "男", "641664"}, arr };
printf("校名 - %s\n", bili.school_name);
printf("学生 - 姓名:%s, 年龄:%d, 性别:%s, 学号:%s\n",bili.s.name,bili.s.age,bili.s.sex,bili.s.id);
printf("地址 - %s\n", bili.pc);
return 0;
}
结构体变量的定义和初始化
定义方法:
① 在定义结构体时定义(全局);
② 在创建结构体变量时定义(局部);
初始化方法:使用大括号对结构体进行初始化;
typedef struct Stu
{
char name[20]; // 定义一个结构体类型
int age;
char sex[10];
char id[20];
} Stu;
int main()
{
Stu s1 = { "GR", 19, "男", "35" };// 使用大括号初始化
Stu s2 = { "小明", 21, "男", "54645661146" };
return 0;
}
#include<stdio.h>
struct Point
{
int x;
int y;
}p1; //声明类型的同时定义变量p1 这里定义的变量都是全局变量,
//把下一行放在mian函数里就是局部变量
struct Point p2; //定义结构体变量p2
//初始化:定义变量的同时赋初值。
struct Point p3 = { 1, 2 };
struct Stu //类型声明
{
char name[15];//名字
int age; //年龄
};
struct Stu s = { "zhangsan", 20 };//初始化
struct Node
{
int data;
struct Point p;
struct Node* next;
}n1 = { 10, {4,5}, NULL }; //结构体嵌套初始化
struct Node n2 = { 20, {5, 6}, NULL };//结构体嵌套初始化
数据类型定义 typedef
typedef struct Stu
{
char name[20];
int age;
char sex[10];
char id[20];
} Stu;
int main()
{
Stu s1; // 加了之后可以作为一个单独的类型来使用
struct Stu s2;// 不影响
return 0;
}
结构体成员的访问
结构变量的成员通过点操作符访问
结构变量的成员通过点操作符(.)访问的。点操作符接受两个操作数。
例如:
#include<stdio.h>
struct Stu
{
char name[20];
int age;
};
int main()
{
struct Stu s = { "GR", 19 };
printf("%s\n", s.name);//使用点操作符访问age成员
printf("%d\n", s.age);//使用点操作符访问age成员
return 0;
}
结构体指针访问指向变量的成员
有时候我们得到的不是一个结构体变量,而是指向一个结构体的指针。那该如何访问成员。
结构体传参
传参形式:
① 传结构体(使用结构体接收);
② 传地址(使用结构体指针接收);
如果选用传地址,可以通过 箭头操作符 访问
如下:
#include<stdio.h>
struct Stu //类型声明
{
char name[20];//名字
int age; //年龄
};
void print(struct Stu* ps)
{
printf("name = %s age = %d\n", (*ps).name, (*ps).age);
//使用结构体指针访问指向对象的成员
printf("name = %s age = %d\n", ps->name, ps->age);
}
int main()
{
struct Stu s = { "zhangsan", 20 };
print(&s);//结构体地址传参
return 0;
}
传结构体 和 传地址 哪种方法更好些? 答案:传地址更好;
原因:
函数传参的时候,参数是需要压栈的。
如果传递一个结构体对象的时候,结构体过大,参数压栈的的系统开销比较大,所以会导致性能的下降。
结论:
结构体传参的时候,要传结构体的地址。
知识点完
笔试题
程序的输出结果是:( )
struct stu
{
int num;
char name[10];
int age;
};
void fun(struct stu *p)
{
printf(“%s\n”,(*p).name);
return;
}
int main()
{
struct stu students[3] = {{9801,”zhang”,20},
{9802,”wang”,19},
{9803,”zhao”,18}
};
fun(students + 1);
return 0;
}
A.zhang
B.zhao
C.wang
D.18
答案解析:
在main函数中先定义了一个stu结构体类型的数组students,students指向结构体的起始位置,students+1表示该数组中的第一个元素,因此fun的形参实际指向的是students数组中的第一个元素,故打印的是wang
因此:选择C
下面哪个是指针数组:( )
A.int* arr[10];
B.int * arr[];
C.int **arr;
D.int (*arr)[10];
答案解析:
指针数组是一个数组,该数组的每个元素是一个指针
A:正确,定义了一个数组,该数组中有10个元素,每个元素都是int*的指针类型
B:错误,编译失败,定义数组时,要给出空间的大小,如果没有给时,必须要给出初始化结果
C:错误,定义了一个二级指针
D:错误,*和arr先结合,说明arr不是数组。实际上arr是一个指针,一个指向数组的指针。
因此:选择A
打印自幂数(水仙花数)
求出0~100000之间的所有“自幂数”并输出。
自幂数是指一个 n 位数,它的每个位上的数字的 n 次幂之和等于它本身。(例如:当n为3时,有1^3 + 5^3 + 3^3 = 153,153即是n为3时的一个自幂数。)
n为1时,自幂数称为独身数。显然,0,1,2,3,4,5,6,7,8,9都是自幂数;
n为2时,没有自幂数;
n为3时,自幂数称为水仙花数,有4个:153,370,371,407;
n为4时,自幂数称为四叶玫瑰数,共有3个:1634,8208,9474;
n为5时,自幂数称为五角星数,共有3个:54748,92727,93084;
n为6时,自幂数称为六合数,只有1个:548834;
n为7时,自幂数称为北斗七星数,共有4个:1741725,4210818,9800817,9926315;
n为8时,自幂数称为八仙数,共有3个:24678050,24678051,88593477;
n为9时,自幂数称为九九重阳数,共有4个:146511208,472335975,534494836,912985153;
n为10时,自幂数称为十全十美数,只有1个:4679307774。
#include<stdio.h>
#include<math.h>
int main()
{
for (int i = 0;i <= 100000;i++)
{
int tmp = i, sum = 0, n = 1;
while (tmp /= 10)//1. 求判断数字的位数
{
n++;
}
tmp = i;
for (;tmp;tmp /= 10)//2. 计算每一位的次方和
{
sum += pow(tmp % 10, n);
}
if (sum == i)//3. 判断
printf("%d ", i);
}
return 0;
}
喝汽水问题
喝汽水,1瓶汽水1元,2个空瓶可以换一瓶汽水,给20元,可以多少汽水(编程实现)。
#include<stdio.h>
int main()
{
int money = 0, total = 0, empty = 0;//钱,得到的汽水总数,空瓶
scanf("%d", &money);
total = money;
empty = total;
while (empty > 1)
{
total += empty / 2;
empty = empty / 2 + empty % 2;
}
printf("%d", total);
return 0;
}
打印棱形图案
用C语言在屏幕上输出以下图案:

/*
思路:
仔细观察图形,可以发现,此图形中是由空格和*按照不同个数的输出组成的。
上三角:先输出空格,后输出*,每行中
空格:从上往下,一行减少一个
*:2*i+1的方式递增
下三角:先输出空格,后输出*,每行中
空格:从上往下,每行多一个空格
*: 从上往下,按照2*(line-1-i)-1的方式减少,其中:line表示总共有多少行
按照上述方式,将上三角和下三角中的空格和*分别输出即可。
*/
#include<stdio.h>
int main()
{
int line = 0;
int i = 0;
scanf("%d", &line);//7
//打印上半部分
for(i=0; i<line; i++)
{
//打印一行
//打印空格
int j = 0;
for(j=0; j<line-1-i; j++)
{
printf(" ");
}
//打印*
for(j=0; j<2*i+1; j++)
{
printf("*");
}
printf("\n");
}
//打印下半部分
for(i=0; i<line-1; i++)
{
//打印一行
int j = 0;
for(j=0; j<=i; j++)
{
printf(" ");
}
for(j=0; j<2*(line-1-i)-1; j++)
{
printf("*");
}
printf("\n");
}
return 0;
}
字符串逆序
写一个函数,使用指针逆序一个字符串的内容。
#include<stdio.h>
#include<string.h>
void reverse(char* p)
{
int sz = strlen(p);
int left = 0, right = sz - 1;
while (left < right)
{
int tmp = *(p + left);
*(p + left) = *(p + right);
*(p + right) = tmp;
left++;
right--;
}
}
int main()
{
char arr[50] = { 0 };
scanf("%s", arr);
reverse(arr);
for (int i = 0;i < sizeof(arr) / sizeof(arr[0]);i++)
{
printf("%c", arr[i]);
}
return 0;
}
本篇完。