指針與結構體
簡介:我們可以使用C的結構體來表示數據結構元素,比如鏈表或樹的節點,指針是把這些元素聯系到一起的紐帶。
typedef struct _person{
char* firstName;
char* lastName;
char* title;
unsigned int age;
} Person;
/*用點表示法初始化*/
Person person;
person.firstName=(char*)malloc(strlen("Emily")+1);
stcpy(person.firstName,"Emily");
person.age=23;
/*****結構體指針初始化*/
Person *ptrperson;
ptrperson=(Person*)malloc(sizeof(Person));
ptrperson->firstName=(char*)malloc(strlen("Emily")+1);
strcpy(ptrperson->firstName,"Emily");
ptrperson->age=23; // (*ptrperson).age = 23;
為結構體分配內存,分配的內存大小至少是各個字段的長度之和。不過,實際長度會大於這個和,結構體的各字段之間可能會有填充。結構體數組各元素之間會有填充。
結構體釋放問題:


用結構體變量和指向結構體的指針函數參數
1.用結構體變量的成員作參數。(用法和普通變量相同)
2.用結構體變量作實參。形參也必須是同類型的結構體變量。調用期間形參也要占用內存。(空間和時間上開銷較大),較少使用該方法。
3.用指向結構體變量(或數組)的指針作實參,將結構體變量(數組)的地址傳給形參。
用指針處理鏈表
鏈表是一種動態地進行存儲分配的一種數據結構。 鏈表是C語言編程中常用的數據結構,比如我們要建一個整數鏈表,一般可能這麼定義:
struct int_node {
int val;
struct int_node *next;
};
假設有五個學生某一門功課的成績分別為A、B、C、D和E,這五個數據在內存中的存儲單元地址分別為1248、1488、1366、1022和1520,其鏈表結構如圖所示。

鏈表有一個“頭指針”變量,圖中以 head表示,它存放一個地址,該地址指向鏈表中第一個結點,第一個結點又指向第二個結點……直到最後一個結點。該結點不再指向其他結點,它稱為“表尾”,它的地址部分存放一個“NULL”(表示“空地址”),鏈表到此結束。鏈表中每個結點都包括兩個部分:用戶需要用的實際數據和下一個結點的地址。
鏈表每個結點中只有一個指向後繼結點的指針,該鏈表稱為單鏈表。其實結點中可以有不止一個用於鏈接其他結點的指針。如果每個結點中有兩個用於鏈接其他結點的指針,一個指向前趨結點(稱前趨指針),另一個指向後繼結點(稱後繼指針),則構成雙向鏈表。雙向鏈表如圖所示。

/*單鏈表的例子(靜態鏈表:因為所有節點在程序中定義的,不是臨時開辟的,也不能用完後釋放)*/
#include<stdio.h>
//#define NULL 0
struct student
{
int num;
int score;
struct student *Next;
};
int main()
{
struct student a,b,*head,*p;
a.num=10012; a.score=99;
b.num=10013; b.score=81;
head=&a;
a.Next=&b;
b.Next=NULL;
p=head;
do
{
printf("%5d %ld\n",p->num,p->score);
p=p->Next;
}while(p!=NULL);
}
問題:結構體的變量名可以當做地址賦給指針嗎?沒有頭指針head行不行?p起了什麼作用?沒它可以嗎?
處理動態鏈表用到的函數 calloc/malloc/free
malloc函數原型: void *malloc(unsigned int size);其作用是在內存的動態存儲區分配一個長度為size的連續空間。此函數的值(返回值)是一個分配域的起始地址(void類型);若函數未成功執行,則返回空指針(NULL)。
calloc函數原型: void *calloc(unsigned n,unsigned size);其作用是在內存的動態存儲區分配n個長度為size的連續空間。函數返回一個指向分配域起始位置的指針;否則,返回NULL。
free 函數原型: void free(void *p);釋放由p指向的動態存儲區。free無返回值。
建立動態鏈表(知難而進)
/*寫一函數建立一個有3名學生數據的單向動態鏈表*/
#include<stdio.h>
#include<malloc.h>
//#define NULL 0
#define LEN sizeof(struct student)
struct student
{
long num;
float score;
struct student *next;
};
int n;
struct student *creat(void)
{
struct student *head;
struct student *p1,*p2;
n=0;
p1=p2=(struct student*)malloc(LEN);
scanf("%ld,%f",&p1->num,&p1->score);
head=NULL;
while(p1->num!=0)
{
n=n+1;
if(n==1) head=p1;
else
p2->next=p1;
p2=p1;
p1=(struct student*)malloc(LEN);
scanf("%ld,%f",&p1->num,&p1->score);
}
p2->next=NULL;
return(head);
}
int main()
{
creat();
}
建立鏈表首先要定義一個包含數據域和指針域的的結構類型,然後建立指向表頭節點的頭指針head,最後通過malloc函數動態申請一塊內存作為表頭節點。
typedef struct node
{
int data; /*信息*/
struct node *link; /*指針*/
}NODE; /*定義節點*/
NODE *head; /*定義頭指針head */
定義結構類型和頭節點之後,我們要建立不包含數據的表頭節點,可以按下列語句進行操作。
NODE *p; /*說明一個指向節點的指針變量p */ p=(NODE*) malloc(sizeof(NODE)); /*申請表頭節點*/ p->link = NULL; /*將表頭節點的link置為NULL */ head=p; /*head指向表頭節點p*/
由於此時鏈表中只有一個表頭節點,沒有數據節點,所以稱為空鏈表。
p=(NODE*) malloc(sizeof(NODE)); /*申請一個數據節點*/ 為了在鏈表中保存數據,可以從表頭位置將數據節點插入到鏈表中,例如,插入一個數據節點:
p=(NODE*) malloc(sizeof(NODE)); /*申請一個數據節點*/ gets(p ->data); /*輸入一個新的數據*/ p->link=head->link; /*建立鏈接關系。將表頭節點的link存入p 的link中*/ head->link=p; /*將數據節點插在表頭節點之後成為第一個數據節點*/
插入第一個數據節點後鏈表,然後繼續插入下一個數據節點。
create(NODE *head,int n) 根據上面的鏈表建立過程,可以寫出函數create建立有n個數據節點的鏈表。
create(NODE *head,int n)
{
NODE *p;
for(; n>0;n--)
{
p=(NODE*) malloc(sizeof(NODE));
if(p==NULL)
exit(0);
gets(p->data);
p->link = head->link;
head->link = p;
}
}