2011-10-08 4 views
7

저는 C에서 약간 익숙하며 메모리가 작동하는 방식을 이해하는 데 어려움을 겪고 있습니다. 특히 memcpy과 같은 내장 함수가 좋습니다. 여기 C - Malloc 및 memcpy (메모리 관리)

내가

struct data_t { 
    int datasize; 
    void *data; 
}; 

사용 해요 struct입니다 그리고 여기에 내가 그것을 사용하고 보조 기능입니다 :

struct data_t *data_create(int size) 
{ 
    struct data_t *dt=malloc(sizeof(struct data_t)+size); 
    dt->datasize=size; 
    dt->data="1234567890a"; 
    return dt; 
} 

는 이제 main 기능에 내가이 일을 아무 문제가 :

struct data_t *data = data_create(1024); 
data->data="123456a";//just an example 

그러나 이것은 Seg 결함을 던집니다.

memcpy(data->data,"123456a",strlen("1234567890a")+1); 

내 질문은 왜입니까? 어떻게 피할 수 있습니까? C를 처음 접했을 때 C가 메모리를 어떻게 다룰 때 조금 새로운가요?

고맙습니다.

편집 : 작동합니다! 고맙습니다. 데이터 포인터를 완전히 놓쳤습니다. 이제 valgrind에 따르면 모든 것이 잘 작동합니다.

답변

6

memcpy(data->data,"123456a",strlen("1234567890a")+1);

는 할당되지 않은 일부 쓰레기/잘못된 주소로 data->data 때문에 void * 유형 점을 실패합니다. data읽기 전용 섹션 (실행 파일의 .rodata처럼)에 저장된 문자열 리터럴의 주소를 가지며 쓰기 불가능한 메모리에로드됩니다. 또한 포인터에 문자열 주소를 할당하지 않은 경우 변수는 다음 그렇게 제 할당. 버퍼를 할당하거나 어떤 유효한 허용 위치로 초기화되지 않은 일부 무효/가비지 어드레스 값을 보유한다.

data->data = malloc (sizeof (char) * size); 

malloc는 어드레스의 블록의 제 1 위치의 주소를 반환 atleast size * sizeof (char) 바이트. size 바이트를 data->data이 가리키는이 메모리 위치에 복사 할 수 있습니다.

free (addr) 호출로 해당 메모리 작업을 완료하면 할당 된 메모리 블록을 비우십시오. 나는 당신이 아주 이상한 방식으로 data 버퍼를 할당하는 것을 시도했다 참조


(?) : 여분이 struct data_t와 함께 size 바이트를 할당하는

struct data_t *dt=malloc(sizeof(struct data_t)+size); 

. 그러나 어떤 경우라도, data 구성 요소는 여전히 변경할 수없는 부분을 가리 킵니다. 사용하십시오 :

struct data_t *dt = malloc(sizeof(struct data_t)); 
dt->data = malloc (sizeof (char) * size); 
memcpy (data->data, "whatever", sizeof ("whatever")+1); 
return dt; 

먼저 무료로 수행

free (dt->data); 

을 다음

free (dt); 
+0

공간은 초기 할당에 할당 된; 포인터는 단순히 할당 된 공간을 가리 키도록 설정되지 않았습니다. –

+0

@JonathanLeffler : 예, 처음에 할당 할 때 묻는 사람이 약간의 공간을 할당했습니다. 한 번에 모두 할당 할 필요가 없다면 나는 명시 적 호출을 선호 할 것이다. – phoxis

+0

이렇게하면 "malloc에서 반환 한 포인터를 명시 적으로 캐스팅해야 함"을 해결하기 위해 ''void * '에서'data_t * '[-fpermissive]'로의 잘못된 변환이 발생합니다. – VasaraBharat

1

공지 사항 void *data 포인터이며, data_create에, 당신은 그것을 위해 당신을 공간을 할당하지 않았다 읽기 전용 인 문자열 상수 "1234567890a"을 가리 키도록하십시오.

main에서 다른 문자열 상수 "123456a"을 만든 다음 void *data을 읽기 전용 인 문자열 상수로 지정합니다.

그래서 memcpy을 호출하여 쓰기 불가능 (또는 초기화하지 않은 메모리 주소)으로 쓸 때 오류가 발생합니다.

0

data-> data는 포인터입니다. 그리고이 포인터는 아무데도 가리 키지 않습니다. memcpy를하기 전에 공간을 할당하고이 공간을 가리 키도록 데이터 -> 데이터를 만들어야한다.

data->data = malloc(strlen("1234567890a")+1); 

하고 방어 적이기는> 데이터 -만큼 실패하지 않습니다 데이터! "123"이 컴파일시에 할당되기 때문에

data->data = "123"

는 괜찮 일 = NULL

, 그래서 data-> data는 문자열 "123"의 시작 부분을 가리키고, 데이터 데이터에 대한 포인터가 초기화되지 않았기 때문에 memcpy(data->data,"123",4)을 호출하는 것은 실패 할 것입니다. 그리고 심지어 읽을 수없는 메모리의 임의의 위치를 ​​가리키게됩니다.

struct data_t *dt=malloc(sizeof(struct data_t)+size); 

이 크기의 구조체 data_t + 크기의 메모리 청크를 생성합니다 :

+0

'memcpy'는 소스보다 많은 바이트를 소스에서 복사하려고 시도하는 경우 여전히 유효하지 않습니다. – Mat

+0

예 코드에 오류가 두 개 있습니다. –

3

첫 번째 실수는 이것이다. 내 생각에 당신이 data_t 내부의 데이터 필드가이 메모리를 사용할 수는 있지만 데이터가이 메모리에 주소를 보유하지 않기 때문에 할 수 없다고 생각합니다.

두 번째 실수는 여기서 "데이터"에 다음 문자열 값을 복사하는 것으로 가정했다 :

사실 여기에 무슨 일이 있었 존재하는 메모리 "123456a"문자열 있다는 것입니다 무엇
data->data="123456a"; 

귀하의 프로그램의 전체 수명 동안. 데이터 -> 데이터에 "123456a"를 할당하면 실제로 "123456a"문자열의 주소를 가져 와서 값 ("123456a")이 아닌 데이터 -> 데이터에 넣는 것이지만 위치는 또는 "123456a"의 주소 (0x23822 ...). 당신은 메모리에 값 "123456a"를 복사하려고

memcpy(data->data,"123456a",strlen("1234567890a")+1); 

데이터가 가리키는 :

당신의 마지막 실수는이이었다. 데이터는 무엇을 가리키고 있습니까? 이전에 할당 된 "123456a"문자열을 포함하는 읽기 전용 메모리 영역을 가리 킵니다. 즉, 프로그램에 "123456a"주소로 쓰라고 지시했습니다.여기

당신이 기대하는 것을 무엇을 할 것 인 프로그램입니다 :

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <assert.h> 

typedef struct { 
    size_t datasize; 
    char *data; 
} data_t; 

data_t *data_create(size_t size) 
{ 
    data_t *dt; 

    dt = malloc(sizeof(data_t)); 
    assert(dt != NULL); 
    dt->data = malloc(size); 
    assert(dt->data != NULL); 
    dt->datasize = size; 

    /* need to decide what to do when this happens */ 
    assert((strlen("1234567890a") + 1) < size); 
    strcpy(dt->data, "1234567890a"); 

    return dt; 
} 

void data_destroy(data_t *dt) 
{ 
    free(dt->data); 
    free(dt); 
} 

int main(void) 
{ 
    data_t *data = data_create(1024); 
    /* data->data="123456a"; DONT DO THIS YOU WILL CAUSE A MEMORY LEAK */ 

    assert(data->datasize >= (strlen("123456a")+1)); 
    memcpy(data->data, "123456a", strlen("123456a")+1); 

    printf("%s\n", data->data); 

    data_destroy(data); 

    return EXIT_SUCCESS; 
}