2011-08-02 5 views
11

크게 downvoted되기 전에 이미 본 적이있는 것과 비슷한 질문이 있지만 모두 유사하지는 않습니다. 적어도 내 생각에 그 질문에 대한 나의 무지를 변명해라. 그렇지 않으면 그것들은 꼭 C- 특정 적이 아니다.C : 구조체의 복사본 만들기 ... 구조체의 얕은 복사본 만들기

내 질문은 멤버로 포인터를 사용하여 구조체의 전체 복사본을 만드는 방법과 포인터 인 멤버가있는 구조체의 SHALLOW 복사본을 만드는 방법에 관한 것입니다. 그리고 나서, 참조 용으로, 포인터 멤버가없는 구조체의 완전한 복사본을 만드는 방법과 포인터 멤버가없는 구조체의 얕은 복사본을 만드는 방법을 설명합니다. 이제

Student* create_student(const char* first_name, const char* last_name, int grade,long id) 

{ 

    Student *newStudentp = (malloc(sizeof(Student))); 

    newStudentp -> last_name = (malloc((strlen(last_name) + 1) * sizeof(char))); 
    newStudentp -> first_name = (malloc((strlen(first_name) + 1) * sizeof(char))); 

    strncpy(newStudentp -> first_name, first_name, strlen(first_name) + 1); 
    strncpy(newStudentp -> last_name, last_name, strlen(last_name) + 1); 

    newStudentp -> grade = grade; 
    newStudentp -> id = id; 


    return newStudentp; 
} 

: 여기

typedef struct Student 
{ 
    char* first_name; 
    char* last_name; 
    int grade; 
    long id; 
} Student; 

내가 (헤더가 나와 함께 곰하시기 바랍니다 서식을 어렵게되고 있습니다) 학생을 만들려고 일반적인 기능입니다 :

의 우리가이 있다고 가정 해 봅시다 나는 깊고 얕은 사본을 만들려고 노력할 것이다. 나는 우리가 포인터와 재치있는 무언가를 우리 자신의 복사 기능을해야합니다 알고 포인터 회원들과 구조체의 전체 복사본을 위해 지금

int main() 
{ 
    Student *s1 = create_Student("Bo","Diddly", 100, 221); 
    Student *s2 = create_Student("Leeroy","Jenkins",50,1337); 
    memcpy(&s2,&s1,sizeof(Student)); //shallow copy of s1 INTO s2? 
    return 0; 
} 

멍청한 짓을하면 말해. 그 분별있는 것은 ... 나는 잘 모르겠다. 그래서이 DEEP 카피에 나의 (아마 형편없는) 시도가있다.

void copy_Student(Student *s1, Student *s2) 
{ 
    s2 -> grade = s1 -> grade; 
    s2 -> id = s1 -> id; 
    s2 -> first_name = s1 -> *first_name; 
    s2 -> last_name = s1 -> *last_name; 

} 

내 질문의 다른 부분 (구조체없이 멤버로 포인터가 있음)은 아마 구두로 설명 할 수 있습니다.

좋아 협조 읽은 후에 코멘트 편집 :

단순 복사본 : 는 memcpy (S2, S1,는 sizeof (학생));

깊은 복사 :

void free_student(Student* stu) 
{ 
    free(stu -> first_name); 
    free(stu -> last_name); 
} 

void copy_Student(Student *s1, Student *s2) 
{ 
    s2 -> grade = s1 -> grade; 
    s2 -> id = s1 -> id; 
    s2 -> first_name = strdup(s1 -> first_name); 
    s2 -> last_name = strdup(s1 -> last_name); 
} 

고마워 (여전히 오류가 있으면 지적해야하지만)! 너무 많은

감사합니다, 필

+0

학생이 끝나면 free_student를 불러야합니다. ** copy_Student **에는 없습니다. 먼저 s2를 비운 다음 내용을 복사합니다. 별로 좋은 생각이 아닙니다. –

+0

Duly 지적했다. 감사! – Phil

답변

5

얕은 복사본으로 나열한 코드는 그렇지 않습니다. 실제로 스택을 깨뜨리고 아마도 프로그램을 중단시킬 것입니다.

Student *s1 = create_Student("Bo","Diddly", 100, 221); 
Student *s2 = create_Student("Leeroy","Jenkins",50,1337); 
memcpy(&s2,&s1,sizeof(Student)); //shallow copy of s1 INTO s2? 

크기가 맞으면 s2 = s1;과 같을 것입니다. 하지만 크기가 잘못 되었기 때문에 복사가 너무 많이되어 s2 이후의 내용을 덮어 씁니다.

memcpy(s2,s1,sizeof(Student)); //shallow copy of s1 INTO s2 

당신이 깊은 사본이 코드는 유사 잘못이지만, 올바른 방향으로 가고있는 것입니다 : 실제 shallow 복사를하려면 &을 둡니다. 깊은 사본의 기본 아이디어는 각 필드를 복사해야한다는 것입니다. 포인터가 아닌 유형의 경우 얕은 사본과 동일하지만 포인터의 경우 더 똑똑한 작업을 수행해야합니다. 그러나 게시 한 코드는 그렇게하지 않습니다.대신이 방법을 사용해보십시오. 메모리 누수를 방지하기

void copy_Student(Student *s1, Student *s2) 
{ 
    s2 -> grade = s1 -> grade; 
    s2 -> id = s2 -> id; 
    s2 -> first_name = strdup(s1 -> first_name); 
    s2 -> last_name = strdup(s1 -> last_name); 
} 

주, 당신은 또한 새로운 사본을 할당하기 전에 s2에서 이전 이름을 해제해야합니다,이 이름을 확보하고, 또한 확인 것이라고 free_Student 기능을하는 create_Student 사본 이름 처음에는 리터럴 문자열을 복사 할 필요가 없도록 "플래그가 있어야 함"플래그가 포함됩니다.

포인터 (또는 다른 참조 유형)가없는 구조체의 경우 데이터 구조 자체가 얕기 때문에 딥 (deep) 복사본과 얕은 복사본 (shallow copy)간에 차이가 없습니다.

+1

strdup는 C 표준이 아닙니다 – user411313

+0

@ user411313 : 그래서? 그것은 POSIX와 SVr4와 4.3BSD에있다. 그리고 당신이 그것을 제공하지 않는 환경에 있다면 어떤 이유로 strlen, malloc, memcpy를 사용하여 대체 코드를 작성하는 것은 쉽지 않습니다. – Anomie

2

얕은 복사 한 문장으로 설명 할 수있다 딥 카피의 차이 : 얕은 복사 복사 포인터; 깊은 사본은 그들이 지적한 것을 복사합니다.

질문의 마지막 부분부터 시작하십시오 : 포인터가없는 경우 얕은 사본과 깊은 사본간에 차이가 없습니다.

얕은 복사를 시도하면 기술적으로 정확합니다. 그것은 논리적으로 잘못되었습니다. delete_student() 함수 (malloc을 해제하는 함수)는 얕은 사본을 처리 할 수 ​​없습니다. 다른 학생의 사본이 얼마나 남아 있는지 알 수 없으므로 원본 사본을 삭제할 때까지 free()을 연기해야합니다.

딥 복사본에는 매우 관련된 문제가 있습니다. 기술적으로 부정확합니다. 이상하게도 충분히 create_student 함수는 char *를 다른 것으로 복사하는 방법을 알고 있음을 보여줍니다. 즉, first_namelast_name의 전체 복사본이 있습니다. copy_Student은 동일한 작업을 수행해야합니다.

0

사본으로 생각하지 않고 새로운 구조체를 만들지 만 복제하려는 매개 변수와 동일한 매개 변수를 사용하는 것이 어떻습니까?

Student *s2 = create_Student("Leeroy","Jenkins",50,1337); 
Student *wiper = create_Student(s2->first_name, s2->last_name, 
               s2->grade, s2->id); 

wiper 구조체 s2의 복제를 가지고 : 그것은 당신이 이미 코드가, 미묘한 차이가 있지만.

은 단순히 당신이 s1s2합니다 ( memcpy)와 함께 일을 같이 할, 얕은 사본을 만들거나하려면 여기

s2 = malloc(sizeof(Student)); 
*s2 = *s1 
0
memcpy(&s2,&s1,sizeof(Student)); //shallow copy of s1 INTO s2? 

당신이 포인터 s2을 덮어 및 포인터 s2을 내했습니다 s1의 해당 포인터 값에 의해 메모리가 누출되었습니다.

딥 복사를 수행하려면 먼저 대상 구조가 가리키는 메모리를 모두 확보해야합니다. 그런 다음 소스 구조가 가리키는 문자열을 보유 할만큼 충분한 메모리를 할당하십시오. 자, strncpy 이상의 문자열. 대신이의

void copy_Student(Student *s1, Student *s2) 
{ 
    assert((s1 != NULL) && (s2 != NULL)); 

    if(s2->first_name != NULL) free(s2->first_name); 
    if(s2->last_name != NULL) free(s2->last_name); 

    s2->grade = s1->grade; 
    s2->id = s1->id; 

    s2->last_name = (malloc((strlen(s1->last_name) + 1) * sizeof(char))); 
    s2->first_name = (malloc((strlen(s1->first_name) + 1) * sizeof(char))); 

    strncpy(s2-> first_name, s1->first_name, strlen(s1->first_name) + 1); 
    strncpy(s2-> last_name, s1->last_name, strlen(s1->last_name) + 1); 
} 
0

:

newStudentp -> last_name = (malloc((strlen(last_name) + 1) * sizeof(char))); 

는 수행

s2->first_name = strdup (s1->first_name); 

:

newStudentp -> last_name = strdup (last_name); 

당신의 깊은 복사 (cnicutar 제안 정확히 무엇을) 비슷한하고 싶어 cnicutar의 문제 제안은 strcpy 앞에 수동으로 버퍼를 할당해야한다는 것이다.

정확하게 기억한다면 :

* s2 = * s1;

은 얕은 복사본을 만듭니다.

물론 딥 및 쉐도우 복사본 모두 free 대상 포인터인지 확인해야합니다. 그렇지 않으면 메모리 누수가 발생합니다. 그러나 free 포인터를 삽입해도 이전에 얕은 복사 된 구조로 전체 복사하면 문제가 발생할 수 있습니다.

+0

strdup는 C 표준이 아니며 malloc은 – user411313

관련 문제