문자열 리터럴과 동적메모리에 문자열할당

duckkuri·2020년 10월 20일
0

42Seoul_Libft_Story

목록 보기
19/22

🚨문제 상황

ft_lstdelone에 맞는 main코드를 짜던 중 자꾸 버그가 발생한다.
이렇게도 고쳐보고, 저렇게도 고쳐보았지만 자꾸 에러가 난다.

경과 1

문제의 코드 내용을 요약해보면 다음과 같다.
code

int main(void)
{
    char *p1;

    p1 = (char *) malloc(sizeof(char) * 4);

    *p1 = "abc";
    printf("%s\n",p1);
    free(p1);
    return(0);
}

output

경과2

'*p1이 첫번째 문자 1개만의 자리값만 나타내서 그런가...?' 싶어서 다음과 같이해봤다.

code

int main(void)
{
    char *p1;

    p1 = (char *) malloc(sizeof(char) * 4);

    p1 = "abc";
    printf("%s\n",p1);
    free(p1);

    return(0);
}

output

abc
untitled(20228,0x1062f55c0) malloc: *** error for object 0x100204fa2: pointer being freed was not allocated
untitled(20228,0x1062f55c0) malloc: *** set a breakpoint in malloc_error_break to debug

그랬더니 어찌어찌 출력이 되는거 같긴한데 free()에서 에러가 떴다.

경과 3

인터넷에 검색해보았더니, malloc할당 후 string입력은 대부분 scanf(), strcpy()을 이용하는 예제 뿐이었다.
""를 사용해서 입력하는게 왜 안되는지 의문스러웠다.

경과 4

동료분의 조언으로 p1 = "abc"하기 전과 후의 p1의 주소를 비교해 보니 다음과 같았다.
code

int main(void)
{
    char *p1;

    p1 = (char *) malloc(sizeof(char) * 4);

    printf("%p\n",p1);
    p1 = "abc";
    printf("%p\n",p1);
    free(p1);
    return(0);
}

output

untitled(21994,0x113ffc5c0) malloc: *** error for object 0x105d68faa: pointer being freed was not allocated
untitled(21994,0x113ffc5c0) malloc: *** set a breakpoint in malloc_error_break to debug
0x7fc5f6400620
0x105d68faa

여기서 뭔가 생각과 다르게 돌아가고 있는것을 느꼈다.

리터럴(literal)

  • 프로그래밍 언어에서 리터럴(literal)이란, 소스상에서 고정된 값을 가지는 것을 일컫는다.
  • 특히 C언어의 경우 큰 따옴표(")로 묶인 것들을 문자열 리터럴(string literal)이라 부른다.
char *pstr = "goodbye";
printf("why so serious?");
scanf("%c", str[0]);
  • 위 코드에서의 리터럴은 따옴표로 묶여진 goodbye, why so serious, %c 이다.

리터럴의 특징

  • 컴퓨터는 이러한 리터럴을 텍스트 세그먼트(text segment)에 모아 보관한다

데이터 영역 종류 (Data Sagment)

text sagment

  • 코드와 상수, 리터럴 등이 정의
  • 읽기만 가능함

data sagement

  • 사전에 정의된 값, 수정가능한 정적변수, 수정가능한 전역변수

BSS sagement

  • 초기화 되지 않은 모든 전역변수와 정적 변수

heap sagment

  • 동적 메모리 할당 영역

stack

  • 일반 변수

  • 리터럴이 text sagment에 저장되어 읽기전용으로 관리되어 지니, 나 혹은 컴퓨터에 의한 버그로 값이 바뀌는일은 생길 수 없다.

따라서

  1. 경과1의 경우
    • *p1sizeof(char) * 1의 크기를 갖고 있으므로 여러개의 값을 가진 string을 넣을 순 없다.
  2. 경과2의 경우
    • p1 = "321";코드가 동작되면서, p1은 기존에 갖고있던 malloc된 주소값 말고 리터럴 주소값인 "321"의 주소를 가리킨다.
    • 그 이후 free()에서 오류가 나는 이유는 p1은 더 이상 동적할당된 값이 아닌, 리터럴 주소값을 가리키기 때문이다.

그렇다면?

*(p1+1) = '1';
*(p1+2) = '2';
*(p1+3) = '3';

위 코드 처럼 일일이 넣을 수 밖에없다.

  • 이렇게 불편하고 짜증나기에 strcpy()를 많이 사용한다.
  • strcpy()는 내가 짰을때처럼 할당된메모리를 하나씩 대입해서 넣도록 돌아가기 때문에 위 코드처럼 일일히 넣는것과 동일하게 동작된다.

참고 링크 :
사실 내가 쓴 글 보단 아래 링크 내용을 보는게 낫다.
https://modoocode.com/33

profile
😤 Today I Learned

0개의 댓글