目次
解決策 (2): パラメーターとしての構造体ポインター (より推奨)
11.2.2 構造と機能
int や float などのデータ型は関数のパラメータとして使用でき、構造体もデータ型として使用できます (前述のように)。
int NumberOfDays(構造体の日付 d)
- 構造全体をパラメータの値として関数に渡すことができます。
- このとき、関数内に新しい構造体変数が作成され、呼び出し元の構造体の値がコピーされます。
- 戻り値は構造体にすることもできます
- (上記の特性は配列とは全く異なります)
例
//求明天的日期
#include<stdio.h>
#include<stdbool.h>
//定义了一个 结构 类型,里面包含三个int类型的变量
struct date{
int month;
int day;
int year;
};
bool isLeap(struct date d);//判断是否是闰年函数
int numberOfDays(struct date d);//给出每个月有几天的函数
int main()
{
struct date today;
struct date tomorrow;
int sig=1;
printf("Enter today's date (mm dd yyyy):");
scanf("%i %i %i",&today.month,&today.day,&today.year);
//%i是旧写法,和%d一样是输出十进制整数的格式控制符
//&today.month是先进行点运算,取成员month,再将输入的数据用&取地址。
//因此点运算优先级高
//若今天不是本月最后一天(也就是本月的天数)
//明天就是天数加一
// printf("today mm %d\n",today.month);
//printf("这个月有%d天\n",numberOfDays(today));//这个月有32764天
if(today.day > numberOfDays(today) ||
today.month >12 ){
sig =0;
printf("非法输入,请检查输入是否正确");
}
if(today.day != numberOfDays(today)){
tomorrow.day = today.day+1;
tomorrow.month = today.month;
tomorrow.year = today.year;
//12月的最后一天,那么第二天就是第二年
}else if(today.month == 12){
tomorrow.day = 1;
tomorrow.month = 1;
tomorrow.year = today.year+1;
}else{
//不是12月,而且今天是本月最后一天,明天就是下个月第一天
tomorrow.day = 1;
tomorrow.month = today.month+1;
tomorrow.year = today.year;
}
if (sig){
printf("Tomorrow's date is %i-%i-%i.\n",
tomorrow.month,tomorrow.day,tomorrow.year);
}
return 0;
}
int numberOfDays(struct date d) //给出每个月有几天的函数
{
int days=0;
const int daysPerMonth[12]={31,28,31,30,31,30,31,31,30,31,30,31};
//printf("函数中的月份 %d\n",d.month); // 3
//printf("daysPerMonth[d.month-1]: %d\n",daysPerMonth[d.month-1]); //31
if(d.month == 2 && isLeap(d))//【if语句里面 判断相等!!一定要用==啊啊啊】
days = 29;
else{
days = daysPerMonth[d.month-1];
//因为数组下标从0开始,month.1对应数组【0】
}
//printf("days %d\n",days);
return days;//单一出口
}
bool isLeap(struct date d)
{
bool leap = false;
if((d.year%4 == 0 && d.year%100 != 0)|| d.year%400 == 0)
leap = true;
//符合条件为闰年
return leap;
}
//構造体変数は関数間で直接受け渡し可能
bool isLeap(struct date d); //閏年かどうかを判定する関数
int numberOfDays(struct date d); //各月の日数を与える関数
scanf 入力構造体
- 構造タイプ全体にはさまざまなタイプのユーザー定義データが含まれるため、構造タイプ全体に直接対応するフォーマット制御文字はありません。
- 次のような関数を使用して構造体を読み取る予定の場合:
-
#include<stdio.h> struct point{ int x; int y; }; void getStruct(struct point); void output(struct point); void main(){ struct point y = {0,0}; getStruct(y); output(y); } void getStruct(struct point p){ //接收到y结构变量的值,是另外一个结构变量 //因此执行完这个程序后,y不会改变,output函数输出0,0 scanf("%d",&p.x); scanf("%d",&p.y); printf("getstruct:%d,%d\n",p.x,p.y); } void output(struct point p){ printf("output:%d,%d\n",p.x,p.y); }
結果: (main の値は変更されません) ただし、関数に渡されるのは外部構造のクローンであり、コンテンツへのポインターではないためです。
解決策 (1): 一時変数
関数を使用して構造を読み取るという上記のアイデアは良いアイデアですが、関数に渡されるのはコンテンツへのポインターではなく、外部構造のクローンであるため、次の方法があります。
受信関数で一時構造変数を作成し、その一時構造を呼び出し元に返します。
#include<stdio.h>
struct point{
int x;
int y; };
struct point getStruct(void);
void output(struct point);
int main()
{
struct point y = {0,0};
y = getStruct();//这个函数不需要传入参数
//结构之间可以直接赋值,将临时结构p赋给y
output(y);
}
//一个返回类型为结构的函数
struct point getStruct(void)//这个函数不需要传入参数 但是它返回一个结构类型
{
struct point p;
scanf("%d",&p.x);
scanf("%d",&p.y);
printf("getStruct: %d,%d\n",p.x,p.y);
return p;//但是它返回一个结构类型
}
void output(struct point p){
printf("output: %d,%d\n",p.x,p.y);
}
解決策 (2): パラメーターとしての構造体ポインター (より推奨)
大きな構造体を関数に渡す場合は、ポインタをコピーするよりも効率的です。C では構造体を転送する方法が値によるため、呼び出される関数内に外部とまったく同じ構造体を作成するにはスペースと時間がかかります。
ポインタが指す構造体変数のメンバーを表す、より簡単な表記法があります。->
struct date{int month; int day; int year;} myday; //構造体の型が宣言され、構造体変数が作成されます
struct date *p = &myday; //mydayのアドレスを取り出してポインタpに与える
——ポインタが指す構造体変数(myday)のメンバ(月)——
(*p).month = 12; //1を書き込みます
p->month = 12; //2と書くと、中国語ではpが指す月と呼ばれます
この簡略化された記述方法を知っていると、解決策 1 のプログラムは次のように記述できます。
#include<stdio.h>
struct point{
int x;
int y; };
//函数的参数和返回类型现在都是结构指针
struct point* getStruct(struct point*);//传入指针 返回指针
void output(struct point);//传入结构变量
void print(const struct point *p);//传入结构指针(常量)
int main()
{
struct point y = {0,0};
getStruct(&y);//int *p=&a; 得到p(指向输出的xy) //getstruct函数返回的是指针p 也就是地址
output(y);
output(*getStruct(&y));
//output函数对其进行了*运算(地址上面的值)
//最后用%d 输出 printf函数拿出了地址 所以要用->指向指针p对应的地址
//才能用%d输出
/************************************************************************************************ */
//这里的参数意义:
//*代表了他要取出指针指向的变量,而此时指针指向的是另一个函数的返回值
//所以实际上传入的参数就是上一个函数的返回值
print(getStruct(&y)); //getStruct得到的指针 传给print print继续操作
//还可以做的是:
*getStruct(&y) = (struct point){1,2};
//为什么?因为左边实际上是个变量,这完全符合编译规则和语法
}
//传入指针操作之后又返回,好处是可以在之后继续调用这个指针
struct point* getStruct(struct point *p) //返回指针 struct point * 参数指针
{
scanf("%d",&p->x); //取p所指的y的x
scanf("%d",&p->y); //取p所指的y的y
printf("getStruct:%d,%d\n",p->x,p->y);
return p;
//返回得到的参数p
}
void output(struct point p){
printf("output:%d,%d\n",p.x,p.y);
}
void print(const struct point *p)
{
//由于只进行输出,传入指针可以是const
printf("print: %d %d",p->x,p->y);
}
11.2.3 構造内の構造
構造体の配列
配列が定義されており、配列内の各ユニットは自分で定義した変数です。
int a[100] //基本型
struct time a[100] //自分で宣言した型
例:
struct date dates[100];
//定义了一个结构数组,100字节大小的数组,每一个单元都是一个结构变量
struct date dates[]={
{4,5,2005},//dates[0]
{2,4,2005} //dates[1]
};
//调用内部数据:
printf("%i",dates[0].day);
printf("%.2f");
出力を実数型(浮動小数点型も可)で示し、小数点以下2桁を保持します。小数点以下2桁未満の場合は0または乱数を使用し、2桁を超える場合は四捨五入します。
構造内の構造
構造変数には、基本変数タイプまたは構造変数を指定できます。
struct dateAndTime{
struct date sdate;
struct time stime;
};
入れ子構造 (2 つの対角点で定義される長方形)
struct point{
int x;
int y;
};
struct rectangle{
struct point p1;
struct point p2;
};
int main()
{
struct rectangle r;
}
就可以有r.p1.x、r.p1.y、r.p2.x、r.p2.y等
来表示每个点
struct Rectangle r,*rp;
rp = &r;がある場合、同等の形式が 4 つ
あります。
- r.p1.x は r の p1 の x を取り出します。
- rp->p1.x rp が指す p1 の x
- (r.p1).x ドット演算子は左から右に作用するため、括弧を追加しても追加しなくても違いはありません。
- (rp->p1).x ポインターが最初にそれを指し、その後構造体がフェッチされるため、上記と同じです。
- しかし、rp->p1->x はありません ( p1 はポインタではなく構造体であり、もちろん他のものを指すことはできません)
構造内の構造の配列
無制限のマトリョーシカ:
#include<stdio.h>
struct point{
int x;
int y;
};
struct rectangle{
struct point p1;
struct point p2;
};
void printRect(struct rectangle r)
{
printf("<%d,%d> to <%d,%d>\n",
r.p1.x, r.p1.y, r.p2.x, r.p2.y);
}
int main()
{
int i;
struct rectangle rects[]=
{ {
{1,2},{3,4}},//{ 1 2, 3 4} 12是p1 34是p2
{
{5,6},{7,8}}
}
//rects[0].p1.x和y == {1,2}
//rects[0].p2.x和y == {3,4}
for(i=0;i<2;i++)
printRect(rects[i]);
return 0;
}