利用結構,可以結合一些彼此相關的變數,並定義成新的變數類型。 以下是一個簡單的範例:

#include <stdio.h>
#include <string.h>

struct Human{
	char name[100];
	int age;
};

int main()
{
	struct Human A;

	strcpy(A.name, "John");
	A.age = 20;

	printf("A's name: %s\n", A.name);
	printf("A's age : %d\n", A.age);
	return 0;
}
上述範例中,「Human」稱為結構標籤,即為結構定義的名稱。大括號包住的變數,稱為結構的成員。 同一個結構定義內,成員的名稱不能一樣,但是不同的結構定義之間,則名稱可以相同,不會衝突。 成員可以是基本的資料型別,也可以是其它的結構變數。

要在宣告時同時給結構指定初始值,則需用一個大括號包住,裡面依照宣告成員的順序放入初始值,用逗號隔開。

「.」則是用於存取結構的成員。

能對結構進行的運算,只有:


結構無法用「==」或「!=」之類的運算子來進行比較。以下示範指派運算:
#include <stdio.h>
#include <string.h>

struct Human{
	char name[100];
	int age;
};

int main()
{
	struct Human A;
	struct Human B;

	strcpy(A.name, "John");
	A.age = 20;

	B = A;

	strcpy(A.name,"Mary");
	A.age = 18;

	printf("A's name: %s\n", A.name);
	printf("A's age : %d\n", A.age);

	printf("B's name: %s\n", B.name);
	printf("B's age : %d\n", B.age);
	return 0;
}

結構變數如同一般變數,將它傳進函式當中並做改變時,不會影響呼叫端的值:

#include <stdio.h>
#include <string.h>

struct Human{
	char name[100];
	int age;
};

void test(struct Human A){
	strcpy(A.name,"Mary");
	A.age = 18;
	printf("(in test) A's name: %s\n", A.name);
	printf("(in test) A's age : %d\n\n", A.age);
}

int main()
{
	struct Human A;

	strcpy(A.name, "John");
	A.age = 20;

	printf("(in main) A's name: %s\n", A.name);
	printf("(in main) A's age : %d\n\n", A.age);

	test(A);

	printf("(in main) A's name: %s\n", A.name);
	printf("(in main) A's age : %d\n\n", A.age);

	return 0;
}

但是如果將結構組合成陣列,則值會被改變:

#include <stdio.h>
#include <string.h>

struct Human{
	char name[100];
	int age;
};

void test(struct Human A[]){
	strcpy(A[0].name,"Tom");
	A[0].age = 18;

	printf("(in test) A[0]'s name: %s\n", A[0].name);
	printf("(in test) A[0]'s age : %d\n\n", A[0].age);
}

int main()
{
	struct Human people[5];

	strcpy(people[0].name,"Mary");
	people[0].age = 15;

	printf("(in main) people[0]'s name: %s\n", people[0].name);
	printf("(in main) people[0]'s age : %d\n\n", people[0].age);

	test(people);

	printf("(in main) people[0]'s name: %s\n", people[0].name);
	printf("(in main) people[0]'s age : %d\n\n", people[0].age);

	return 0;
}

前面提過,可以利用「.」來取得結構成員。但如果是指向結構的指標,要取其成員時,必須使用「->」:

#include <stdio.h>
#include <string.h>

struct Human{
	char name[100];
	int age;
};

int main()
{
	struct Human A, *B;

	strcpy(A.name, "John");
	A.age = 20;

	B = &A;

	printf("A's name: %s\n", A.name);
	printf("A's age : %d\n", A.age);
	printf("B's name: %s\n", B->name);
	printf("B's age : %d\n\n", B->age);

	strcpy(B->name,"Mary");
	B->age = 19;

	printf("A's name: %s\n", A.name);
	printf("A's age : %d\n", A.age);
	printf("B's name: %s\n", B->name);
	printf("B's age : %d\n", B->age);
	
	return 0;
}

一個結構不能包含它自己,但是可以包含指向自己類型的指標。 如果加上動態記憶體配置,則我們可以把一堆結構串連起來,稱為鏈結串列(linked list)。 「malloc」函式可以幫你取得一塊記憶體空間,傳入的參數是空間大小(以Bytes為單位),傳出的參數是指向那塊空間的指標。 程式結束之前,要將空間歸還給系統,這時候必須利用「free」函式,把指向要歸還的空間指標傳進去,就可以將空間釋放出來。

#include <stdio.h>
#include <stdlib.h>

struct Human{
	int value;
	struct Human *hPtr;
};

int main()
{
	struct Human *startPtr, *currPtr;
	int i = 1;

	/* set initial value */
	startPtr = NULL;
	currPtr = NULL;

	 for ( i = 0 ; i < 4 ; i ++ ){
		/* create space */
		if ( startPtr == NULL ){
			startPtr = (struct Human *) malloc( sizeof( struct Human ) );
			currPtr = startPtr ;
		}
		else {
			currPtr->hPtr = (struct Human *) malloc( sizeof( struct Human ) );
			currPtr = currPtr->hPtr;
		}
		currPtr -> value = i;
		currPtr -> hPtr = NULL;
	}

	/* print out */
	currPtr = startPtr;
	while(currPtr != NULL){
		printf("%d\n", currPtr->value );
		currPtr = currPtr->hPtr;
	}

	/* free */
	currPtr = startPtr;
	while(currPtr != NULL){
		currPtr = currPtr -> hPtr;
		free(startPtr);
		startPtr = currPtr ;
	}

	return 0;
}

如果在結構中,包含了兩個以上的,可以指向自己類型的指標,則可以串出更多花樣。 例如,一個結構有指標指向另外兩個結構時,可以串成一棵「二元樹」。 樹很適合用遞迴來描述,最上面的節點稱為「根」, 指向的左邊也是一顆小樹,稱為「左子樹」,指向右邊的稱為「右子樹」, 最末端沒有指向其它節點的節點,稱為「葉」。 樹狀結構的應用非常多,像是「二元搜尋樹」就可以把陣列轉換成樹, 其中遵守的原則是,左子樹的所有節點都比根小,右子樹的所有節點都比根大。

#include <stdio.h>
#include <stdlib.h>

struct Node{
	int value;
	struct Node *leftPtr;
	struct Node *rightPtr;
};

int treeSearch(struct Node *rootPtr, int key){
	while(rootPtr!=NULL){
		if( key > rootPtr->value ){
			rootPtr = rootPtr->rightPtr;
		}
		else if( key == rootPtr->value ){
			return 1;
		}
		else if( key < rootPtr->value ){
			rootPtr = rootPtr->leftPtr;
		}
	}
	return 0;
}

void freeTree(struct Node *ptr){
	if(ptr!=NULL){
		freeTree( ptr->leftPtr );
		freeTree( ptr->rightPtr );
		free(ptr);
	}
}

int main()
{
	int a[] = {7, 9, 4, 3, 6, 13, 8, 17, 5, 12}; /* size: 10 */
	int i, key;
	struct Node *rootPtr, *currPtr, *nextPtr;

	/* set initial value */
	rootPtr = NULL;
	currPtr = NULL;
	nextPtr = NULL;

	/* create space */
	for ( i = 0 ; i < 10 ; i ++ ){
		key = a[i];
		if ( rootPtr == NULL ){
			rootPtr = (struct Node *) malloc( sizeof( struct Node ) );
			currPtr = rootPtr;
			rootPtr->value = key;
			rootPtr->leftPtr  = NULL; /* ATTENTION!! */
			rootPtr->rightPtr = NULL; /* ATTENTION!! */
		}
		else {
			currPtr = rootPtr;
			nextPtr = currPtr;
			while(nextPtr!=NULL){
				currPtr = nextPtr;
				if( key > currPtr->value ){
					nextPtr = currPtr -> rightPtr;
					if(nextPtr==NULL){
						nextPtr = (struct Node *) malloc( sizeof( struct Node ) );
						nextPtr->value = key;
						nextPtr->leftPtr  = NULL; /* ATTENTION!! */
						nextPtr->rightPtr = NULL; /* ATTENTION!! */
						currPtr->rightPtr = nextPtr;
						break;
					}
				}
				else {
					nextPtr = currPtr -> leftPtr;
					if(nextPtr==NULL){
						nextPtr = (struct Node *) malloc( sizeof( struct Node ) );
						nextPtr->value = key;
						nextPtr->leftPtr  = NULL; /* ATTENTION!! */
						nextPtr->rightPtr = NULL; /* ATTENTION!! */
						currPtr->leftPtr = nextPtr;
						break;
					}
				}
			}
		}
	}/* end create space */


	/* search */
	printf("Is %d in the tree? Ans: %d\n", 10, treeSearch(rootPtr, 10) );
	printf("Is %d in the tree? Ans: %d\n", 17, treeSearch(rootPtr, 17) );

	/* free */
	freeTree(rootPtr);

	return 0;
}