结构体的基础知识
① 结构体是一些值的集合,这些值称为成员变量;
② 结构体的每个成员可以是不同类型得变量;
结构体的声明
注意事项:
① 成员变量之间用分号隔开,全局变量之间用逗号隔开;
② 结构体末大括号后 必须加上分号(即使不写全局变量也要加上);
结构体的声明:使用结构体描述一个学生
描述一个学生需要一些数据:姓名、年龄、性别、学号
/* 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; }
本篇完。