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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

發布時間:2025/3/21 编程问答 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 第四天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)結構體變量之間的相互賦值

①賦值運算符 ②memcpy(&s1,&s2,sizeof(s2)); ③逐個元素的手動copy

(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)【?重要】

【淺拷貝】
淺拷貝發生的情形:當結構體中有指針類型的數據元素時,如果使用默認的拷貝構造,會發生淺拷貝。
【帶來的問題】在進行指針釋放時,釋放兩次內存造成程序運行崩潰。

【深拷貝】
可以消除默認拷貝構造帶來的淺拷貝情形,使程序正常運行。

【例】 #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"; //【注】在進行字符串初始化操作時,用strcpy,不要用等號運算符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個字節到目標dest所指的內存地址的起始位置中//深拷貝to->pname = (char*)malloc(sizeof(char)*100); //給to->pname分配額外的空間strcpy(to->pname,from->pname); } int main() {person *p1 = creat_person(); //p1、p2是指針變量,而不是person結構體對象person *p2 = creat_person(); //*p1、*p2是person結構體對象init_person(p1);init_person(p2);print_person(p1);print_person(p2);//(*p2) = (*p1); //結構體對象賦值(【注】淺拷貝)//p2 = p1; //此句話表示:結構體對象賦值,而不是指針賦值copy_person(p1,p2);//【注】深拷貝print_person(p1);print_person(p2);free_person(p1); free_person(p2); //淺拷貝導致程序崩潰getchar(); } 《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀

總結

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

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。