C語言結(jié)構(gòu)體成員賦值的深拷貝與淺拷貝詳解
淺拷貝
C語言中的淺拷貝是指在拷貝過程中,對于指針型成員變量只拷貝指針本身,而不拷貝指針?biāo)赶虻哪繕?biāo),它按字節(jié)復(fù)制的。我們分幾種情況舉例子來看一下。
結(jié)構(gòu)體中不存在指針成員變量時
代碼如下:
#include <stdio.h>
typedef struct {
char name[64];
int age;
}Member;
int main(){
Member stu1 = { "LiMing", 18 };
Member stu2;
stu2 = stu1;
printf("%s,%d\n", stu2.name, stu2.age);
system("pause");
return 0;
}
運(yùn)行如下:

結(jié)構(gòu)體中存在指針成員變量時
代碼如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char *name;
int age;
}Member;
int main() {
Member Member1, Member2;
Member1.name = malloc(sizeof(char) * 64);
if (NULL == Member1.name)
{
printf("malloc failed\n");
}
memset(Member1.name, 0, 64);
//strcpy(Member1.name, "LiMing");
snprintf(Member1.name, 64, "LiMing");
Member1.age = 18;
Member2 = Member1;/*拷貝*/
snprintf(Member2.name, 64, "LiXiaoYao");
Member2.age = 29;
printf("%s, %d\n", Member1.name, Member1.age);
if (NULL != Member1.name) {
free(Member1.name);
Member1.name = NULL;
}
system("pause");
return 0;
}運(yùn)行如下:

從中我們看到,改變Member2的值,Member1的值也改變了,這說明一片空間被兩個不同的子對象共享了,改變一個對象的值另外一個也會隨之改變。
我們改變Member2寫法,申請內(nèi)存的代碼如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char *name;
int age;
}Member;
int main() {
Member Member1;
Member1.name = malloc(sizeof(char) * 64);
if (NULL == Member1.name)
{
printf("malloc failed\n");
}
memset(Member1.name, 0, 64);
//strcpy(Member1.name, "LiMing");
snprintf(Member1.name, 64, "LiMing");
Member1.age = 18;
Member Member2;
Member2.name = malloc(sizeof(char) * 64);
if (NULL == Member2.name)
{
printf("malloc failed\n");
}
memset(Member2.name, 0, 64);
//strcpy(Member2.name, "LiMing");
snprintf(Member2.name, 64, "LiXiaoYao");
Member2.age = 29;
Member1 = Member2;
printf("%s, %d\n", Member2.name, Member2.age);
if (NULL != Member1.name) {
free(Member1.name);
Member1.name = NULL;
}
if (NULL != Member2.name) {
free(Member2.name);
Member2.name = NULL;
}
system("pause");
return 0;
}運(yùn)行如下:

從中我們看到,當(dāng)數(shù)據(jù)成員中有指針時,兩個類中的兩個指針將指向同一個地址,當(dāng)對象快結(jié)束時,會調(diào)用兩次free函數(shù),此時Member2已經(jīng)是野指針(圖中有X的錯誤標(biāo)志),這個野指針指向的內(nèi)存空間已經(jīng)被釋放掉,再次釋放會報異常錯誤,要解決這個問題就要涉及到深拷貝了。
深拷貝
深拷貝除了拷貝其成員本身的值之外,還拷貝成員指向的動態(tài)內(nèi)存區(qū)域內(nèi)容,深拷貝會在堆內(nèi)存中另外申請空間來儲存數(shù)據(jù)。
解決的思路是在釋放掉被賦值指針變量的舊指向內(nèi)存時,重新對其開辟新內(nèi)存,這種情況下兩個結(jié)構(gòu)體中指針地址不同,但是指向的內(nèi)容是一致的。代碼如下:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char *name;
int age;
}Member;
int main() {
Member Member1;
Member1.name = malloc(sizeof(char) * 64);
if (NULL == Member1.name)
{
printf("malloc failed\n");
}
memset(Member1.name, 0, 64);
//strcpy(Member1.name, "LiMing");
snprintf(Member1.name, 64, "LiMing");
Member1.age = 18;
Member Member2;
Member2.name = malloc(sizeof(char) * 64);
if (NULL == Member2.name)
{
printf("malloc failed\n");
}
memset(Member2.name, 0, 64);
//strcpy(Member2.name, "LiMing");
snprintf(Member2.name, 64, "LiXiaoYao");
Member2.age = 29;
if (Member1.name != NULL) {
free(Member1.name);
Member1.name = NULL;
}
Member1.name = malloc(strlen(Member2.name) + 1);
strcpy(Member1.name, Member2.name);
printf("%s, %d\n", Member1.name, Member1.age);
if (NULL != Member1.name) {
free(Member1.name);
Member1.name = NULL;
}
if (NULL != Member2.name) {
free(Member2.name);
Member2.name = NULL;
}
system("pause");
return 0;
}運(yùn)行如下:

結(jié)論
使用C語言來說,深拷貝淺拷貝的概念我們不需要深究,在進(jìn)行結(jié)構(gòu)體拷貝的時候,結(jié)構(gòu)體成員是非指針的話,那么直接賦值是沒有任何問題的,建議使用這種方式,避免淺拷貝這類不易發(fā)現(xiàn)的錯誤產(chǎn)生。
如果成員有指針類型,我們就需要重寫拷貝函數(shù),自己定義拷貝行為了,這一點(diǎn)我們需要尤為注意。
到此這篇關(guān)于C語言結(jié)構(gòu)體成員賦值的深拷貝與淺拷貝詳解的文章就介紹到這了,更多相關(guān)C語言深拷貝 淺拷貝內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++讀取訪問權(quán)限沖突引發(fā)異常問題的原因分析
C語言是一門通用計算機(jī)編程語言,廣泛應(yīng)用于底層開發(fā),最近在用C++寫代碼時經(jīng)常會遇到“引發(fā)了異常: 讀取訪問權(quán)限沖突,所以這篇文章主要給大家介紹了關(guān)于C++讀取訪問權(quán)限沖突引發(fā)異常問題的相關(guān)資料,需要的朋友可以參考下2021-07-07
C++實(shí)現(xiàn)LeetCode(37.求解數(shù)獨(dú))
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(37.求解數(shù)獨(dú)),本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07
C++關(guān)鍵字thread_local學(xué)習(xí)筆記
這篇文章主要為大家介紹了C++關(guān)鍵字thread_local學(xué)習(xí)筆記,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10
C/C++ 原生API實(shí)現(xiàn)線程池的方法
線程池,簡單來說就是有一堆已經(jīng)創(chuàng)建好的線程,接下來通過本文給大家介紹C/C++ 原生API實(shí)現(xiàn)線程池的方法,感興趣的朋友跟隨小編一起看看吧2021-11-11
Linux系統(tǒng)下如何使用C++解析json文件詳解
JSON(JavaScript Object Notation, JS 對象簡譜) 是一種輕量級的數(shù)據(jù)交換格式。下面這篇文章主要給大家介紹了關(guān)于Linux系統(tǒng)下如何使用C++解析json文件的相關(guān)資料,需要的朋友可以參考下2021-06-06
C++實(shí)現(xiàn)二分法求連續(xù)一元函數(shù)根
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)二分法求連續(xù)一元函數(shù)根,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2020-06-06

