작성
·
962
1
int c = 'A';
printf("%c", c);
printf("%d",c);
위 printf 문 실행 결과로 'A'와 65가 정상적으로 출력됩니다.
그러나,
scanf("%c",&c);
로 입력을 받으면
제 생각에는 A를 입력하면
%c 가 A를 받고,
이는 내부적을 65의 형태로 저장이 되어
변수 c에 65를 저장하고,
작은 char 자료형을 큰 int 자료형에 담았으니 문제가 없을거라 생각했습니다.
혹은
scanf("%d",&c);
로 입력을 받았을 때,
'A'가 %d를 만나 65로 바뀌어서 c 에 저장될 것이라고 생각했고,
위 두가지 경우 모두
printf 문의 형식지정자에 따라 65 혹은 'A' 로 다시 출력할 것으로 예상하였는데
전혀 다른 값이 출력되고 있습니다.
잘못된 이해가 있다면 바로잡아주시면 학습에 도움이 될 것 같습니다. 감사합니다!
답변 8
2
%d 는 반드시 4byte 를 읽어와라라고 의미 하는 것이 아닙니다. 단지 해당 변수를 10진수 정수로 출력하라는 지시문일 뿐이라고 편하게 생각해주시면 됩니다.
%c나 %hhd도 단순히 문자로 출력해라, 1byte, 즉 0~127 사이의 값을 가진 정수로 출력해라 라는 지시문 정도일 뿐입니다.
n은 int고 c는 char라고 할 때
printf("%d", n) -> n 이 가진 값을 10진수 정수로 출력. n은 4byte 공간이니까 이 4byte를 그대로 다 읽어오는 것 뿐
printf("%c", n) -> n 이 가진 값을 하나의 문자(아스키코드 0~127)로 출력. 0~127 즉 1byte 크기만 출력 가능하다는 의미나 마찬가지이므로 n에서 1byte만 읽어오는 것 뿐
printf("%hhd", n) -> 위와 마찬가지 (hhd는 1byte크기의 정수이므로 마찬가지로 0~127 정수 만 출력 가능)
printf("%d", c) -> c 가 가진 값을 10진수 정수로 출력. c는 1byte 공간이니까 이 1byte를 읽어와 10진수 정수로 출력하는 것 뿐.
c를 정수로 출력하라고 했을 뿐인데 굳이 c의 범위가 아닌 부분인 뒤의 3칸 까지 다 가져올 이유가 없겠죠?
내부적으로 돌아가는 것들에 대한 과목이라고 하시면 '컴퓨터 구조'와 '운영체제' 정도가 있습니다. KMOOC 이런 곳에 대학 전공 강의 무료로 들으실 수 있는걸로 알고 있습니다. 관심있으시면 여기서 공부해보세요! C언어에서의 로우한 부분 말씀하시는 것이라면 그냥 디버깅 많이 해보시고!!! 모르는거 스택오버플로우에 검색해보고 C언어에 대해서 자세하게 다루는 책 같은 것들 보시면서 공부하시면 될 것 같습니다. 스택오버플로우에 웬만한거 다 나오니 검색 많이 해보세요!
1
질문 1. 네 맞습니다.
질문 2.
저도 로우한 부분에 대해서는 잘 알지 못합니다.
질문자 글에 답변을 드리기 위해 메모리를 확인해봤는데 41 cc cc cc 라고 메모리에 적재되어 있길래 이 0x41cccccc 값이 -858993599 이구나 싶어 답변에서 그렇게 말씀을 드렸던 것이었습니다. 근데 아니었습니다!
질문 2를 읽고 저도 의문이 들어 24516 을 저장한 int 변수의 메모리를 확인해봤는데 c4 5f 00 00 이렇게 적재가 되어 있었습니다. 24516 은 16진수로 5fc4 입니다. 이것을 보아하니 값은 거꾸로 저장이 되나봐요. 그래서 메모리에 c4 5f 00 00 이렇게 저장이 되어 있다면 0x00005fc4 값이라고 읽는 것이 맞는 것 같습니다. 그래서 41 cc cc cc 는 0xcccccc41 이렇게 읽어야 하는 것 같아요. (덧붙여서 0xcccccc41은 십진수로 3,435,973,697입니다. 그래서 오버플로우가 발생해서 -858993599 값으로 나온 것 같네요)
질문 3. 이 부분은 저도 잘 모르겠습니다만 어떤 4byte 크기의 변수 값에 담겨져 넘겨진 것이 아니라 1byte짜리 'A' 리터럴만 넘겨진거니까 1byte만 출력된게 아닐까 싶네요.
0
0
질문 1,2 번 답변
이해가 잘 됐습니다!
관련해서 마지막 질문이 될 것 같은데,
int c;
char d;
scanf("%c %c", &c, &d);
printf("%d %d", c, d);
위 코드에서, int c 는 설명해주신 내용처럼, %d가 4bytes를 읽어오며 쓰레기 3bytes 까지 읽어와서 문제가 발생한다는 것을 알겠습니다.
char d 는 %d를 만나서도 정상출력 되었습니다.
그런데, char d의 경우에도, char d가 1byte만 차지하긴 하지만
%d를 만나 출력되면 4bytes를 읽어와서 d 에 할당되지 않은 뒤의 이상한 세 칸을 더 읽어오지 않는 이유는 무엇인가요?
변수의 자료형 char 이니까 그 뒷부분의 메모리는 읽어올 필요가 없다고 판단하는, 내부적인 과정이 있는건가요?
'로우한 부분'이라고 말씀 주신 것처럼... 문법 이외에도 메모리에 접근하셔서 명쾌하게 답변 해주신 것처럼 뭔가 내부적으로 돌아가는 것들을 공부하는 과목이 따로 있을까요? 비전공자로서 접할 수 있는 정보가 많지 않아 조금 궤를 달리하는 질문도 드려봅니다... 감사합니다!
0
감사합니다! 조금만 더 여쭙겠습니다 ㅠㅠ
int c;
char d;
scanf("%c %c", &c, &d); // int 형과 char 형 둘 다 'A' 를 입력받아보았습니다.
printf("\n");
printf("%d %d\n", c, d); // 결과는 각각 위 질문의 경우처럼 쓰레기 값과, 65 정상출력이 나왔습니다.
printf("%d", 0xcccccc41); // 출력문 1
printf("%d", 0x41cccccc); // 출력문 2
설명해주신 내용이 이해가 잘 되었으나, 더 궁금한 점이 생겼습니다.
위 코드를 실행한 후, 메모리를 조회해보니
답변 내용과 같음을 확인할 수 있었습니다.
질문 1. 여기서 int c 가 차지하는 부분은 41 cc cc cc 이고, char d가 차지하는 부분은 41 한칸인건가요?
질문 2. 코드 마지막의 출력문입니다. 답변해주신 내용대로라면 출력문 2에서 같은 결과가 나올 것 같은데, 출력문 1에서 위 질문의 쓰레기 값과 같은 값이 출력이 됩니다. 출력문도 그렇고, 밑의 창에서도 '값' 란에 41 cc cc cc 가 아닌 cc cc cc 41 로 표현이 됩니다.... 이 부분이 이해가 잘 가지 않습니다 ㅠㅠ
char d의 메모리에서는 0x41 한칸만 저장이 되고... 아주 혼동이 오고 있습니다 ㅠㅠ
질문 3. 이번에는 printf("%d", 'A'); 로 변수가 아닌 값을 직접 전달해봤습니다. 이 경우에는 1byte 를 4bytes 형태로 출력하는데도 위와 같은 쓰레기값 현상이 발생하지 않고 65가 잘 나왔습니다.
이 경우는 41 cc cc cc 를 읽어 오는 것과 다른 형태인건가요?
(질문 2의 내용처럼 41 cc cc cc / cc cc cc 41 둘중에 어떤 걸 읽어오는건지도 잘 모르지만 말입니다......)
뭔가 강의의 내용과 거리가 먼 부분을 자꾸 질문드리는 것 같은데 항상 친절하게 답해주셔서 그저 감사할 따름입니다 ㅠㅠ
0
scanf("%c", &c); 를 통해 int c 에 'A'를 입력했을 떄 메모리 모습입니다.
왜 65가 아닌 -858993599 라는 값이 들어있는걸까요? c의 주소를 통해 c 메모리를 들여다보겠습니다.
(한 칸 당 1byte입니다.)
int 는 4byte고 char은 1byte라는 것을 알고 계실겁니다.
c는 int 이기에 4 칸을 차지합니다.
int c 에 문자 'A'를 입력하면 위와 같이, 4 칸 중 앞에 있는 1 칸만 A 이며 나머지를 쓰레기 값인 것을 확인할 수 있습니다. (65를 16진수로 변환하면 41입니다. 즉 'A'의 아스키코드인 65나 마찬가지입니다.)
이렇게 int 에 문자(아스키코드)를 저장하면 4byte 공간 중에 1byte 공간에만 문자가 저장되는 것이 되어요. 나머지 3byte(3칸)은 쓰레기값입니다.
그래서 printf("%c, c)와 printf("%hhd, c)는 문제 없이 각각 'A'와 65가 잘 출력되었습니다. 왜냐면 %c, %hhd 즉, c의 1byte 부분만(앞에 한칸) 출력하는 것이기 떄문입니다.
반면 printf("%d, c) 는 4byte로 출력하고자하는 것입니다.
그래서 "A + 쓰레기 + 쓰레기 + 쓰레기" 이렇게 총 4칸이 총 합쳐진 값이 출력되었던거라 이상한 값이 나온 것입니다. 이 메모리 사진으로 보자면 16진수로 "41cccccc" 이렇게 4 칸이 출력되어 -858993599라는 값이 출력 된 것입니다.
결론적으로 말씀 드리자면 int a 변수에 'A' 문자를 넣었다면
a는 65 값을 가지게 되는 것이 아니라 "65 쓰레기 쓰레기 쓰레기" 이런 값을 가지게 됩니다. 4byte니까요!
0
항상 이해에 도움이 되는 답변 감사드립니다 ㅠㅠ 이번에도 큰 도움이 되었습니다.
답변 내용은 잘 이해했습니다!
제 질문 중 첫번째 경우,
scanf("%c", &c);
printf("%d", c);
printf("%c", c);
즉, 답변 주신 내용중 A가 int 형에 정수로 저장이 가능하다고 하신 부분에 대하여 다시 질문 드리고 싶어서 한번 더 글을 남깁니다!
위 경우에는 %c로 정상적으로 입력을 받았습니다.
출력의 결과는
%hhd : 65 정상 출력
%c : A 정상출력
%d : 이상한 값
의 결과가 나타납니다.
int 자료형, 즉 더 큰 풀에 들어있는 작은 자료형을 저장하는 것에도 문제가 없을 것 같고,
char d = 65;
printf("%d", d)
>> 65
가 정상출력 되듯 출력 과정에도 문제가 없을 것 같은데 어디서 문제가 생긴건지 알고 싶습니다!
읽어주시고, 도움주셔서 감사합니다.
0
안녕하세요!
테스트 하셨던 코드까지 그대로 주시면 제가 답변 드리는데 더 도움이 됩니다.
우선 이런식으로 테스트 해보신 것 같다고 이해했는데 맞으신가요? 이 코드에서 scanf 를 "%d" 로 입력 받느냐, "%c" 로 입력 받느냐에 따라 차이가 있었기 때문에 질문 주신 것으로 이해하고 답변 드리겠습니다.
scanf("%d",&c); 로 입력을 할 때 'A' 를 입력하셨다면 A 는 c 에 전혀 저장되지 않습니다. 아무것도 저장 안돼요!
"%d"의 의미는 scanf에게
"10진수의 숫자만 c에 입력할 수 있다! 10진수의 숫자만 c에 입력받고 10진수 숫자가 아닌 것은 걸러라" 라고 명령하는 일종의 지시문입니다.
문자도 아스키코드 정수로 저장되므로 'A'는 int 변수에 입력 될 수 있습니다. 가능합니다. 그러나 scanf의 %d 형태로 입력 받기로 했다면 A 는 입력 되지 못합니다. 10진수 정수가 아니기 때문입니다.
'A' 는 10진수 숫자가 아니기 때문에 c에 입력 되지 않습니다. scanf는 입력 버퍼에서 'A' 를 만나면 c에 입력하지 않고 그냥 지나갑니다. scanf도 리턴값이 있는데 전부 입력 실패라면 0을 리턴해요! 이 경우엔 scanf에 c에 입력하는 것을 실패했으니 0 을 리턴하겠습니다.
A를 입력했고 입력 버퍼에 A 가 들어갔는데, scanf는 "%d" 지시문으로 인해 10진수 숫자만 c 에 입력할 수 있으므로 이 'A' 문자를 무시하고 c에 입력하는 것을 포기합니다. 그러므로 scanf는 0 을 리턴했고 c에는 아무것도 입력되지 않아 이상한 쓰레기값이 출력되는 것을 확인할 수 있습니다.