?? ex12.cpp
字號:
///// 第12章 結 構 與 聯 合
//// [例12.1]結構變量的內存與邊界對齊效應
#include<stdio.h>
void main (void)
{ struct S { char c; int k; } s ;
struct A { char c[9]; double d; } a ;
struct B { char *c[9]; double* d; } b;
struct C { char c[8]; double d; } c ;
printf("%d,%d, %d,%d \t",sizeof(S),sizeof(a) ,sizeof(B),sizeof(c));
} //輸出:8 ,24,40,16
//// [例12.2] 字符指針成員和字符數組成員
# include<stdio.h>
typedef struct data_s { int n; char *s; } SData;
typedef struct data_a { int n; char a[12]; } AData;
void main(void)
{ SData d[]={1,"For",2,"Before",3,"And",4,"Anyone"};
AData c[]={5,"for",6,"before",7,"and",8,"anyone"};
const int n=sizeof(d)/sizeof(d[0]);
d[1].s=c[3].a;// d[1].s是char *型的左值,c[3].a是char *型的右值
d[1].s[1]='N';//當SData的指針成員s指向左值內存區時可以對其更新
//d[0].s[1]='O';// 當SData的指針成員s指向只讀內存區時不應對其更新
SData*p=d;//定義結構指針p,以優化輸出的尋址計算,p初值等于d
int k ;for(k=0;k<n;k++,p++) printf("{%p,%s} ",d[k].s,p->s);
printf("\n");
for( k=0;k<n;k++) printf("{%p,%s} ",(*(c+k)).a,(c+k)->a); printf("\n");
AData *q=c; //定義結構指針q,優化輸出的尋址計算,q初值等于c
for(p=d,k=0;k<n;k++,p++,q++) printf("[%d,%d] ",p->n,q->n);
}//輸出結果:
//////////[例12.3]求數組和的函數double sum(double* ,int )求結構成員數組的和
# include<stdio.h>
typedef struct SType { int v; double a[6]; } S, * PS;
double sum(double* q,int n)
{
double s=0;
for(double*p=q;p<q+n;p++) s+=*p; return s;
}
void main()
{ S a[2]={4,{1,2,3,4},5,{1,2,3,4,5}}; //結構成員數組的截斷賦值
for(PS s=a;s<a+2;s++) printf("%2.0f ",sum(s->a,s->v)); //輸出結果:10 15
}
////[例12.4]數值形參a,引用形參r和指針形參p對實參結構變量的影響
# include<stdio.h>
typedef struct Sa { int x; } A;
void f(A a,A& r,A* p){ a.x += 1; r.x += 2; p->x += 3; }
void main()
{ A a[3]={1,2,3}; //結構數組的初始賦值
f(a[0],a[1],a+2);
printf("%d,%d,%d",a[0].x, a[1].x, a[2].x); //輸出結果:1,4,6
}
//[例12.5] 數值形參v和引用形參u求點積的函數double DotProduct( PT& u, PT v)
# include <stdio.h>
# include <stdio.h>
typedef struct point_t { double x,y,z;} PT;
double DotProduct( PT& u, PT v) { return u.x*v.x+u.y*v.y+u.z*v.z;}
double Dot(double p[3], double *q){return p[0]*q[0]+p[1]*q[1]+p[2]*q[2]; }
void main(void)
{ PT x={1,1,0},y={0,2,1},z={1,0,3};
PT a; a.y=Dot(&y.x,&z.x);
a.x=DotProduct(x,y); a.z=DotProduct(z,x);
printf("a={%1.0f,%1.0f,%1.0f}\t", a.x,a.y,a.z);
} //輸出:a={2,3,1}
/// [例12.6] 只讀指針形參double DotProduct(const point_t *, const point_t *)求點積
# include <stdio.h>
typedef struct { double v[3]; } point_t;
double DotProduct(const point_t *p, const point_t *q)
{ return p->v[0]*q->v[0]+p->v[1]*q->v[1]+p->v[2]*q->v[2]; }
double Dot(double *p, double q[3]){return p[0]*q[0]+p[1]*q[1]+p[2]*q[2]; }
void main(void)
{ point_t x={1,1,0}, y={0,2,1}, z={1,0,3};
point_t a={DotProduct(&x,&y),DotProduct(&y,&z),Dot(z.v,x.v)};
printf("a={%1.0f,%1.0f,%1.0f}\n", a.v[0],a.v[1],a.v[2]);
} //輸出:a={2,3,1}
/////////[例12.7]對結構不同成員的排序
# include<stdio.h>
#include<string.h>
typedef struct data_tag { int n; char *s;} SData;
void SelectSort(SData* a, int n) //選擇排序的優點在于變量的交換次數少
{ for(int i=0;i<n-1;i++)
{ int min=i; //設置最小元素下標初始值為i
for(int j=i+1;j<n;j++) //在無序區間中尋找最小值對應的下標min
if(strcmp(a[j].s,a[min].s)<0) min=j;
if(min!=i) { SData t=a[i];a[i]=a[min];a[min]=t; }
} //僅在min!=i即最小值在無序區才交換結構變量
}
void BubbleSort(SData a[],int n) //對結構數組排序
{ for(int i=1;i<n;i++) //外層循環i共循環n-1回
for(int j=0;j<n-i;j++) //從0~n-i進行內層循環
if (a[j].n>a[j+1].n)
{ SData t=a[j];a[j]=a[j+1];a[j+1]=t;}//交換結構變量
} //對結構數組排序算法的效率不及下面對結構指針數組的排序的效率高
void BubbleSort(SData *a[],int n) //對結構指針數組的排序
{ for(int i=1;i<n;i++)
for(int j=0;j<n-i;j++)
if (a[j]->n > a[j+1]->n)
{SData *t=a[j];a[j]=a[j+1];a[j+1]=t;} //交換指針數組元素的值
} //交換指針的值相當于交換int型變量的值
void main(void)
{ char * const ca[]={"For","Before","FOR","And","anyone"};
SData d[]={6,ca[0],4,ca[1],7,ca[2],5,ca[3],8,ca[4]};//定義結構數組d[5]
const int n=sizeof(d)/sizeof(d[0]); int k;
for(k=0;k<n;k++) printf("{%d,%s} ",d[k].n,d[k].s);//顯示原始數據
printf("\n1");BubbleSort(d,n); //1調用結構數組的冒泡排序算法
SData* p=d; //定義一級結構指針p,以優化輸出的尋址計算,p初值等于d
for(k=0; k<n;k++,p++) printf("{%d,%s} ",p->n,p->s); //顯示排序后的數據
printf("\n2");SelectSort(d,n); //2調用選擇法對字符串排序
for( k=0;k<n;k++) printf("{%d,%s} ",d[k].n,(d+k)->s); //顯示排序后的數據
SData* s[n]; //定義結構指針數組s[5],s[i]分別指向數組d的相應元素d[i]。
for( k=0;k<n;k++) s[k]=d+k;//相當于s[0]=&d[0], s[1]=&d[1], ..., s[n-1]=&d[n-1],
printf("\n3");BubbleSort(s,n); //3調用結構指針數組的冒泡排序算法
SData** pp=s;p=*pp; //定義二級結構指針pp,以優化輸出結構成員的尋址計算
for( k=0;k<n;k++,pp++,p=*pp) printf("{%d,%s} ",p->n,s[k]->s);
}
/// [例12.8] 指針形參輸出成員數據
#include<stdio.h>
typedef struct a_t { int x ; } A;
typedef struct b_t { int m; A a; } B;
typedef struct c_t { int n; B b; } C;
void show(const C* pc)
{ printf("c={%d,%d,%d}\t",pc->n,pc->b.m,pc->b.a.x);}
void main (void)
{ A a={1}; B b={3,4}; C c={6,7,8};
C *pc=&c;
pc->b = b; show(pc);
pc->b.a=a; show(&c);
} //輸出:c={6,3,4} c={6,3,1}
/// [例12.9]結構數組和鏈表
# include <stdio.h>
# include <memory.h>
typedef struct SList_tag
{ float data;
int elem;
struct SList_tag* pNext;
} SList;
void ShowL(SList* p) //顯示單鏈表結構數據的函數
{ while(p!=0) //要求鏈表中存在結束的0指針值
{ printf("p=%p{%3.1f,%d}, ",p,p->data,p->elem);//顯示當前結點的物理數據
p=p->pNext; //指向下一個結點
}
}
void ShowP(SList p[],int n)
{ for(int k=0;k<n;p++,k++)
printf("c[%d]{%3.1f,%d}, ",k,p->data,p->elem);
}
void ShowA(SList *p,int n)
{ for (int k=0;k<n;k++) printf("d[%d]{%3.1f,%d}, ",k,p[k].data,p[k].elem); }
static SList d[]={5.0,1,NULL, 4.0,2,NULL, 6.0,3,NULL}; //靜態結構數組定義
void main(void)
{ const int n=sizeof(d)/sizeof(SList); //n=3
SList c[n]; //局部結構數組定義
memcpy(c,d,sizeof(d)); //將結構數組d的元素賦值給c的元素
printf("show array d:"); ShowA(d,n); //顯示d[0],d[1],d[2]
printf("\nshow array c:"); ShowP(c,n); //顯示c[0],c[1],c[2]
int k; for( k=0;k<n-1;k++) //對結構數組元素d[k]的pNext賦值
d[k].pNext=&d[k+1]; //d[0].pNext=&d[1]; d[1].pNext=&d[2];
printf("\nshow List from d[0]:\n");
ShowL(d); //顯示d單鏈中的元素
for( k=n-1;k>0;k--) //對結構數組元素c[k]的pNext賦值
c[k].pNext=&c[k-1]; //c[2].pNext=&c[1]; c[1].pNext=&c[0];
printf("\nshow List from &c[n-1]:\n");
ShowL(&c[n-1]); //顯示c單鏈中的元素
}
////////////////[例12.10]先建立單鏈表然后賦值的算法
# include <stdio.h>
typedef struct SList_tag
{ float data; int elem;
struct SList_tag* pNext;
} SList;
void Show(SList* p){ for(;p;p=p->pNext) printf("{%1.0f,%d},",p->data,p->elem);}
SList* Create(int n) //建立擁有n個結點的單鏈表
{ SList* pThis=new SList(); //申請新的結點,pThis指向這個結點
SList* pHead=pThis; //建立表頭
SList* pPrev=pThis; // 定義pPrev保留當前的位置
for(int i=1;i<n;i++) //循環建立中間的單鏈表
{ pThis=new SList(); //申請新的結點,pThis指向這個結點
pPrev->pNext= pThis; //先前結點的pNext指向這個新的結點
pPrev=pThis; // pPrev保留新的結點位置,以便下次循環
}
pThis->pNext=0; //尾結點的pNex等于0
return pHead; //返回鏈結妥當的單鏈表的頭指針
}
inline void SetData(SList& d,const SList& s) //僅僅設置結點的數據項
{ d.data=s.data; d.elem=s.elem;}
SList* ListCpy(SList s[],int n) //將結構數組逆序拷貝給單鏈表
{ SList* pHead=Create(n); //建立單鏈表但數據項尚未賦值
SList* p=pHead;
int i=0; //s的初始值經由虛實結合得到
for(s+=n-1;i<n;i++) //s+=n-1表示向后偏移入口地址n-1個元素
{ SetData(*p,*s); //僅僅對單鏈表的數據項賦值操作
p=p->pNext; //向下遍歷鏈表
s--; //向前遍歷數組
} //重要概念:SetData(*p,*s)不能改為*p=*s這破壞單鏈表的連接關系
return pHead; //返回數據項已經賦值的單鏈表
}
void main(void)
{ static SList s[]={{5.0,1,0},{4.0,2,0},{6.0,3,0},{7.0,4,0},{8.0,5,0},{9.0,6,0}};
SList* pHead=ListCpy(s,6);
Show(pHead); // 輸出:{9,6},{8,5},{7,4},{6,3},{4,2}, {5,1},
}
//// [例12.11] 插入結點到已知鏈表中
# include <stdio.h>
typedef struct SList_tag
{ int elem; char data;
struct SList_tag* pNext;
} SList;
SList* Insert(SList*pHead,SList*pAdd)
{ const int key=pAdd->elem; //引入局部不變量使代碼略微清晰
if(pHead==NULL) //頭指針為空時的處理
{ pAdd->pNext = NULL; //插入點既是表頭又是表尾
return pAdd; //返回新的表頭即pAdd
}
if(key <= pHead->elem) //插入點在原頭結點之前, [pAdd]<= [pHead]<[...]<[Tail]
{ pAdd->pNext=pHead; //插入點變為新的表頭
return pAdd; //返回新的表頭即pAdd
}
SList*pFind=pHead; //pFind是一個探尋插入位置的指針,首先指向頭結點
SList*pPrev= pFind; // pPrev記住插入位置的當前結點,此時指向頭結點
while(pFind->elem<key && pFind->pNext!=0) //循環查找插入位置
{ /*要找的結點元素小于關鍵值同時后面尚有非0結點,進入循環*/
pPrev=pFind; // pPrev保留搜尋的當前位置
pFind=pFind->pNext; // pFind指針后移,即指向下一個結點
} //循環結束則找到插入位置,分兩種狀況
if(pFind->elem>=key) //跳出while循環,此時pFind ->elem>=key
{ pPrev->pNext=pAdd; //包含 pFind->pNext!=0或==0
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -