第四天2017/03/31(下午1:结构体、数组)
生活随笔
收集整理的這篇文章主要介紹了
第四天2017/03/31(下午1:结构体、数组)
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
//備用知識(shí):沒(méi)有內(nèi)存,哪有指針?
int main()
{//錯(cuò)誤程序char *name; //此處只定義了指針name(指針占4個(gè)字節(jié)),并沒(méi)有給name分配內(nèi)存//name = (char*)malloc(100*sizeof(char));cin>>name; //因此:往name中寫(xiě)數(shù)據(jù),程序肯定會(huì)運(yùn)行崩潰!cout<<name;
}
修改成下面的程序:
int main()
{//正確程序char *name; //此處只定義了指針name(指針占4個(gè)字節(jié)),并沒(méi)有給name分配內(nèi)存name = (char*)malloc(100*sizeof(char));//動(dòng)態(tài)給name指針?lè)峙鋬?nèi)存cin>>name; //因?yàn)閚ame已經(jīng)分配完內(nèi)存,可以往里邊寫(xiě)數(shù)據(jù)cout<<name;
}
int main()
{//正確程序char name[100];//靜態(tài)給name分配內(nèi)存 cin>>name; //因?yàn)閚ame已經(jīng)分配完內(nèi)存,可以往里邊寫(xiě)數(shù)據(jù)cout<<name;
}
//============================================================
//知識(shí)延伸:
//cin何時(shí)能寫(xiě)入?結(jié)構(gòu)體指針和結(jié)構(gòu)體成員指針?lè)峙鋬?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; //沒(méi)有給name指針?lè)峙鋬?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)體變量之間的相互賦值
(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ū)別二:(效率問(wèn)題)①發(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ù)組方式一:通過(guò)返回結(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ù)組方式二:通過(guò)實(shí)參是結(jié)構(gòu)體一級(jí)指針的地址,形參是結(jié)構(gòu)體二級(jí)指針rev = create_PArr2(&per,N,num); if(rev!=0){goto END; //用goto語(yǔ)句避免內(nèi)存泄漏}//初始化結(jié)構(gòu)體數(shù)組rev = initPerArr(per,N,num);if(rev!=0){goto END; //用goto語(yǔ)句避免內(nèi)存泄漏}//打印出結(jié)構(gòu)體數(shù)組rev = PrintPerArr(per,N,num);if(rev != 0){goto END; //用goto語(yǔ)句避免內(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)存,通過(guò)return把在被調(diào)函數(shù)中分配的結(jié)構(gòu)體數(shù)組的指針?lè)祷氐街髡{(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)); //類(lèi)似于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ù)組方式二:(通過(guò)二級(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) //如果傳入的地址是無(wú)效值return -1;person *ptemp = NULL; //定義一個(gè)臨時(shí)的結(jié)構(gòu)體指針ptemp = (person *)malloc(N*sizeof(person)); //給ptemp指針?lè)峙鋬?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是無(wú)效值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是無(wú)效值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,所以)無(wú)法把主調(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)橥ㄟ^(guò)方式二在進(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í)參被釋放后全都沒(méi)有了,為了避免野指針的發(fā)生,在釋放完所有的(*p)指向的內(nèi)容//后,把指針p也設(shè)置為NULL } //==========================================================================================================(4)【?重要】
【淺拷貝】
淺拷貝發(fā)生的情形:當(dāng)結(jié)構(gòu)體中有指針類(lèi)型的數(shù)據(jù)元素時(shí),如果使用默認(rèn)的拷貝構(gòu)造,會(huì)發(fā)生淺拷貝。
【帶來(lái)的問(wèn)題】在進(jìn)行指針釋放時(shí),釋放兩次內(nèi)存造成程序運(yùn)行崩潰。
【深拷貝】
可以消除默認(rèn)拷貝構(gòu)造帶來(lái)的淺拷貝情形,使程序正常運(yùn)行。
總結(jié)
以上是生活随笔為你收集整理的第四天2017/03/31(下午1:结构体、数组)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 第四天2017/03/31(上午:指针、
- 下一篇: 第四天2017/03/31(下午2:结构