gzip C#/.NET EnhancedSoapHttpClientProtocol.cs
一、結構的定義
結構是有struct關鍵字和結構模板以及結構中的成員組成:
struct names
{
int ma;
double line;
char file[30];
char sie;
};
在上面面的程式碼中,names叫做結構模板的名稱,整個所表示的就是結構模板,ma,line,file[30],sie叫做這個結構的成員。
二、宣告結構模板
1.宣告結構模板一般放在主函式的外部進行定義宣告,結構模板中的成員之間要用分號分隔開。
2.並且,在宣告結構模板的時候,每一個成員都不能進行初始化。
3.宣告結構模板不需要在模板名稱後面加等於號。
重點:
在結構模板中定義宣告字串的時候,用陣列形式,而不用字串形式,原因是陣列形式宣告的字串會儲存在結構變數所在的記憶體中,而用指標形式宣告的字串不會儲存在結構變數記憶體中,結構變數記憶體中儲存的只是字串的地址。
三、宣告結構變數
宣告結構變數的前提是要有結構模板,通過結構模板來進行結構變數的宣告。
#include <stdio.h>
struct names
{
int ma;
double line;
char file[30];
char sie;
};
int main(void)
{
struct names hold=
{
3,
2.3,
"I love Micy very much!",
'A',
};
}
在上面程式碼中,首先在主函式外面定義聲明瞭names結構模板,然後在主函式裡面定義聲明瞭以names為結構模板的結構變數hold,因此hold在進行初始化的時候要遵循names結構模板,並且每個成員之間用逗號隔開,這和定義宣告結構模板不相同。
由於結構變數也是變數,因此結構變數也遵循前面講的儲存方式。
宣告結構變數,要在結構變數後面加等於號。
四、初始化結構變數以及對結構變數賦值
初始化結構變數有三種方式:
1)對各成員都進行初始化
struct names
{
int ma;
double line;
char file[30];
char sie;
};
int main(void)
{
struct names hold=
{
3,
2.3,
"I love Micy very much!",
'A',
};
}
按照個成員之間的順序,分別對每個成員都進行初始化,並且初始化後個成員之間用逗號隔開。
2)用相同結構模板的結構變數進行初始化
struct names
{
int ma;
double line;
char file[30];
char sie;
};
int main(void)
{
struct names hold=
{
3,
2.3,
"I love Micy very much!",
'A',
};
struct names buge=hold;
此時,結構變數buge和結構變數hold的內容就完全一樣了。
3)指定初始化
//隨機
#include <stdio.h>
struct names
{
int ma;
double line;
char file[30];
char sie;
char games[20];
};
int main(void)
{
struct names hold=
{
.line=23.45,
.file="I love Micy very much!",
'S',
};
printf("print hold.line :%.2f\nprint hold.file :%s\n",hold.line,hold.file);
printf("print hold.sie :%c\nprint hold.ma :%d\n",hold.sie,hold.ma);
printf("print hold.games :%s\n",hold.games);
return 0;
}
列印結果:
print hold.line :23.45
print hold.file :I love Micy very much!
print hold.sie :S
print hold.ma :0
print hold.games :
在hold的初始化中,指定了line,file這兩個成員的初始化,(注意指定初始化要在指定的成員前面加上點運算子),因此在列印這兩個成員的值的時候,打印出來的就是初始化的值,而在初始化中有'A'這個值,這個值會被初始化給file成員後面的成員(按順序),未被初始化的成員會自動被初始化成0或者空字元。
4)對結構變數進行賦值
1.用相同結構模板的變數進行賦值
//用相同結構模板的結構變數進行賦值
#include <stdio.h>
struct names
{
int ma;
double games;
char datas[30];
};
int main(void)
{
struct names holds=
{
3,
4.3,
"I love Micy very much!",
};
struct names memb=holds;
printf("print ma in memb :%d\n",memb.ma);
printf("print games in memb :%.2f\n",memb.games);
printf("print datas in memb :%s\n",memb.datas);
return 0;
}
列印結果:
print ma in memb :3
print games in memb :4.30
print datas in memb :I love Micy very much!
2.用結構常量進行賦值
//使用結構常量進行賦值操作
#include <stdio.h>
struct names
{
int ma;
double games;
char datas[30];
};
int main(void)
{
struct names hold=(struct names){
3,
4.5,
"I love Micy very much!",
};
printf("print ma in hold :%d\n",hold.ma);
printf("print games in hold :%.2f\n",hold.games);
printf("print datas in hold :%s\n",hold.datas);
return 0;
}
列印結果:
print ma in hold :3
print games in hold :4.50
print datas in hold :I love Micy very much!
3.指定成員進行賦值
//指定結構成員進行賦值操作
#include <stdio.h>
struct names
{
int ma;
double games;
char datas[30];
};
int main(void)
{
struct names hold;
printf("enter ma in hold:\n");
scanf("%d",&hold.ma);
printf("print the ma in hold :%d\n",hold.ma);
printf("print the games in hold :%.2f",hold.games);
return 0;
}
列印結果:
enter ma in hold:
3
print the ma in hold :3
print the games in hold :0.00
可以發現,賦值操作和初始化有類似的地方,指定賦值之後,沒有值的成員就會初始化成0或者空字元,指定初始化也是如此。
五、訪問結構成員和指向結構變數的指標
1)指向結構變數的指標:
1.宣告結構模板,系統並不會為結構模板分配記憶體,也就是說不佔據記憶體。(由於結構模板相當於資料型別,因此使用sizeof()運算子能夠知道這個結構模板的大小),而宣告結構變數後,這個變數會佔據記憶體,這個記憶體的大小就是結構模板的大小,這塊記憶體是由各個成員的記憶體按順序組成的。(可以理解為各個成員都分配在結構變數這塊記憶體上)
2.由於這個變數擁有記憶體,也就擁有地址,因此可以宣告一個指標,去指向這塊記憶體(指標所儲存的一般都是這塊記憶體首位元組的地址)
如果要用指標指向他的成員,就用間接成員運算子->進行連線。
//隨機
#include <stdio.h>
struct names
{
int ma;
double line;
char file[30];
char sie;
char games[40];
};
int main(void)
{
struct names hold=
{
.line=23.45,
.file="I love Micy very much!",
'S',
"Love is a wonderful thing!",
};
struct names *ptst=&hold;
printf("print the hold.ma:%d\nprint the hold.line:%.2f\n",ptst->ma,ptst->line);
printf("print the hold.file:%s\nprint the hold.sie:%c\n",ptst->file,ptst->sie);
printf("print the hold.games:%s\n",ptst->games);
return 0;
}
列印結果:
print the hold.ma:0
print the hold.line:23.45
print the hold.file:I love Micy very much!
print the hold.sie:S
print the hold.games:Love is a wonderful thing!
*重點:
1.需要注意的是:ptst->ma代表的是變數名稱,即結構成員ma的名稱,變數名稱通過相應的轉換說明能直接打印出內容。
ptst->file代表的是陣列名稱(結構成員file[30]這個字串陣列的名稱),因此ptst->file表示的是陣列中首字元的地址,使用%s轉換說明能夠打印出整個字串。
2.hold是變數名稱,必須進行取地址操作才能夠賦值給ptst。
2)訪問結構成員
訪問結構有兩種方式,第一種是通過間接成員運算子->,這個運算子只能用在指標上面;第二種是通過點運算子,不能用在指標上面。
//
#include <stdio.h>
struct names
{
int ma;
char games;
double jir;
char dates[30];
};
int main(void)
{
struct names hold=
{
1,
'a',
2.3,
"I love yoga very much!",
};
struct names *ptstruct=&hold;
printf("print the members in the name of struct:\n");
printf("ma=%d\n",hold.ma);
printf("games=%c\n",hold.games);
printf("jir=%.1f\n",hold.jir);//上面這三個都表示的是結構中的變數。
printf("datas=%s\n\n",hold.dates);//在這裡hold.datas表示的是這個結構中陣列首元素的地址。
printf("print the members in point:\n");
printf("ma=%d\n",ptstruct->ma);
printf("games=%c\n",ptstruct->games);
printf("jir=%.1f\n",ptstruct->jir);
printf("datas=%s\n",ptstruct->dates);
return 0;
}
列印結果如下:
print the members in the name of struct:
ma=1
games=a
jir=2.3
datas=I love yoga very much!print the members in point:
ma=1
games=a
jir=2.3
datas=I love yoga very much!
1.使用結構變數名稱
使用結構變數名稱必須使用點運算子,訪問哪個成員,就在點後面加上哪個成員的名稱。如果是陣列名稱,代表的是陣列首元素的地址。
2.使用指向結構變數的指標
使用指向結構變數的指標必須使用間接成員運算子,訪問那個成員就在->後面加上哪個成員的名稱。如果是陣列名稱,代表陣列首元素的地址。
六、結構常量
對一個結構變數進行賦值操作的時候,可以將結構常量賦值給這個變數(避免另建立新的結構變數)
#include <stdio.h>
struct names
{
int ma;
double games;
char datas[30];
};
int main(void)
{
struct names hold;
hold=(struct names){
2,
3.4,
"I love Micy very much!",
};
printf("ma=%d\n",hold.ma);
printf("games=%.1f\n",hold.games);
printf("datas=%s\n",hold.datas);
return 0;
}
列印結果:
ma=2
games=3.4
datas=I love Micy very much!
結構常量的寫法:不需要設定出結構名稱,只需要把結構模板名稱加上括號即可,這樣可以避免再設定一個結構變數來進行賦值。
七、結構陣列
結構陣列就是多個擁有同一結構模板的變數組合。
//定義宣告結構陣列
#include <stdio.h>
struct names
{
int ma;
double games;
char datas[30];
};
int main(void)
{
struct names trains[5];
trains[0]=(struct names){
2,
3.4,
"I love Micy very much!",
};
printf("ma=%d\n",trains[0].ma);
printf("games=%.1f\n",trains[0].games);
printf("datas=%s\n",trains[0].datas);
return 0;
}
列印結果如下:
ma=2
games=3.4
datas=I love Micy very much!
在上面的程式碼中,聲明瞭一個具有names結構模板的結構陣列,這個陣列中擁有五個元素(結構變數),每個元素都是names的結構模板。
八、結構與函式之間聯絡方式
1)通過結構指標進行聯絡
把指標作為被調函式的形參,通過指標把原始結構的地址傳遞給被調函式。
//結構指標與被調函式
#include <stdio.h>
struct names
{
int ma;
double games;
char datas[30];
};
void sum_123(struct names *pts);//由於引數中使用了結構模板,所以要把結構模板的宣告放在上面,這是易出錯的地方。
void read_(struct names *pts);
int main(void)
{
struct names hold;
hold=(struct names){
2,
3.4,
"I love Micy very much!",
};
struct names *pts=&hold;
sum_123(pts);
read_(&hold);
return 0;
}
void sum_123(struct names *pts)//這裡表示的是隻能傳遞指向擁有names結構模板的變數的指標(或地址)
{
double sum=(pts->ma)+(double)(pts->games);
printf("print the sum is :%.2f\n",sum);
return;
}
void read_(struct names *pts)//可以傳遞結構變數指標,或者結構變數地址
{
printf("The characters is :%s\n",pts->datas);
return;
}
列印結果:
print the sum is :5.40
The characters is :I love Micy very much!
被調函式中的形參接受的是結構變數的指標或者結構變數的地址,這是呼叫原始資料。
2)通過結構變數(常量)進行聯絡
除了結構變數的指標或者地址能夠作為實際引數傳遞,結構變數本身(結構常量)也能夠作為實際引數進行傳遞。
//結構變數(結構常量)本身作為實際引數傳遞
#include <stdio.h>
struct names
{
int ma;
double games;
char datas[30];
};
void sum_(struct names data);
void read_(struct names data);
int main(void)
{
struct names hold=
{
2,
3.4,
"I love Micy very much!",
};
sum_(hold);
read_(hold);
return 0;
}
void sum_(struct names data)//這個引數表示接受一個以names為結構模板的結構變數作為實際引數
{
double sum=(double)data.ma+data.games;
printf("%.2f\n",sum);
return;
}
void read_(struct names data)
{
printf("%s\n",data.datas);
return;
}
列印結果如下:
5.40
I love Micy very much!
分析一下:指標作為實際引數進行傳遞的時候,被調函式通過這個地址直接訪問原始資料,而直接將結構變數本身作為實際引數的話,會複製一個副本傳遞給被調函式,被調函式無法修改原始結構變數(因為被調函式中接受的只是一個副本)。
3)直接將結構成員傳遞給被調函式
注意:這個結構成員不能是陣列,但可以是單一的資料型別,比如int、double、char或者指標或者陣列中的一個元素。
//傳遞結構成員
#include <stdio.h>
struct names
{
int ma;
double games;
char datas[30];
};
void sum_(int n);
void read_(double n);
void check_(char n);
int main(void)
{
struct names hold=
{
2,
3.4,
"I love Micy very much!",
};
sum_(hold.ma);
read_(hold.games);
check_(hold.datas[0]);
return 0;
}
void sum_(int n)
{
n++;
printf("print the value of the member :%d\n",n);
return;
}
void read_(double n)
{
n++;
printf("print the value of the member :%.2f\n",n);
return;
}
void check_(char n)
{
printf("print the value of the value :%c\n",n);
return;
}
列印結果:
print the value of the member :3
print the value of the member :4.40
print the value of the value :I
如果成員作為實際引數傳遞的話,被調函式的形參應該符合成員的相應資料型別,並且只能傳遞具有單個值的資料型別。
4)總結
1.單一的傳遞結構成員不常用到
2.一般不直接傳遞結構變數本身,因為這樣會建立副本,佔據記憶體。
3.一般採用傳遞指標的方法,因為指標訪問的是原始資料本身,如果不希望指標更改資料,最好加上const關鍵字,const直接放在struct關鍵字之前就好。
九、結構陣列與函式之間的聯絡方式
結構陣列與函式的聯絡方式和普通陣列與函式的聯絡相同,都是通過指標進行聯絡,同樣可以寫成陣列形式和指標形式(本質上都是指標)。
1)陣列形式
//結構陣列和字串之間的聯絡
#include <stdio.h>
#include <string.h>
#define SIZE 5
struct names
{
int ma;
double games;
char datas[30];
};
struct names hold[SIZE];//在這裡面,陣列名稱代表的就是陣列首元素的地址,也就是指向結構的指標。
void input_starray(struct names array[]);
void read_starray(struct names array[]);
int main(void)
{
input_starray(hold);
read_starray(hold);
return 0;
}
void input_starray(struct names array[])//以陣列形式呈現形參,這個形參表示的是接受指向names為模板的結構變數的指標。
{
for (int i=0;i<SIZE;i++)
{
puts("Please enter a int value :");
scanf("%d",&array[i].ma);
puts("Please enter a double value :");
scanf("%lf",&array[i].games)//需要注意的是,使用scanf()函式輸入double型別時,轉換說明使用%lf
getchar();
puts("Please enter a characters :");
fgets(array[i].datas,30,stdin);
{
int length=strlen(array[i].datas);
if (array[i].datas[length-1] == '\n')
{
array[i].datas[length-1] = '\0';
}
else
{
while (getchar() != '\n')
{
continue;
}
}
}
}
return;
}
void read_starray(struct names array[])
{
for (int i=0;i<SIZE;i++)
{
printf("\nThe %d group's value:\n",i+1);
printf("%d\n",array[i].ma);
printf("%.2f\n",array[i].games);
puts(array[i].datas);
}
return;
}
列印結果如下:
Please enter a int value :
1
Please enter a double value :
1.1
Please enter a characters :
qqq
Please enter a int value :
2
Please enter a double value :
2.2
Please enter a characters :
www
Please enter a int value :
3
Please enter a double value :
3.3
Please enter a characters :
eee
Please enter a int value :
4
Please enter a double value :
4.4
Please enter a characters :
rrr
Please enter a int value :
5
Please enter a double value :
5.5
Please enter a characters :
tttThe 1 group's value:
1
1.10
qqqThe 2 group's value:
2
2.20
wwwThe 3 group's value:
3
3.30
eeeThe 4 group's value:
4
4.40
rrrThe 5 group's value:
5
5.50
ttt
2)指標形式
//結構陣列指標形式引數
#include <stdio.h>
#include <string.h>
#define SIZE 5
struct names
{
int ma;
double games;
char datas[30];
};
struct names hold[SIZE];//在這裡面,陣列名稱代表的就是陣列首元素的地址,也就是指向結構的指標。
void input_starray(struct names *pts);
void read_starray(struct names *pts);
int main(void)
{
struct names *pts=hold;//注意,在這裡,hold是陣列名,所以就是一個指標,儲存的是首元素的地址。
input_starray(pts);
read_starray(pts);
return 0;
}
void input_starray(struct names *pts)//以陣列形式呈現形參,這個形參表示的是接受指向names為模板的結構變數的指標。
{
for (int i=0;i<SIZE;i++)
{
puts("Please enter a int value :");
scanf("%d",&(pts+i)->ma);//雖然用的是指標,但是指標訪問成員相當於還是成為一個成員對應的變數,因此要加取地址。
puts("Please enter a double value :");
scanf("%lf",&(pts+i)->games);
getchar();
puts("Please enter a characters :");
fgets((pts+i)->datas,30,stdin);//在這裡,指標訪問datas,所以表示的是陣列的陣列名,也就代表著陣列首元素地止。
{
int length=strlen((pts+i)->datas);
if ((pts+i)->datas[length-1] == '\n')
{
(pts+i)->datas[length-1] = '\0';
}
else
{
while (getchar() != '\n')
{
continue;
}
}
}
}
return;
}
void read_starray(struct names *pts)
{
for (int i=0;i<SIZE;i++)
{
printf("\nThe %d group's value:\n",i+1);
printf("%d\n",(pts+i)->ma);
printf("%.2f\n",(pts+i)->games);
puts((pts+i)->datas);
}
return;
}
列印結果如下:
Please enter a int value :
1
Please enter a double value :
1.1
Please enter a characters :
qqq
Please enter a int value :
2
Please enter a double value :
2.2
Please enter a characters :
www
Please enter a int value :
3
Please enter a double value :
3.3
Please enter a characters :
eee
Please enter a int value :
4
Please enter a double value :
4.4
Please enter a characters :
rrr
Please enter a int value :
5
Please enter a double value :
5.5
Please enter a characters :
tttThe 1 group's value:
1
1.10
qqqThe 2 group's value:
2
2.20
wwwThe 3 group's value:
3
3.30
eeeThe 4 group's value:
4
4.40
rrrThe 5 group's value:
5
5.50
ttt
3)總結
在上面的兩段程式碼中:
1.為什麼把陣列定義宣告放在外面:
原因是主函式在執行的時候所用的記憶體叫棧(zhan),棧的大小是有限制的,由於結構陣列是一種比較大的陣列,因此宣告在外部是一種比較常見的做法,這樣陣列就不會佔用主程式中的棧。
2.用指標訪問成員:
指標是訪問成員的一種方式,比如pts->names表示訪問的是結構中的names成員,如果names是個變數,那麼pts->names整體就表示這個變數,如果names是一個數組,那麼pts->names整體就表示陣列首元素的地址。
十、伸縮型陣列成員
在結構中,我們有一種特殊形式可以使用,那就是伸縮型陣列成員,在宣告結構模板的時候可以不去宣告陣列的大小。
1)使用伸縮型陣列成員的要求:
1.結構中只能使用一個伸縮型陣列成員;
2.結構中的伸縮型陣列成員必須位於結構的最末尾;
3.使用malloc()函式。
2)為什麼使用伸縮型陣列成員
1.首先,使用伸縮型陣列成員要用malloc()函式,該函式建立的是動態記憶體,不在棧中,對於成員非常多的結構,我們可以使用malloc函式(不具有伸縮型陣列成員的結構同樣能用malloc()函式)。
2.其次:可以自定義成員陣列的大小。(最重要的)
3)程式:
//伸縮型陣列成員的使用
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct names
{
int ma;
double games;
char datas[];//由於要使用伸縮型結構成員,因此方括號中什麼也不加。
};
void input_st(struct names *pt,int size);
void read_st(struct names *pt);
int main(void)
{
int size;
puts("Please enter the array's size you want:");
scanf("%d",&size);
struct names *pts;
pts=malloc(sizeof(struct names)+size*sizeof(char));
//在這裡,由於結構模板中的陣列沒有大小,所以struct names的大小不包含陣列,因此再加上想要的陣列大小,就是所需結構變數的大小
//雖然使用malloc()建立的結構,pts是這個結構變數唯一的訪問方式,但是這個結構和普通結構完全一樣,訪問方式也完全一樣。
input_st(pts,size);
read_st(pts);
free(pts);//養成好習慣,用完動態記憶體記得釋放掉。
return 0;
}
void input_st(struct names *pt,int size)
{
puts("Enter the value of a int:");
scanf("%d",&pt->ma);
puts("Enter the value of a double:");
scanf("%lf",&pt->games);
getchar();
puts("Enter a characters you want:");
fgets(pt->datas,size,stdin);
int length=strlen(pt->datas);
if (pt->datas[length-1] == '\n')
{
pt->datas[length-1]='\0';
}
else
{
while (getchar() != '\n')
{
continue;
}
}
return;
}
void read_st(struct names *pt)
{
puts("The contents are:");
printf("ma=%d\n",pt->ma);
printf("games=%.2f\n",pt->games);
puts(pt->datas);
return;
}
列印結果:
Please enter the array's size you want:
30
Enter the value of a int:
3
Enter the value of a double:
3.3
Enter a characters you want:
I love Micy very much!
The contents are:
ma=3
games=3.30
I love Micy very much!
4)注意事項
1.使用malloc()函式來建立結構,創建出來的結構和普通結構相同,訪問方式和指標訪問方式相同。
2.使用完malloc()函式來分配動態記憶體,因此在最後需要使用free()函式釋放掉動態記憶體。
十一、匿名結構在巢狀結構中的應用
匿名結構用在巢狀結構中比較常見,原因是可以減少結構變數的設定次數。
//匿名結構在巢狀結構中的應用
#include <stdio.h>
struct names
{
int ma;
double games;
};
struct holds
{
int diy;
double numbers;
char datas[30];
struct//這裡不能加names這個結構模板名稱
{
int ma;
double games;
};//避免建立變數,這樣可以直接放進來。現在ma 和games就相當於直接成為holds的成員了。
int cch;
};
int main(void)
{
struct holds toys=
{
2,
3.4,
"I love Micy very much!",
5,
4.6,//初始化的時候只需要按著順序初始化就可以了。
7,
};
printf("diy=%d\n",toys.diy);
printf("ma=%d\n",toys.ma);//由於直接成為了成員,因此可以直接使用一次點運算子。
return 0;
}
列印結果:
diy=2
ma=5
一定要注意,在巢狀的時候使用匿名,這樣可以簡化操作,但是需要省略巢狀部分的結構模板名稱,並且巢狀部分的成員就相當於是整個結構的成員了。