網(wǎng)站動態(tài)海報效果怎么做的寧波seo搜索引擎優(yōu)化公司
C語言進階 11.結(jié)構(gòu)體
文章目錄
- C語言進階 11.結(jié)構(gòu)體
- 11.1. 枚舉
- 11.2. 結(jié)構(gòu)類型
- 11.3. 結(jié)構(gòu)與函數(shù)
- 11.4. 結(jié)構(gòu)中的結(jié)構(gòu)
- 11.5. 類型定義
- 11.6. 聯(lián)合
- 11.7. PAT
- 11-0. 平面向量加法(10)
- 11-1. 通訊錄的錄入與顯示(10)
11.1. 枚舉
-
常量符號化:
- 用符號而不是具體的數(shù)字表示程序中的數(shù)字
- const int red = 0;
- const int yellow = 1;
- const int green = 2;
- 用符號而不是具體的數(shù)字表示程序中的數(shù)字
-
枚舉:
-
用枚舉而不是定義獨立的const int變量
- enum COLOR { RED, YELLOW, GREEN };//0 1 2
-
枚舉是一種用戶定義的數(shù)據(jù)類型, 它用關(guān)鍵字enum以如下語法來聲明:
- enum枚舉類型名字{ 名字0, …, 名字n };
-
枚舉類型名字通常并不真的使用, 要用的是在打括號里的名字, 因為它們就是常量符號, 它們的類型是int, 值則依次從0到n, 如:
- enum colors { red, yellow, green };//三個常量, red是0, yellow是1, green是2
-
當需要一些可以排列起來的常量值時, 定義枚舉的意義就是給了這些常量值名字
-
枚舉類型可以跟上enum作為類型
- void f(enum COLOR c);
-
它是以整數(shù)來做內(nèi)部計算和外部輸入輸出的
-
-
套路: 自動計數(shù)的枚舉:
- 這樣需要遍歷所有的枚舉量或者建立一個用枚舉量做下標的數(shù)組的時候就很方便了
- enum COLOR { RED, YELLOW, GREEN, NumCOLORS };//NumCOLORS就表示這個枚舉有多少個量
char* ColorNames[NumCOLORS] = {"red","yellow","green", };
- 這樣需要遍歷所有的枚舉量或者建立一個用枚舉量做下標的數(shù)組的時候就很方便了
-
枚舉量:
- 聲明枚舉量的時候可以指定值
- enum COLOR { RED = 1; YELLOW, GREEN = 5 };//1 2 5
- 聲明枚舉量的時候可以指定值
-
枚舉只是int:
- 即使給枚舉類型的變量賦不存在的整數(shù)值也沒有任何的warning或error
- enum COLOR RED = 3;
- 即使給枚舉類型的變量賦不存在的整數(shù)值也沒有任何的warning或error
-
枚舉:
-
雖然枚舉類型可以當作類型使用, 但是實際上很(bu)少(hao)用
-
如果有意義上排比的名字, 用枚舉比const int方便
-
枚舉比宏(macro)好, 因為枚舉有int類型
-
#include <stdio.h>const int red = 0;
const int yellow = 1;
const int green = 2;enum COLOR { RED, YELLOW, GREEN };//0 1 2void f(enum COLOR c);int main(int argc, char const* argv[]) {int color = -1;scanf("%d", &color);char* colorName = NULL;printf("%d %d %d\n", RED, YELLOW, GREEN);switch (color) {case RED: colorName = "red"; break;case YELLOW: colorName = "yellow"; break;case GREEN: colorName = "green"; break;default: colorName = "unknown"; break;}printf("%s\n", colorName);return 0;
}
#include <stdio.h>enum COLOR { RED, YELLOW, GREEN, NumCOLORS };int main(int argc, char const* argv[]) {int color = -1;char* ColorNames[NumCOLORS] = {"red","yellow","green",};char* colorName = NULL;scanf("%d", &color);if (color >= 0 && color < NumCOLORS) {colorName = ColorNames[color];}else {colorName = "unknown";}printf("%s\n", colorName);return 0;
}
11.2. 結(jié)構(gòu)類型
-
聲明結(jié)構(gòu)類型:
- 一個結(jié)構(gòu)就是一個復合的數(shù)據(jù)類型, 里面可以有各種不同類型的成員, 用一個變量來表達它們
struct date { //一個結(jié)構(gòu)可以有多個成員int month;int day;int year;//成員變量 }; //初學者最常見的錯誤: 漏了這個分號
- 一個結(jié)構(gòu)就是一個復合的數(shù)據(jù)類型, 里面可以有各種不同類型的成員, 用一個變量來表達它們
-
在函數(shù)內(nèi)/外?
- 和本地變量一樣, 在函數(shù)內(nèi)部聲明的結(jié)構(gòu)類型只能在函數(shù)內(nèi)部使用
- 所以通常在函數(shù)外部聲明結(jié)構(gòu)類型, 這樣就可以被多個函數(shù)所使用了
-
聲明結(jié)構(gòu)的形式:
-
- struct point{
int x;
int y;
};
struct point p1, p2;
- p1和p2都是point里面有x和y的值
- struct point{
-
- struct {
int x;
int y;
} p1, p2;
- p1和p2都是一種無名結(jié)構(gòu), 里面有x和y
- struct {
-
- struct point {
int x;
int y;
} p1, p2;
- p1和p2都是point里面有x和y的值
- struct point {
-
第一和第三種形式, 都聲明了結(jié)構(gòu)point并定義了兩個變量, 而第二種形式?jīng)]有聲明point
-
-
結(jié)構(gòu)變量:
-
struct date today; //定義結(jié)構(gòu)變量
-
today.month = 07; //給變量賦值
today.day = 31;
today.year = 2014;
-
-
結(jié)構(gòu)的初始化:
- struct date today = { 07, 31, 2014 };
- struct date today = { .month = 07, .year = 2014 };//.day沒有初始化, 和數(shù)組初始化一樣, 默認為0
-
結(jié)構(gòu)成員:
-
結(jié)構(gòu)和數(shù)組有點像, 數(shù)組當中有很多的單元, 而結(jié)構(gòu)當中有很多的成員, 不同的是, 數(shù)組當中的單元只能是相同類型的, 而結(jié)構(gòu)當中的成員可以是不同類型的
-
數(shù)組用[]運算符和下標訪問其成員
- a[0] = 10;
-
結(jié)構(gòu)用.運算符和名字訪問其成員
today.day
today.month
today.year
-
-
結(jié)構(gòu)運算:
-
要訪問整個結(jié)構(gòu), 直接用結(jié)構(gòu)變量的名字
-
對于整個結(jié)構(gòu), 可以做賦值, 取地址, 也可以傳遞給函數(shù)參數(shù)
p1 = (struct point){5, 10};//相當于p1.x = 5; p1.y = 10;p1 = p2; //相當于p1.x = p2.x; p1.y = p2.y;
-
-
結(jié)構(gòu)指針:
- 和數(shù)組不同, 結(jié)構(gòu)變量的名字并不是結(jié)構(gòu)變量的地址, 必須使用&運算符
- struct date* pDate = &today;
- 和數(shù)組不同, 結(jié)構(gòu)變量的名字并不是結(jié)構(gòu)變量的地址, 必須使用&運算符
#include <stdio.h>struct date { //聲明結(jié)構(gòu)類型int month;int day;int year;
};
struct point {int x;int y;
};
int main(int argc, char const* argv[]) {struct date today = { 07, 31, 2014 }; //定義結(jié)構(gòu)變量today.month = 07; //訪問結(jié)構(gòu)成員today.day = 31;today.year = 2014;today = (struct date){ 07, 31, 2014 };//類型轉(zhuǎn)換struct date day;day = today; //結(jié)構(gòu)變量給結(jié)構(gòu)變量賦值, 而數(shù)組是不能這樣做的day.year = 2015;struct date* pDate = &today;printf("Today's date is %i-%i-%i.\n", today.year, today.month, today.day);printf("day's date is %i-%i-%i.\n", day.year, day.month, day.day);printf("address of today is %p\n", pDate);return 0;
}
11.3. 結(jié)構(gòu)與函數(shù)
-
沒聽懂
-
結(jié)構(gòu)作為函數(shù)參數(shù):
-
int numberOfDays(struct date d)
-
整個結(jié)構(gòu)可以作為參數(shù)的值傳入函數(shù)
-
這時候是在函數(shù)內(nèi)新建一個結(jié)構(gòu)變量, 并復制調(diào)用者的結(jié)構(gòu)的值
-
也可以返回一個結(jié)構(gòu)
-
這與數(shù)組是完全不同的
-
-
輸入結(jié)構(gòu):
-
沒有直接的方式可以一次scanf一個結(jié)構(gòu)
-
如果我們打算寫一個函數(shù)來讀入結(jié)構(gòu)
-
但是讀入的結(jié)構(gòu)如何送回來呢?
-
記住C在函數(shù)調(diào)用時是傳值的
-
所以函數(shù)中的p與main中的y是不同的
-
在函數(shù)讀入了p的數(shù)值之后, 沒有任何東西回到main, 所以y還是{0,0}
-
-
解決方案:
-
之前的方案, 把一個結(jié)構(gòu)傳入了函數(shù), 然后再函數(shù)中操作, 但是沒有返回回去
- 問題在于傳入函數(shù)的是外面那個結(jié)構(gòu)的克隆體, 而不是指針
- 傳入結(jié)構(gòu)和傳入數(shù)組是不同的
- 問題在于傳入函數(shù)的是外面那個結(jié)構(gòu)的克隆體, 而不是指針
-
在這個輸入函數(shù)中, 完全可以創(chuàng)建一個臨時的結(jié)構(gòu)變量, 然后把這個結(jié)構(gòu)返回給調(diào)用者
-
-
-
結(jié)構(gòu)指針作為參數(shù):
- C語言經(jīng)典教材<<K & R>>說過(p.131)
- If a large structure is to be passed to a function, it is generally more efficient to pass a pointer than to copy the whole structure.
- 傳一個結(jié)構(gòu)給函數(shù)的時候, 應(yīng)該傳指針, 而不是整個結(jié)構(gòu)
- C語言經(jīng)典教材<<K & R>>說過(p.131)
-
指向結(jié)構(gòu)的指針:
-
用->表示指針所指的結(jié)構(gòu)變量中的成員
-
(*p).month = 12;
-
p->month = 12;//這個寫法更簡潔, ->讀作arrow
-
有了這個運算符之后, 就可以將3當中實現(xiàn)的代碼修改
-
-
輸入今天的日期, 打印明天的日期
#include <stdio.h>
#include <stdbool.h>struct date {int month;int day;int year;
};bool isLeap(struct date d);
int numberOfDays(struct date d);int main(int argc, char const* argv[]) {struct date today, tomorrow;printf("Enter today's date (mm dd yyyy):");scanf("%i %i %i", &today.month, &today.day, &today.year);if (today.day != numberOfDays(today)) {tomorrow.day = today.day + 1;tomorrow.month = today.month;tomorrow.year = today.year;}else if (today.month == 12) {tomorrow.day = 1;tomorrow.month = 1;tomorrow.year = today.year + 1;}else {tomorrow.day = 1;tomorrow.month = today.month + 1;tomorrow.year = today.year;}printf("Tomorrow's date is %i-%i-%i.\n", tomorrow.year, tomorrow.month, tomorrow.day);return 0;
}int numberOfDays(struct date d) {int days;const int daysPerMonth[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 };if (d.month == 2 && isLeap(d)) {days = 29;}else {days = daysPerMonth[d.month - 1];}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;
}
- 方案一完成入讀結(jié)構(gòu)的功能, 行不通
#include <stdio.h>struct point {int x;int y;
};void getStruct(struct point);
void output(struct point);int main(void) {struct point y = { 0,0 };getStruct(y);output(y);
}void getStruct(struct point p) {scanf("%d", &p.x);scanf("%d", &p.y);printf("%d, %d\n", p.x, p.y);
}
void output(struct point p) {printf("%d, %d\n", p.x, p.y);
}
方案二
#include <stdio.h>struct point {int x;int y;
};struct point getStruct(void);
void output(struct point);int main(int argc, char const* argv[]) {struct point y = { 0,0 };y = getStruct();output(y);
}struct point getStruct(void) {struct point p;scanf("%d", &p.x);scanf("%d", &p.y);printf("%d, %d\n", p.x, p.y);return p;
}
void output(struct point p) {printf("%d, %d\n", p.x, p.y);
}
- ->運算符
#include <stdio.h>struct date {int month;int day;int year;
}myday;int main(void) {struct date* p = &myday;(*p).month = 12;p->month = 12;printf("%i\n", (*p).month);printf("%i\n", p->month);return 0;
}
- 修改后
#include <stdio.h>struct point {int x;int y;
};struct point* getStruct(struct point* p);
void output(struct point);
void print(const struct point* p);int main(int argc, char const* argv[]) {struct point y = { 0,0 };getStruct(&y);output(y);output(*getStruct(&y));print(getStruct(&y));*getStruct(&y) = (struct point){ 1,2 };
}struct point* getStruct(struct point* p) {scanf("%d", &p->x);scanf("%d", &p->y);printf("%d, %d\n", p->x, p->y);return p;
}
void output(struct point p) {printf("%d, %d\n", p.x, p.y);
}
void print(const struct point* p) {printf("%d, %d\n", p->x, p->y);
}
11.4. 結(jié)構(gòu)中的結(jié)構(gòu)
- 沒聽懂
- 結(jié)構(gòu)數(shù)組:
struct date dates[100]; struct date dates[] = {{4,5,2005}, {2,4,2005} }
- 結(jié)構(gòu)中的結(jié)構(gòu):
struct dateAndTime{struct date sdate;struct time stime;};
#include <stdio.h>struct time {int hour;int minutes;int seconds;
};struct time timeUpdate(struct time now);int main(void) {struct time testTimes[5] = {{11,59,59}, {12,0,0},{1,29,59},{23,59,59},{19,12,27}};return 0;
}
struct time timeUpdate(struct time now) {}
11.5. 類型定義
-
自定義數(shù)據(jù)類型(typedef):
-
C語言提供了一個typedef的功能來聲明一個已有的數(shù)據(jù)類型的新名字, 改善了程序的可讀性, 比如:
- typedef int Length;
- 使得Length成為int類型的別名
-
這樣, Length這個名字就可以代替int出現(xiàn)在變量定義和參數(shù)聲明的地方了:
- Length a,b,len;
- Length numbers[10]; //但是這樣感覺比原來還復雜, 所以typedef就用在定義結(jié)構(gòu)的別名時使用就可以
-
typedef struct {int month;int day;int year;} mydate; //這里是沒有名字的struct, mydate是struct的別名
#include <stdio.h>typedef struct date {int month;int day;int year;
} mydate; //在typedef和最后的單詞中間的東西都是原來的, 最后的單詞mydate是struct date的別名int main(int argc, char const* argv[]) {typedef int Length;Length a, b, len;Length numbers[10];mydate d = { 9, 1, 2005 };return 0;
}
11.6. 聯(lián)合
-
聯(lián)合(union):
union AnEit {int i;char c;} elt1, elt2;
-
這個結(jié)構(gòu)中有兩個成員i和c, 對于是struct, i和c的值是分開的, 隨時都可以使用其中的 任何一個, 而對于union, i和c是聯(lián)合的, 它們都占據(jù)了相同的內(nèi)存空間
-
聯(lián)合: 所有的成員共享一個空間, 同一時間只有一個成員是有效的, union的大小是其最大的成員
-
-
union的用處:
- 通過這個方法可以得到一個int或者double或者其它類型的內(nèi)部的各個字節(jié)
#include <stdio.h>union AnEit {int i;char c;
} elt1, elt2;int main(int argc, char const* argv[]) {elt1.i = 4;elt2.c = 'a';elt2.i = 0xDEADBEEF;return 0;
}
- union的用處:
#include <stdio.h>typedef union {int i;char ch[sizeof(int)];
} CHI;int main(void) {CHI chi;int i;chi.i = 1234; //0x04D2for (i = 0; i < sizeof(int); i++) {printf("%02hhX", chi.ch[i]); //小端:000004D2 大端:D2040000}printf("\n");return 0;
}
11.7. PAT
-
11-0. 平面向量加法(10)
-
疑問:
-
如果處理這個功能: 不能輸出-0.0
-
fabs()函數(shù):
- 返回某一個值的絕對值
- #include <math.h>
-
-
本題要求編寫程序,計算兩個二維平面向量的和向量。
-
輸入格式:
輸入在一行中按照“x1 y1 x2 y2”的格式給出兩個二維平面向量V1=(x1, y1)和V2=(x2, y2)的分量。 -
輸出格式:
在一行中按照“(x, y)”的格式輸出和向量,坐標輸出小數(shù)點后1位(注意不能輸出-0.0)。 -
輸入樣例:
3.5 -2.7 -13.9 8.7 -
輸出樣例:
(-10.4, 6.0)
-
-
看著答案完成的處理-0.0功能
#include <stdio.h>
#include <math.h>//聲明結(jié)構(gòu)類型
struct xiangLiang {double x;double y;
} xY, Xy; //定義結(jié)構(gòu)變量int main() {//引用結(jié)構(gòu)成員進行輸入scanf("%lf %lf %lf %lf", &xY.x, &xY.y, &Xy.x, &Xy.y);//結(jié)果變量double resultX = xY.x + Xy.x;double resultY = xY.y + Xy.y;//判斷-0.0的情況if (fabs(resultX) < 0.05) {resultX = fabs(resultX);}if (fabs(resultY) < 0.05) {resultY = fabs(resultY);}printf("(%.1f, %.1f)\n", resultX, resultY);//求和并輸出//printf("(%.1f, %.1f)\n", xY.x + Xy.x, xY.y + Xy.y);return 0;
}
- 答案
答案
#include <stdio.h>
#include <math.h>
#define EPSILON 0.05struct Vector {double x;double y;
};int main(void)
{struct Vector v1, v2, v3;scanf("%lf %lf %lf %lf", &v1.x, &v1.y, &v2.x, &v2.y);v3.x = v1.x + v2.x;v3.y = v1.y + v2.y;if(fabs(v3.x) < EPSILON)v3.x = fabs(v3.x);if(fabs(v3.y) < EPSILON)v3.y = fabs(v3.y);printf("(%.1f, %.1f)\n", v3.x, v3.y);return 0;
}
-
11-1. 通訊錄的錄入與顯示(10)
-
疑問:
-
如何查詢記錄編號?
-
已解決, 通過結(jié)構(gòu)數(shù)組的方式將輸入的結(jié)構(gòu)成員信息和輸入的記錄編號存放起來, 遍歷數(shù)組, 使用下標和.訪問數(shù)組和結(jié)構(gòu)中的單元和成員, 打印輸出
-
-
通訊錄中的一條記錄包含下述基本信息:朋友的姓名、出生日期、性別、固定電話號碼、移動電話號碼。本題要求編寫程序,錄入N條記錄,并且根據(jù)要求顯示任意某條記錄。
-
輸入格式:
輸入在第1行給出正整數(shù)N(<=10);隨后N行,每行按照格式“姓名 生日 性別 固話 手機”給出一條記錄。其中“姓名”是不超過10個字符、不包含空格的非空字符串;生日按“yyyy/mm/dd”的格式給出年月日;性別用“M”表示“男”、“F”表示“女”;“固話”和“手機”均為不超過15位的連續(xù)數(shù)字,前面有可能出現(xiàn)“+”。
在通訊錄記錄輸入完成后,最后一行給出正整數(shù)K,并且隨后給出K個整數(shù),表示要查詢的記錄編號(從0到N-1順序編號)。數(shù)字間以空格分隔。 -
輸出格式:
對每一條要查詢的記錄編號,在一行中按照“姓名 固話 手機 性別 生日”的格式輸出該記錄。若要查詢的記錄不存在,則輸出“Not Found”。 -
輸入樣例:
3
Chris 1984/03/10 F +86181779452 13707010007
LaoLao 1967/11/30 F 057187951100 +8618618623333
QiaoLin 1980/01/01 M 84172333 10086
2 1 7 -
輸出樣例:
LaoLao 057187951100 +8618618623333 F 1967/11/30
Not Found
-
-
看著答案寫的
#include <stdio.h>struct tongXunLu {//朋友的姓名、出生日期、性別、固定電話號碼、移動電話號碼char name[10];struct birthday {int year;int month;int day;} date;char sex;char guHua[15];char phone[15];
};int main(int argc, char const* argv[]) {//定義結(jié)構(gòu)變量struct tongXunLu inf[10];//輸入nint n;scanf("%d", &n);//循環(huán)輸入n次int i;for (i = 0; i < n; i++) {//輸入信息scanf("%s %i/%i/%i %c %s %s", &inf[i].name, &inf[i].date.year, &inf[i].date.month, &inf[i].date.day, &inf[i].sex, &inf[i].guHua, &inf[i].phone);}//輸入kint k;scanf("%d", &k);//輸入k個整數(shù)//num[i]表示查詢的記錄編號int num[10];for (i = 0; i < k; i++) {scanf("%d", &num[i]);}for (i = 0; i < k; i++) {if (num[i] >= 0 && num[i] < n) {//姓名 固話 手機 性別 生日printf("%s %s %s %c %i/%i/%i\n", inf[num[i]].name, inf[num[i]].guHua, inf[num[i]].phone, inf[num[i]].sex, inf[num[i]].date.year, inf[num[i]].date.month, inf[num[i]].date.day);}else {printf("Not Found\n");}}return 0;
}
- 答案
#include <stdio.h>
#define N 10struct Person {char name[11];char birthday[11];char sex;char fixed[17];char mobile[17];
};int main(void){struct Person p[N];int num[N];int i, n, k;scanf("%d", &n);for (i = 0; i < n; ++i){scanf("%s %s %c %s %s", &p[i].name, &p[i].birthday,&p[i].sex, &p[i].fixed, &p[i].mobile);}scanf("%d", &k);for (i = 0; i < k; ++i) {scanf("%d", &num[i]);}for(i = 0; i < k; ++i) {if (num[i] >= 0 && num[i] < n) {printf("%s %s %s %c %s\n", p[num[i]].name, p[num[i]].fixed, p[num[i]].mobile, p[num[i]].sex, p[num[i]].birthday);}else {printf("Not Found\n");}}return 0;
}