C언어 문자열의 입출력

Kiwoong Park·2023년 3월 27일
0

C언어에서 문자열을 입력받을 때는 아래 코드와 같이 문자열의 길이가 선언되어야 하며 scanf을 통해 저장할 변수에 &를 붙일 필요가 없습니다.
숫자를 입력 받는 경우는 &를 통해 변수의 주소에 접근해서 값을 넣어주기 위한 것이고, 문자열은 그 자체가 배열의 주소값이기 때문에 &를 붙일 필요가 없습니다.

#include <stdio.h>
int main ()
{
	char a[9];
	scanf("%s", a); 
	printf("%s", a);
	return 0;
}

C언어에서 scanf("%s", str);를 사용하면 "Hello, World!" 와 같은 공백이후의 문자가 들어올 경우 해당 문자열 전체를 입력받을 수 없습니다.
scanf 함수는 버퍼에 문자열을 가져와 배열에 저장하는데 중간에 공백 문자, 탭문자, 개행문자가 있으면 그 이전까지만 저장하기 때문입니다.
fgets(str, 31, stdin);을 사용하면 공백 포함 30자리 이내의 문자열을 입력 받을 수 있게 된다.

#include <stdio.h>
int main(){
    char a[31]; /* 문자(배)열의 크기는 저장될 문자열 +1로 정의한다. 
    (C에서 문자열의 끝은 항상 널로 끝나야 하기 때문 
    - 문자열의 특성을 유지하려면 '\0'으로 끝나야 함!)
    */
    fgets(a,31,stdin); 
    printf("%s",a);
return 0;
}

https://www.onlinegdb.com/online_c_compiler 에서
아래 코드와 같이 길이 3의 문자열 3개를 선언한 뒤 3개의 문자를 각각 인풋으로 넣고 출력을 하면 NULL을 고려하지 않은 결과, 의도치 않은 결과를 출력하게 된다

#include <stdio.h>

int main()
{
    char arr1[3], arr2[3], arr3[3];
    scanf("%s %s %s",arr1, arr2, arr3);
    
    printf("%s %s %s\n",arr1, arr2, arr3);
    
    printf("%x %x %x", &arr1[0], &arr2[0], &arr3[0]);
    return 0;
}
입력 > 123 456 789
출력 > 123456789 456789 789
      d171d1cf d171d1d2 d171d1d5

주소값을 확인해 보면 arr1, arr2, arr3이 각 3byte씩(각 배열의 크기) 차이를 두고 있다. 즉, arr1 배열의 시작 주소부터 차례대로 '123'을 집어 넣었고 바로 다음 arr2 배열에 '456', 마지막 arr3 배열에 '789'를 집어 넣은 것이다.
그 결과 당연히 printf 함수는 \0, 즉 NULL값이 나올 때까지를 %s로 출력하기 때문에 arr1을 출력할 경우 arr2, arr3까지의 값이 나온 것이다.

이는 main()함수 내 지역변수인 arr1, arr2, arr3가 스택(stack) 영역에 할당 되며, Stack 영역은 메모리의 가장 큰 주소값부터 거꾸로 할당 된다(32비트 시스템의 경우만 해당, 64비트 시스템의 경우 지역변수 할당 시 할당 순서대로 메모리 주소값도 커짐). arr1이 먼저 정의되어 맨 아래 쌓이고, 그 다음 arr2, 다음 arr3로 할당되었기 때문이다.

만약 아래의 코드와 같이, arr1, arr2 순서로 선언하여 해당 변수의 메모리 주소가 차례대로 할당(arr1의 주소 = 0x7ffde44546e1, arr2의 주소 = 0x7ffde44546e4)되지만, scanf를 통해 입력 데이터를 받을 때 buffer overflow로 인해 제대로 변수에 값이 할당 되지 않는 것을 볼 수 있다.

#include <stdio.h>

int main()
{
    char arr1[3], arr2[3];
    scanf("%s %s",arr2, arr1);
    
    printf("arr1: %s and arr2: %s\n",arr1, arr2);
    
    printf("%p %p", &arr1[0], &arr2[0]);
    return 0;
}
input : 456 123
output : arr1: 123 and arr2: 
      0x7ffde44546e1 0x7ffde44546e4
profile
You matter, never give up

0개의 댓글