第四天2017/03/31(下午1:结构体、数组)
生活随笔
收集整理的這篇文章主要介紹了
第四天2017/03/31(下午1:结构体、数组)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
//備用知識:沒有內存,哪有指針?
int main()
{//錯誤程序char *name; //此處只定義了指針name(指針占4個字節),并沒有給name分配內存//name = (char*)malloc(100*sizeof(char));cin>>name; //因此:往name中寫數據,程序肯定會運行崩潰!cout<<name;
}
修改成下面的程序:
int main()
{//正確程序char *name; //此處只定義了指針name(指針占4個字節),并沒有給name分配內存name = (char*)malloc(100*sizeof(char));//動態給name指針分配內存cin>>name; //因為name已經分配完內存,可以往里邊寫數據cout<<name;
}
int main()
{//正確程序char name[100];//靜態給name分配內存 cin>>name; //因為name已經分配完內存,可以往里邊寫數據cout<<name;
}
//============================================================
//知識延伸:
//cin何時能寫入?結構體指針和結構體成員指針分配內存的知識、釋放內存的順序? 結構體里邊的二級指針
#include <iostream>
using namespace std;
typedef struct student
{char **ptr; //【?結構體里邊的二級指針ptr】char na[100]; //給na數組靜態分配了內存char *name; //沒有給name指針分配內存int age;
}student;
int main()
{student *s1 = (student*)malloc(sizeof(student));cin >>s1->na;cout<<s1->na;//cin>>s1->name; //程序崩潰:【知識點】給結構體指針s1分配了內存,并不表示給結構體中的成員name也分配內存//cout<<s1->name;s1->name = (char *)malloc(100*sizeof(char)); //再給結構體中的name單獨分配內存cin>>s1->name;cout<<s1->name;//釋放內存:s1指針和s1->name指針必須單獨釋放
//【重點:釋放順序】先釋放里邊的s1->name,再釋放外邊的s1。if(s1!=NULL){free(s1);s1 = NULL;}if(s1->name){free(s1->name);s1->name = NULL;}return 0;
}
學習模塊:結構體
(1)結構體變量之間的相互賦值
(2)結構體作函數參數的兩種case
①用結構體變量作形參 ②用結構體指針、引用作形參 【二者有天壤之別】 區別一:(在被調函數中修改后,主調函數的結構體中的內容是否也被修改)①是傳值調用②傳址調用,改變了指針變量指向的內容的值 區別二:(效率問題)①發生賦值運算符之間的拷貝,消耗更大的,不建議使用;應用②更好。例:
(3)結構體中有二級指針、結構體數組相結合的代碼
【注】結構體中的二級指針一般用“二級指針的內存模型三”
#include <iostream> using namespace std;typedef struct person {char *pname;//char *name[100];int age;char **ptr; //二級指針 }person;//函數接口的聲明 person* create_PArr1(int N,int num); //創建結構體數組 int create_PArr2(person **per,int N,int num);int initPerArr(person* per,int N,int num); //初始化結構體數組 int PrintPerArr(person* per,int N,int num); //打印結構體數組void free_person1(person *p,int N,int num); //釋放結構體數組中分配的指針 void free_person2(person **p,int N,int num); int main() {int rev = 0; //0表示程序運行正確int N = 3;int num = 2;person *per = NULL;//創建結構體數組方式一:通過返回結構體指針//per = create_PArr1(N,num); //動態創建結構體數組(3個元素),每個元素中的二級指針指向2個字符串//if(per==NULL)//{// goto END;//} //創建結構體數組方式二:通過實參是結構體一級指針的地址,形參是結構體二級指針rev = create_PArr2(&per,N,num); if(rev!=0){goto END; //用goto語句避免內存泄漏}//初始化結構體數組rev = initPerArr(per,N,num);if(rev!=0){goto END; //用goto語句避免內存泄漏}//打印出結構體數組rev = PrintPerArr(per,N,num);if(rev != 0){goto END; //用goto語句避免內存泄漏}END://free_person1(per,N,num); //此種方式會導致野指針//cout<<"釋放完畢,程序結束!"<<endl;free_person2(&per,N,num); //傳入per的地址&per,可以在被調函數中修改per的值,即 per = NULL;cout<<"釋放完畢,程序結束!"<<endl;getchar(); }//========================================================================================================== //創建結構體數組方式一:(在被調函數中分配內存,通過return把在被調函數中分配的結構體數組的指針返回到主調函數中) person* create_PArr1(int N,int num) //創建結構體數組,數組中有N個結構體元素 {person* per = (person*)malloc(N*sizeof(person)); //類似于int* array = (int*)malloc(N*sizeof(int));//動態分配內存創建數組person per[N];if(per==NULL){cout<<"創建數組失敗"<<endl;return NULL;}//給結構體數組中的成員分配內存空間for(int i=0;i<N;i++){//給結構體數組中的一級指針成員pname分配內存空間per[i].pname = (char*)malloc(100*sizeof(char)); if(per[i].pname==NULL)return NULL;//給結構體數組中的二級指針成員ptr分配內存空間per[i].ptr = (char**)malloc(num*sizeof(char*)); //num表示二級指針指向一級指針的個數if(per[i].ptr==NULL)return NULL;for(int j=0;j<num;j++) //每個per[i]中的ptr指針指向一級指針的個數,per[i].ptr[num]{per[i].ptr[j] = (char*)malloc(100*sizeof(char));if(per[i].ptr[j]==NULL)return NULL;}}return per; //在堆中分配的內存可以返回到main函數 }//創建結構體數組方式二:(通過二級指針作為形參,一級指針作為實參) int create_PArr2(person **per,int N,int num) //創建結構體數組,數組中有N個結構體元素 {if(per==NULL) //如果傳入的地址是無效值return -1;person *ptemp = NULL; //定義一個臨時的結構體指針ptemp = (person *)malloc(N*sizeof(person)); //給ptemp指針分配內存,讓ptemp指向一個動態分配的結構體數組,相當于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; //方式二:在被調函數中定義一個臨時的變量ptemp,給ptemp分配完空間后,在把ptemp賦值給形參*per即可//主調函數傳入的是地址return 0; } //==========================================================================================================int initPerArr(person* per,int N,int num) //傳入的是一級指針 {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; }//========================================================================================================== //內存釋放方式一:這種方法在進行釋放完成后,(因為是值傳遞,所以)無法把主調函數中的傳入的實參設置為NULL void free_person1(person *p,int N,int num) //釋放N個結構體指針 {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) //因為通過方式二在進行釋放完后,可以順便把實參的值也設置為NULL,避免野指針的發生 {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;}//方式二的優點p = NULL; //因為傳進去的實參被釋放后全都沒有了,為了避免野指針的發生,在釋放完所有的(*p)指向的內容//后,把指針p也設置為NULL } //==========================================================================================================(4)【?重要】
【淺拷貝】
淺拷貝發生的情形:當結構體中有指針類型的數據元素時,如果使用默認的拷貝構造,會發生淺拷貝。
【帶來的問題】在進行指針釋放時,釋放兩次內存造成程序運行崩潰。
【深拷貝】
可以消除默認拷貝構造帶來的淺拷貝情形,使程序正常運行。
總結
以上是生活随笔為你收集整理的第四天2017/03/31(下午1:结构体、数组)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 第四天2017/03/31(上午:指针、
- 下一篇: 第四天2017/03/31(下午2:结构