日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

第四天2017/03/31(下午1:结构体、数组)

發(fā)布時(shí)間:2025/3/21 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 第四天2017/03/31(下午1:结构体、数组) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
//備用知識(shí):沒有內(nèi)存,哪有指針? int main() {//錯(cuò)誤程序char *name; //此處只定義了指針name(指針占4個(gè)字節(jié)),并沒有給name分配內(nèi)存//name = (char*)malloc(100*sizeof(char));cin>>name; //因此:往name中寫數(shù)據(jù),程序肯定會(huì)運(yùn)行崩潰!cout<<name; } 修改成下面的程序: int main() {//正確程序char *name; //此處只定義了指針name(指針占4個(gè)字節(jié)),并沒有給name分配內(nèi)存name = (char*)malloc(100*sizeof(char));//動(dòng)態(tài)給name指針分配內(nèi)存cin>>name; //因?yàn)閚ame已經(jīng)分配完內(nèi)存,可以往里邊寫數(shù)據(jù)cout<<name; } int main() {//正確程序char name[100];//靜態(tài)給name分配內(nèi)存 cin>>name; //因?yàn)閚ame已經(jīng)分配完內(nèi)存,可以往里邊寫數(shù)據(jù)cout<<name; } //============================================================ //知識(shí)延伸: //cin何時(shí)能寫入?結(jié)構(gòu)體指針和結(jié)構(gòu)體成員指針分配內(nèi)存的知識(shí)、釋放內(nèi)存的順序? 結(jié)構(gòu)體里邊的二級(jí)指針 #include <iostream> using namespace std; typedef struct student {char **ptr; //【?結(jié)構(gòu)體里邊的二級(jí)指針ptr】char na[100]; //給na數(shù)組靜態(tài)分配了內(nèi)存char *name; //沒有給name指針分配內(nèi)存int age; }student; int main() {student *s1 = (student*)malloc(sizeof(student));cin >>s1->na;cout<<s1->na;//cin>>s1->name; //程序崩潰:【知識(shí)點(diǎn)】給結(jié)構(gòu)體指針s1分配了內(nèi)存,并不表示給結(jié)構(gòu)體中的成員name也分配內(nèi)存//cout<<s1->name;s1->name = (char *)malloc(100*sizeof(char)); //再給結(jié)構(gòu)體中的name單獨(dú)分配內(nèi)存cin>>s1->name;cout<<s1->name;//釋放內(nèi)存:s1指針和s1->name指針必須單獨(dú)釋放 //【重點(diǎn):釋放順序】先釋放里邊的s1->name,再釋放外邊的s1。if(s1!=NULL){free(s1);s1 = NULL;}if(s1->name){free(s1->name);s1->name = NULL;}return 0; }

學(xué)習(xí)模塊:結(jié)構(gòu)體
(1)結(jié)構(gòu)體變量之間的相互賦值

①賦值運(yùn)算符 ②memcpy(&s1,&s2,sizeof(s2)); ③逐個(gè)元素的手動(dòng)copy

(2)結(jié)構(gòu)體作函數(shù)參數(shù)的兩種case

①用結(jié)構(gòu)體變量作形參 ②用結(jié)構(gòu)體指針、引用作形參 【二者有天壤之別】 區(qū)別一:(在被調(diào)函數(shù)中修改后,主調(diào)函數(shù)的結(jié)構(gòu)體中的內(nèi)容是否也被修改)①是傳值調(diào)用②傳址調(diào)用,改變了指針變量指向的內(nèi)容的值 區(qū)別二:(效率問題)①發(fā)生賦值運(yùn)算符之間的拷貝,消耗更大的,不建議使用;應(yīng)用②更好。

例:

(3)結(jié)構(gòu)體中有二級(jí)指針、結(jié)構(gòu)體數(shù)組相結(jié)合的代碼

【注】結(jié)構(gòu)體中的二級(jí)指針一般用“二級(jí)指針的內(nèi)存模型三”

#include <iostream> using namespace std;typedef struct person {char *pname;//char *name[100];int age;char **ptr; //二級(jí)指針 }person;//函數(shù)接口的聲明 person* create_PArr1(int N,int num); //創(chuàng)建結(jié)構(gòu)體數(shù)組 int create_PArr2(person **per,int N,int num);int initPerArr(person* per,int N,int num); //初始化結(jié)構(gòu)體數(shù)組 int PrintPerArr(person* per,int N,int num); //打印結(jié)構(gòu)體數(shù)組void free_person1(person *p,int N,int num); //釋放結(jié)構(gòu)體數(shù)組中分配的指針 void free_person2(person **p,int N,int num); int main() {int rev = 0; //0表示程序運(yùn)行正確int N = 3;int num = 2;person *per = NULL;//創(chuàng)建結(jié)構(gòu)體數(shù)組方式一:通過返回結(jié)構(gòu)體指針//per = create_PArr1(N,num); //動(dòng)態(tài)創(chuàng)建結(jié)構(gòu)體數(shù)組(3個(gè)元素),每個(gè)元素中的二級(jí)指針指向2個(gè)字符串//if(per==NULL)//{// goto END;//} //創(chuàng)建結(jié)構(gòu)體數(shù)組方式二:通過實(shí)參是結(jié)構(gòu)體一級(jí)指針的地址,形參是結(jié)構(gòu)體二級(jí)指針rev = create_PArr2(&per,N,num); if(rev!=0){goto END; //用goto語句避免內(nèi)存泄漏}//初始化結(jié)構(gòu)體數(shù)組rev = initPerArr(per,N,num);if(rev!=0){goto END; //用goto語句避免內(nèi)存泄漏}//打印出結(jié)構(gòu)體數(shù)組rev = PrintPerArr(per,N,num);if(rev != 0){goto END; //用goto語句避免內(nèi)存泄漏}END://free_person1(per,N,num); //此種方式會(huì)導(dǎo)致野指針//cout<<"釋放完畢,程序結(jié)束!"<<endl;free_person2(&per,N,num); //傳入per的地址&per,可以在被調(diào)函數(shù)中修改per的值,即 per = NULL;cout<<"釋放完畢,程序結(jié)束!"<<endl;getchar(); }//========================================================================================================== //創(chuàng)建結(jié)構(gòu)體數(shù)組方式一:(在被調(diào)函數(shù)中分配內(nèi)存,通過return把在被調(diào)函數(shù)中分配的結(jié)構(gòu)體數(shù)組的指針返回到主調(diào)函數(shù)中) person* create_PArr1(int N,int num) //創(chuàng)建結(jié)構(gòu)體數(shù)組,數(shù)組中有N個(gè)結(jié)構(gòu)體元素 {person* per = (person*)malloc(N*sizeof(person)); //類似于int* array = (int*)malloc(N*sizeof(int));//動(dòng)態(tài)分配內(nèi)存創(chuàng)建數(shù)組person per[N];if(per==NULL){cout<<"創(chuàng)建數(shù)組失敗"<<endl;return NULL;}//給結(jié)構(gòu)體數(shù)組中的成員分配內(nèi)存空間for(int i=0;i<N;i++){//給結(jié)構(gòu)體數(shù)組中的一級(jí)指針成員pname分配內(nèi)存空間per[i].pname = (char*)malloc(100*sizeof(char)); if(per[i].pname==NULL)return NULL;//給結(jié)構(gòu)體數(shù)組中的二級(jí)指針成員ptr分配內(nèi)存空間per[i].ptr = (char**)malloc(num*sizeof(char*)); //num表示二級(jí)指針指向一級(jí)指針的個(gè)數(shù)if(per[i].ptr==NULL)return NULL;for(int j=0;j<num;j++) //每個(gè)per[i]中的ptr指針指向一級(jí)指針的個(gè)數(shù),per[i].ptr[num]{per[i].ptr[j] = (char*)malloc(100*sizeof(char));if(per[i].ptr[j]==NULL)return NULL;}}return per; //在堆中分配的內(nèi)存可以返回到main函數(shù) }//創(chuàng)建結(jié)構(gòu)體數(shù)組方式二:(通過二級(jí)指針作為形參,一級(jí)指針作為實(shí)參) int create_PArr2(person **per,int N,int num) //創(chuàng)建結(jié)構(gòu)體數(shù)組,數(shù)組中有N個(gè)結(jié)構(gòu)體元素 {if(per==NULL) //如果傳入的地址是無效值return -1;person *ptemp = NULL; //定義一個(gè)臨時(shí)的結(jié)構(gòu)體指針ptemp = (person *)malloc(N*sizeof(person)); //給ptemp指針分配內(nèi)存,讓ptemp指向一個(gè)動(dòng)態(tài)分配的結(jié)構(gòu)體數(shù)組,相當(dāng)于ptemp[N]if(ptemp==NULL)return -1;for(int i=0;i<N;i++){ptemp[i].pname = (char *)malloc(100*sizeof(char));if(ptemp[i].pname==NULL)return -1;ptemp[i].ptr = (char **)malloc(num*sizeof(char*));if(ptemp[i].ptr==NULL)return -1;for(int j=0;j<num;j++){ptemp[i].ptr[j] = (char*)malloc(100*sizeof(char));if(ptemp[i].ptr[j]==NULL)return -1;}}*per = ptemp; //方式二:在被調(diào)函數(shù)中定義一個(gè)臨時(shí)的變量ptemp,給ptemp分配完空間后,在把ptemp賦值給形參*per即可//主調(diào)函數(shù)傳入的是地址return 0; } //==========================================================================================================int initPerArr(person* per,int N,int num) //傳入的是一級(jí)指針 {if(per==NULL) //如果傳入的指針per是無效值return -1;for(int i=0;i<N;i++){per[i].age = 20+i;sprintf(per[i].pname,"pname = %d",20+i); for(int j=0;j<num;j++){sprintf(per[i].ptr[j],"pname = %d , %d",20+i,j);}}return 0; } int PrintPerArr(person* per,int N,int num) {if(per==NULL) //如果傳入的指針per是無效值return -1;for(int i=0;i<N;i++){per[i].age = 20+i;cout<<per[i].age<<" , "<<per[i].pname<<" , {";for(int j=0;j<num;j++){cout<<per[i].ptr[j]<<" ";}cout<<"}"<<endl;}return 0; }//========================================================================================================== //內(nèi)存釋放方式一:這種方法在進(jìn)行釋放完成后,(因?yàn)槭侵祩鬟f,所以)無法把主調(diào)函數(shù)中的傳入的實(shí)參設(shè)置為NULL void free_person1(person *p,int N,int num) //釋放N個(gè)結(jié)構(gòu)體指針 {for(int j=0;j<N;j++){if(p[j].pname!=NULL){free(p[j].pname);p[j].pname = NULL;}if(p[j].ptr!=NULL){for(int i=0;i<num && p[j].ptr[i]!=NULL;i++){free(p[j].ptr[i]);p[j].ptr[i] = NULL;}}free(p[j].ptr);p[j].ptr = NULL;}}void free_person2(person **p,int N,int num) //因?yàn)橥ㄟ^方式二在進(jìn)行釋放完后,可以順便把實(shí)參的值也設(shè)置為NULL,避免野指針的發(fā)生 {for(int j=0;j<N;j++){if((*p)[j].pname!=NULL){free((*p)[j].pname);(*p)[j].pname = NULL;}if((*p)[j].ptr!=NULL){for(int i=0;i<num && (*p)[j].ptr[i]!=NULL;i++){free((*p)[j].ptr[i]);(*p)[j].ptr[i] = NULL;}}free((*p)[j].ptr);(*p)[j].ptr = NULL;}//方式二的優(yōu)點(diǎn)p = NULL; //因?yàn)閭鬟M(jìn)去的實(shí)參被釋放后全都沒有了,為了避免野指針的發(fā)生,在釋放完所有的(*p)指向的內(nèi)容//后,把指針p也設(shè)置為NULL } //==========================================================================================================

(4)【?重要】

【淺拷貝】
淺拷貝發(fā)生的情形:當(dāng)結(jié)構(gòu)體中有指針類型的數(shù)據(jù)元素時(shí),如果使用默認(rèn)的拷貝構(gòu)造,會(huì)發(fā)生淺拷貝。
【帶來的問題】在進(jìn)行指針釋放時(shí),釋放兩次內(nèi)存造成程序運(yùn)行崩潰。

【深拷貝】
可以消除默認(rèn)拷貝構(gòu)造帶來的淺拷貝情形,使程序正常運(yùn)行。

【例】 #include <iostream> using namespace std;typedef struct person {char *pname;int age; }person;person* creat_person() {person *p = NULL;p = (person*)malloc(sizeof(person));if(p==NULL)return NULL;p->pname = (char*)malloc(sizeof(char)*100);if(p->pname==NULL)return NULL;return p; } void init_person(person* p) {p->age = 25;//p->pname = "Mr.right"; //【注】在進(jìn)行字符串初始化操作時(shí),用strcpy,不要用等號(hào)運(yùn)算符strcpy(p->pname,"Mr.right"); } void print_person(person* p) {cout<<p->age<<" "<<p->pname<<endl; } void free_person(person* p) {if(p!=NULL){if(p->pname!=NULL){free(p->pname);p->pname = NULL;}p = NULL;} } void copy_person(person* from,person* to) {memcpy(to,from,sizeof(struct person));//從源src所指的內(nèi)存地址的起始位置開始拷貝n個(gè)字節(jié)到目標(biāo)dest所指的內(nèi)存地址的起始位置中//深拷貝to->pname = (char*)malloc(sizeof(char)*100); //給to->pname分配額外的空間strcpy(to->pname,from->pname); } int main() {person *p1 = creat_person(); //p1、p2是指針變量,而不是person結(jié)構(gòu)體對(duì)象person *p2 = creat_person(); //*p1、*p2是person結(jié)構(gòu)體對(duì)象init_person(p1);init_person(p2);print_person(p1);print_person(p2);//(*p2) = (*p1); //結(jié)構(gòu)體對(duì)象賦值(【注】淺拷貝)//p2 = p1; //此句話表示:結(jié)構(gòu)體對(duì)象賦值,而不是指針賦值copy_person(p1,p2);//【注】深拷貝print_person(p1);print_person(p2);free_person(p1); free_person(p2); //淺拷貝導(dǎo)致程序崩潰getchar(); } 《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀

總結(jié)

以上是生活随笔為你收集整理的第四天2017/03/31(下午1:结构体、数组)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。