一、構造類型
基本概念:
(1)在C語言中,變量類型除了幾種基本類型之外,還有另外一些復雜類型,合稱為構造類型。
(2)構造類型:是由基本類型構造而成的(如數組、結構體、共同體、枚舉型)。
(3)構造類型的每一個分量是一個變量,它可以是一個簡單類型或者構造類型。
(4)構造類型的分量的使用方法與簡單變量相同
(5)構造類型的分量占用相鄰的存儲空間。
(6)對於構造類型的變量來說,重點是訪問其分量的方法。
二、數組
數組概念:按序排列的具有相同類型的變量的集合
(1)用一符號名(數組名)來表示這一組數
(2)用數組名后跟下標來唯一地確定數組中的元素
(3)數組的首地址、數組元素的類型和個數(數組長度)
1、一維數組
(1)一維數組的定義
定義方式: 數據類型 數組名[常量表達式]
【1】數組的命名規則和簡單變量名相同
【2】數組名后只能用方括弧括起來的常量表達式(常量和符號常量)
【3】常量表達式的值確定數組元素的個數(數組尺寸)
(2)一維數組的存儲
c編譯程序中用連續的內存單元存放 各個元素
保存數組所需內存量與數組元素的基本類型和數組大小有關
總字節數 = sizeof (基本類型) * 數組元素個數
(3)一維數組的引用
數組必須先定義,后引用
只能逐個引用數組元素,不能一次引用整個數組。
引用一維數組元素的一般形式: 數組名 [下標]
其中:下標可以是整型常量或整型表達式
int a[10]; printf(“%d”,a); //(錯誤) for(j=0;j<10;j++) printf(“%d\t”,a[j]); //(正確)

#include <stdio.h> void main() { int i,a[10]; for(i=0;i<=9;i++) a[i]=i; for(i=9;i>=0;i- -) printf(“%d”,a[i]); } //運行結果:9 8 7 6 5 4 3 2 1 0
(4)一維數組的初始化
【1】在定義數組時對數組元素賦初值

static int a[5]={1,2,3,4,5}; int a[5]={1,2,3,4,5}; //等價於:a[0]=1; a[1]=2; a[2]=3; a[3]=4; a[4]=5;
注:標准C只有靜態存儲(static)數組和外部存儲(extern)數組才能初始化,但Turbo C和Microsoft C的編譯系統中,中的數組與外部存儲數組均可以進行初始化。
【2】給一部分元素賦初值

int a[5]={6,2,3}; //等價於: a[0]=6; a[1]=2;a[2]=3; a[3]=0; a[4]=0;
注:對static數組不賦初值,系統會對所有數組元素自動賦以0值
【3】若對全部數組元素賦初值時,可以不指定數組長度

int a[]={1,2,3,4,5,6}; //自動定義數組長度為6
注意:編譯系統根據初值個數確定數組大小,若被定義數組長度與提供初值的個數不相同,則數組長度不能省略。
【4】數組元素值全部為0
int a[5]={0,0,0,0,0}; int a[5]={0};
(5)相關例題

#include <stdlib.h> #include <stdio.h> void main() { int a[5] = { 1, 2, 3, 4, 5 }; int b[5] = { 1, 2, 3 }; int c[] = { 1, 2, 3, 4, 5 }; static int d[5]; int e[5]; int i; for (i = 0; i < 5; i++) printf("%d", a[i]);printf("\n"); for (i = 0; i < 5; i++) printf("%d", b[i]);printf("\n"); for (i = 0; i < 5; i++) printf("%d", c[i]);printf("\n"); for (i = 0; i < 5; i++) printf("%d", d[i]);printf("\n"); for (i = 0; i < 5; i++) printf("%d", e[i]);printf("\n"); system("pause"); }

#include <stdlib.h> #include <stdio.h> void main() { int i; long int f1=1, f2=1; printf("%16ld%16ld", f1, f2); for (i = 2; i <= 0; i++) { f1 = f1 + f2; f2 = f2 + f1; printf("%16ld%16ld", f1, f2); if (i % 2 == 0) printf("\n"); } system("pause"); } //用數組方法 void main() { int i; static int f[20] = { 1, 1 }; for (i = 2; i <= 20; i++) f[i] = f[i - 2] + f[i - 1]; for (i = 0; i < 20; i++) { if (i % 4 == 0) printf("\n"); printf("%6d", f[i]); } system("pause"); }

#include <stdlib.h> #include <stdio.h> #define N 5 //簡單變量實現 void main() { int i, sum = 0, high = 0,score; float average; printf("input everyone's scbre.\n"); for (i = 0; i < N; i++) { scanf_s("%d", &score); sum += score; if (score>high) high = score; } average = (float)sum / N; printf("average=%f\n", average); printf("highest=%d\n", high); system("pause"); } //用數組實現 void main() { int i, sum = 0, high, score[N]; float average; printf("input everyone's scbre.\n"); for (i = 0; i < N; i++) scanf_s("%d", &score[i]); for (high = score[0], i = 0; i < N; i++) { sum += score[i]; if (score[i]>high) high = score[i]; } average = (float)sum / N; printf("average=%f\n", average); printf("highest=%d\n", high); system("pause"); }

#include <stdlib.h> #include <stdio.h> void main() { int x, n1=0, n2=0, n3=0, n4=0; printf("input number:"); scanf_s("%d",&x); while (x) { if (x == 1) n1 += 1; if (x == 2) n2 += 1; if (x == 3) n3 += 1; if (x == 4) n4 += 1; printf("input number:"); scanf_s("%d", &x); } printf("n1=%d n2=%d n3=%d n4=%d", n1, n2, n3, n4); system("pause"); } //用數組方法 void main() { static int x, n[9]; printf("input no.:"); scanf_s("%d", &x); while (x) { n[x] += 1; printf("input no.:"); scanf_s("%d", &x); } for (x = 1; x <= 8; x++) printf("\tno.%d= %d(票)\n", x, n[x]); if (x % 2 == 0) printf("\n"); system("pause"); }

#include <stdlib.h> #include <stdio.h> #define N 10 void main() { int a[N + 1]; int i, j, t; printf("input 10 numbers: "); for (i = 1; i <= N; i++) scanf_s("%d", &a[i]); printf("\n"); for (j = 1; j < N;j++) for (i = 1; i <= N-j;i++) if (a[i]>a[i + 1]) { t = a[i]; a[i] = a[i + 1]; a[i + 1] = t; } printf("the sorted numbers:\n"); for (i = 1; i <= N; i++) printf("%d ", a[i]); system("pause"); }
ps:起泡法的思路是:將相鄰兩個數比較,將小的調到前頭
1.要排序的數必須放入數組中
2.用二重循環控制排序過程
1)外循環j控制比較趟數(n-1趟)
2)內循環i控制一趟比較的次數(n-j次)
2、二維數組
在C語言中,數組的元素還可以是數組,這樣就構成二維數組,所以二維數組可以看成是“數組的數組”,依此類推,還可以構成三維數組,思維數組(稱多維數組)等等,二維數組是多維數組中最簡單,最常用的數組,它代表多維數組的基本特征。
(1)二維數組的定義
定義方式: 類型說明符 數組名[常量表達式][常量表達式]
int a[3][4],b[4][M]; //M是符號常量 //注意不能寫成下面情況 int a[3,4],b(4,M) //<--錯誤
概念上可理解二維數組a[3][4]是一個3行4列的矩陣
(2)二維數組的存儲
二維數組從概念上可理解為行-列矩陣,但存儲器是一維的,需按一定規則轉換,在內存中:二維數組中元素排列的順序是——按行存放。
數組元素的實際存放順序是右邊下標比左邊下標變化的快
(3)二維數組的引用
形式: 數組名[下標][下標]
注意:
【1】下標是整型或字符型的常量,變量或表達式。(定義時不能使用變量)如: a[1][2] a[i][j]
【2】數組元素可出現在表達式中,如: a[1][2]=a[2][2]/2
【3】使用數組元素時,應注意不要超出其定義的范圍,即要注意數組定義和數組元素引用的區別。
如: int a[2][3]; a[2][3]=5; -->a[0][0] a[0][1] a[0][2] a[1][0] a[1][1] a[1][2]
(4)二維數組的初始化
【1】按存放順序賦植
int x[2][3] = {1,2,3,4,5,6}; /*結果: x[0][0] =1 x[0][1] = 2 x[0][2] = 3 x[1][0] =4 x[1][1] = 5 x[1][2] = 6 */
【2】按行賦值
int x[2][3] = {{1,2,3},{4,5,6}}; /*結果: x[0][0] =1 x[0][1] = 2 x[0][2] = 3 x[1][0] =4 x[1][1] = 5 x[1][2] = 6 */
【3】部分賦值
static int x[2][3] = {1,2,4}; //以存放順序賦值 /*結果: x[0][0] =1 x[0][1] = 2 x[0][2] = 4 x[1][0] =0 x[1][1] = 0 x[1][2] = 0 */ static int x[2][3] = {{1,2},{4}}; //以行賦值 /*結果: x[0][0] =1 x[0][1] = 2 x[0][2] = 0 x[1][0] =4 x[1][1] = 0 x[1][2] = 0 */ static int x[2][3] = {{6,2},{5,0,6}}; //以行賦值 /*結果: x[0][0] =6 x[0][1] = 2 x[0][2] = 0 x[1][0] =5 x[1][1] = 0 x[1][2] = 6 */
【4】省略第一維長度
static int x[][3] = {1,2,3,4,5,6,7}; /*結果: x[0][0] =1 x[0][1] = 2 x[0][2] = 3 x[1][0] =4 x[1][1] = 5 x[1][2] = 6 x[2][0] =7 x[2][1] = 0 x[2][1] = 0 */
注:不能省略第二維的長度
(5)二維數組程序舉例
一般二維數組的處理用二重循環來實現,用循環變量的值控制數組元素的下標,外循環控制行,內循環控制列。

#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> void main1() { int a[3][3], i, j; for (i = 0; i <= 2; i++) for (j = 0; j <= 2; j++) scanf("%d", &a[i][j]); for (i = 0; i <= 2; i++) { for (j = 0; j <= 2; j++) printf("%5d", a[i][j]); printf("\n"); } system("pause"); } /* 1 2 3 4 5 6 7 8 9 */ void main2() { int a[3][3], i, j; for (i = 0; i <= 2; i++) for (j = 0; j <= 2; j++) scanf("%d", &a[j][i]); for (i = 0; i <= 2; i++) { for (j = 0; j <= 2; j++) printf("%5d", a[i][j]); printf("\n"); } system("pause"); } /* 1 4 7 2 5 8 3 6 9 */ void main3() { int a[3][3], i, j; for (i = 0; i <= 2; i++) for (j = 0; j <= 2; j++) scanf("%d", &a[i][j]); for (i = 0; i <= 2; i++) { for (j = 0; j <= 2; j++) if ((i+j)%2) //2 4 6 8 //if ((i+j)%2==0) //1 3 5 7 9 printf("%5d", a[i][j]); printf("\n"); } system("pause"); } void main4() { int a[3][3], i, j; for (i = 0; i <= 2; i++) for (j = 0; j <= 2; j++) scanf("%d", &a[i][j]); for (i = 0; i <= 2; i++) { printf("%5d", a[i][i]); //1 5 9 //printf("%5d", a[i][i]); //7 5 3 } system("pause"); } //下三角 void main5() { int a[3][3], i, j; for (i = 0; i <= 2; i++) for (j = 0; j <= 2; j++) scanf("%d", &a[i][j]); for (i = 0; i <= 2; i++) { for (j = 0; j <= i; j++) printf("%5d", a[i][j]); printf("\n"); } system("pause"); }

#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> void main() { static int a[2][3] = { { 1, 2, 3 }, { 4, 5, 6 } }; static int b[3][2], i, j; printf("array a:\n"); for (i = 0; i <= 1; i++) { for (j = 0; j <= 2; j++) { printf("%5d", a[i][j]); b[j][i] = a[i][j]; } printf("\n"); } printf("array b:\n"); for (i = 0; i <= 2; i++) { for (j = 0; j <= 1; j++) { printf("%5d", b[i][j]); } printf("\n"); } system("pause"); } /* //對於n*n的二維數組,可以在同一個數組進行矩陣轉置操作 #define N 3 void main() { static int a[N][N] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9} }; int i, j; printf("原矩陣:\n"); for (i = 0; i < N; i++) { for (j = 0; j < N; j++) { printf("%5d", a[i][j]); } printf("\n"); } //進行轉置操作 int t; for (i = 0; i < N; i++) for (j = 0; j < i; j++) { t = a[i][j]; a[i][j] = a[j][i]; a[j][i] = t; } printf("轉置后的矩陣:\n"); //打印轉置后的矩陣 for (i = 0; i < N; i++) { for (j = 0; j < N; j++) { printf("%5d", a[i][j]); } printf("\n"); } system("pause"); } //對稱於主對角線的元素進行兩兩交換 void main() { static int a[N][N] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } }; int i, j; printf("原矩陣:\n"); for (i = 0; i < N; i++) { for (j = 0; j < N; j++) { printf("%5d", a[i][j]); } printf("\n"); } //對稱於主對角線的元素進行兩兩交換 int t; for (i = 0; i < N; i++) for (j = 0; j < i; j++) { if (i > j) { t = a[i][j]; a[i][j] = a[j][i]; a[j][i] = t; } } printf("轉置后的矩陣:\n"); //打印轉置后的矩陣 for (i = 0; i < N; i++) { for (j = 0; j < N; j++) { printf("%5d", a[i][j]); } printf("\n"); } system("pause"); } */
轉置的算法:
1.a數組初始化(或賦值)並輸出
2.用二重循環進行轉置
b[j][i]=a[i][j]
3.輸出b數組
3、字符數組
(1)字符數組的定義
在C語言中,沒有專門的字符串變量,而是將字符串存入字符數組來處理,即用一個一維數組來存放一個字符串,每個元素存放一個字符,字符數組是數組的一個特殊情況,它的定義方法與一般的數組類似,引用方法可以相同,但也有其獨特的引用方法。
形式: char 數組名[常量表達式] 一維字符數組:存放一個字符串(每個數組元素存放一個字符)
char 數組名[常量表達式][常量表達式] 二維字符數組:存放多個字符串(行數是字符串的個數)
常量表達式:整數、字符、符號常量
注:可以用整型數組存放字符型數據,但浪費存儲空間
(2)字符數組的初始化
【1】按元素賦值
static char c[10]={'s','t','o','r','e'}; //c[0] c[1] c[2] c[3] c[4] c[5] c[6] c[7] c[8] c[9]
注:
[1] static char c[10]; 則c[0]……c[9]初值均為‘\0’。 但若 char c[10]; 則c[0]……c[9]初值是未知的
[2] 在C語言中,將字符串作為字符數組來處理,即用一個一維數組來存放一個字符串。
[3] 為了測定實際字符串長度,C語言規定了一個“字符串結束標志”,即‘\0’。即遇到字符 ‘\0’時,表示字符串結束。
【2】使用字符串常量給字符數組賦初值
char c[6]={"china"}; char c[6]="china"; char c[]="china"; //結果 c[0] c[1] c[2] c[3] c[4] c[5]
注:以字符串方式賦值時,必須保證數組元素個數>=字符個數+1(字符串后面自動加上一個‘\0’)
數組初始化后,剩余的元素均為\0
數組未初始化,則static數組 元素的值為\0,否則元素值是隨機的

#define _CRT_CECRUE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> void main() { char a[7] = { 'a', 'p', 'p', 'l', 'e' }; char b[7] = { "apple" }; char c[7]; static char x[7]; int i; for (i = 0; i < 7; i++) printf("%5d %5d %5d %5d\n", a[i], b[i], c[i], x[i]); system("pause"); } /* 97 97 -52 0 112 112 -52 0 112 112 -52 0 108 108 -52 0 101 101 -52 0 0 0 -52 0 0 0 -52 0 */

#define _CRT_CECRUE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> void main() { char str[] = "This is a string!"; int i = 0; while (str[i] != '\0') { printf("%c=%d\n", str[i], str[i]); i++; } printf("%c=%d\n", str[i], str[i]); system("pause"); } /* T=84 h=104 i=105 s=115 =32 i=105 s=115 =32 a=97 =32 s=115 t=116 r=114 i=105 n=110 g=103 !=33 =0 */
注:[1] 用字符串給字符數組賦初值,系統自動加上空字符‘\0’(終結符)
[2] ‘ ’——空格字符,ASCII編碼值為32
[3] ‘\0’——空字符,ASCII編碼值為0
[4] 兩者均無法直接打印
(3)字符串的引用與輸入輸出
對於字符數組,在程序中既可以逐個引用字符串中的單個字符(數組元素),也可以一次引用整個字符串(數組)
【1】逐個字符數組元素輸入輸出:用%c格式符描述
scanf("%c",&a[i]); printf("%c%c%c",a[0],a[1],a[2]);
【2】整個字符串(數組)輸入輸出:用%s格式符描述
char a[]="china"; scanf("%s",a); printf("%s",a); //用%s輸出,無論數組元素有多少個只要遇到"\0"便結束。
char star[3][4]={{"*"},{"**"},{"***"}}; print("%s\n%s\n%s\n",star[0],star[1],star[2]); /*運行結果: * ** *** */ //%s要求的是地址:對一維數組,數組名就是地址,對二維數組,只寫行下標時是地址。
其它注意事項:
0_1>數組中有多個‘\0’時, 遇第一個結束
#include <stdio.h>
void main()
{
char a[ ]={'h','e','l','\0','l','o','\0'}; printf("%s",a); } //輸出:hel
0_2>scanf中%s輸入時,用字符數組名,不要加&,遇空格或回車結束,自動加‘\0’
輸入數據:how are you? char str1[5],str2[5],str3[5]; scanf("%s%s%s",str1,str2,str3); //注:用%s輸入時,遇空格或回車便認為一個字符結束 等價於《==》 char s[3][5]; scanf("%s%s%s",&s[0][1],&[1][0],&[2][0]); printf("%s\t%s\t%s\n",s[0],s[1],s[2]);
#include <stdio.h> void main() { char a[15],b[5],c[5]; scanf("%s%s%s",a,b,c); printf("a=%s\nb=%s\nc=%s\n",a,b,c); scanf("%s",a); printf("a=%s\n",a); } /* 運行情況: 輸入:How are you? 輸出:a=How b=are c=you? 輸入:How are you? 輸出:a=How */
三、字符串處理函數
1、gets(字符數組名)
從鍵盤輸入一個字符串(以回車結束)放到數組中,並且得到一個函數值,該函數值是字符數組的起始地址
如:get (str)
2、puts(字符數組名/字符串)
將數組中的字符串(以‘\0’結束的字符序列)輸出到終端上,輸完換行
puts (str); <=> printf("%s\n",str); puts("ok!"); <=> printf("%s\n","ok!"); <=> printf("ok!\n");
3、strcpy(字符數組1,字符串 / 字符數組2)
將字符串 / 字符數組2的字符串拷貝到字符數組1中
注:
(1)字符數組1的長度 >= 字符數組2(字符串)的長度
(2)拷貝時連同‘ \0 ’一起拷貝
(3)不能把字符串或字符數組直接賦給一個字符數組
char str[6]; str[0]='c'; str[1]='i'; strcpy(str,"china"); //用strcpy可以把一個數組賦給另一個數組
4、strcat(字符數組1,字符串/字符數組2)
將字符串或字符數組2,連接到字符串1的后面,並放在字符數組1中
main() { char str1[40],str2[10],str3[10]; gets(str1); gets(str2); gets(str3); strcat(str1,str2); strcat(str1,str3); printf(str1); }
注:數組1要足夠大
5、strcmp(字符數組1 / 字符串1,字符數組2 / 字符串2)
功能:比較兩個字符串,1>2->正數,1=2->0,1<2->負數
注意:對兩個字符串的比較,不能用以下形式(str1==str2或str1>str2或str1<str2)
只能用 strcmp(str1,str2) >0 或 ==0 或 <0來判斷

#define _CRT_CECRUE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <string.h> void main() { char s1[40], s2[40]; int i; printf("輸入字符串s1:"); gets(s1); printf("輸入字符串s2:"); gets(s2); i = strcmp(s1, s2); if (i == 0)printf("輸入的兩字符串相等。"); else if (i > 0)printf("輸入的字符串s1大於s2。"); else printf("輸入的字符串s1小於s2。"); system("pause"); }
# 字符串的拷貝、連接、比較都必須用函數
6、strlen(字符數組名 / 字符串)
測試字符串長度(不含 ‘ \0 ’)
strlen("china"); //值為5

#define _CRT_CECRUE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <string.h> void main() { char s[40]; int i; printf("enter a string!\n"); gets(s); i = strlen(s); printf("string length=%d\n",i); for (; i >= 0; i--) putchar(s[i]); system("pause"); } /* 輸入:abcdefg12345 輸出:string length=12 54321gfedcba */
7、strlwr(字符串)
將字符串中大寫字母轉換成小寫字母
8、strupr(字符串)
將字符串中小寫字母轉換成大寫字母
四、字符數組應用舉例

/*設:字符串用str【100】存放,單詞計數器位num 算法: 1、輸入字符串 2、找第一個非空字符串 3、記數 4、跳過本單詞,即尋找空格或 '\0' 5、未結束則轉 2 6、否則打印個數 */ #define _CRT_CECRUE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <string.h> void main() { int num = 0, i = 0; char str[100], c; gets(str); do { while ((c = str[i]) == ' ') i++; if (c != '\0') num++; while ((c = str[i]) != ' ' && c != '\0') i++; } while(c!='\0'); printf("number of word:%d\n", num); system("pause"); }

/* 算法: 1、輸入str1和str2 2、找到str1的結束標志\0 3、將str2的字符逐個放入str1當前位置開始的地方 */ #define _CRT_CECRUE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <string.h> void main() { int i = 0, j = 0; char str1[100], str2[100]; puts("輸入兩個字符串:"); gets(str1); gets(str2); while (str1[i] != '\0') i++; while ((str1[i++] = str2[j++]) != '\0') ; printf("結果為:%s\n", str1); system("pause"); } /* 輸入兩個字符串: ABC 12345 xyz 結果為:ABC 12345xyz */

#define _CRT_CECRUE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <string.h> #define NUM 10 void main() { int i, j; char name[NUM][10], stmp[10]; float score[NUM], tmp; printf("輸入姓名和成績:\n"); for (i = 0; i < NUM; i++) scanf("%s%f", name[i], &score[i]); for (i = 0; i < NUM-1;i++) for (j = i+1; j < NUM;j++) if (score[i] < score[j]) { tmp = score[i]; score[i] = score[j]; score[j] = tmp; strcpy(stmp, name[i]); strcpy(name[i], name[j]); strcpy(name[j], stmp); } printf("排序為:\n"); for (i = 0; i < NUM; i++) printf("%-10s%f\n", name[i], score[i]); system("pause"); }