해결된 질문
작성
·
120
1
안녕하세요. 14.4강 구조체의 배열 연습문제 풀이 중 궁금한 점이 생겨 질문 드립니다.
while(1) 코드 내에서 library[count].price의 값을 받을 때
int flag = scanf("%f",&library[count].price);
로 코드를 작성하셨는데요,
scanf를 통해 library[count].price 에 값이 들어왔는지 확인하기 위한 용도라면 위 코드 아래에
if(flag == NULL)
{
printf("가격이 입력되지 않았습니다.\n");
break;
}
뭐 이런 식으로 flag 값을 활용하는 부분이 있어야 의미가 있을 것 같은데.... 해당 코드에서는 flag로 scanf 값을 받은 의미가 없는 것 같아서요.
교수님께서 flag를 사용하신 의도가 뭔지, 제가 제시한 코드 외적으로 flag의 추가적인 용도가 있는건지, 아니면 습관적으로 저렇게 코드를 작성하신 건지 궁금합니다.
감사합니다.
답변 2
1
안녕하세요? 질문&답변 도우미 durams입니다.
말씀하신것처럼 flag
변수를 사용하는 부분은 없습니다. 대신 교수님께서는 scanf
의 반환값을 변수에 저장하지 않았을 때 인텔리센스가 발생시키는 경고를 보지 않기 위한 목적으로 이렇게 작성하신 것이 아닐까 싶네요.
그리고 약간 보충해드리자면, 값이 들어왔는지 확인하는 용도로 if (flag == NULL)
과 같이 작성하는 것은 적절하지 않을 수 있습니다. 본 예제는 구조체에 대해 학습하는 간단한 형태이기 때문에 예외처리에 대해 말씀드리는 것은 조금 범위를 벗어나는 감이 없지 않아 있습니다만, 몇 가지 주제에 대해서 말씀드릴게요.
NULL
은 void *
타입으로, 그 값은 0입니다. C에서 정수 값과 포인터 값을 바로 비교하는 것은 적절하지 않습니다. 컴파일러에 따라 동작이 달라질 수 있는 정의되지 않은 동작입니다. C에서는 코드에서 피연산자 간의 자료형을 맞춰주는 것이 무척 중요합니다. 현재 질문자님 컴퓨터에서 문제가 없다고 해도, 여러 machine에서도 동일하게 동작한다는 보장이 없어요.
포인터와 정수간의 안전한 형변환을 지원하는 uintptr_t
같은 자료형도 존재하니 흥미가 있으시다면 알아보셔도 좋을 것 같습니다.
NULL
을 정수 0, 즉 입력된 것이 없다는 의미로 쓰셨다고 해도 사실 적절치 않습니다. scanf
의 반환값을 정확히 말하자면 '포맷과 일치하는 입력을 성공적으로 받은 개수'입니다.
int x;
int cnt = scanf("%d", &x);
printf("%d\n", cnt);
위 코드를 실행해서 입력받을 때 수가 아니라 "abc"
이런 문자열을 입력하면 "%d
포맷과 일치하지 않기 때문에 cnt
는 0이 됩니다.
그렇다면 적절하지 않은 입력이 주어진 경우를 0으로 검사해야하나 싶지만, 그것도 아닙니다. scanf
는 포맷과 일치하지 않는 입력을 만나면 입력이 버퍼에 남은 채로 동작이 중단되기 때문입니다.
int x;
int cnt = scanf("%d %d", &x, &x);
printf("%d\n", cnt);
위 코드는 두 개의 정수를 입력받습니다. 첫 번째 입력으로 정수를 입력하고, 두 번째 입력으로 "abc"
를 입력한다면 첫 번째 입력만 정상적으로 되었기 때문에 cnt
는 1이 됩니다.
는 scanf
의 반환값을 EOF
매크로와 비교하는것이 적절하다고 생각됩니다. scanf
는 eof(파일의 끝)에 도달하게 되면 -1을 반환합니다. EOF
매크로는 여러 표준 입출력 함수에서 편리하게 사용할 수 있도록 -1 값으로 정의되어 있습니다.
위 내용들을 종합해서 강의 예제를 조금 더 보완해보시는 것도 좋은 공부가 되실 것 같습니다. 적절한 입력이 주어지지 않은 경우 제대로 입력하도록 다시 사용자에게 요구하는 방식으로 작성할 수도 있겠죠. (입력이 아예 주어지지 않은 경우와 적절한 입력이 주어지지 않은 경우를 구분하셔야 합니다)
더 궁금한 점이 있으시다면 질문주세요.
네, 인텔리센스(IntelliSense)는 비주얼 스튜디오에 내장된 기능 중 하나입니다. 코드 자동 완성, 정적 코드 분석 등의 기능을 제공합니다. 비주얼 스튜디오에서 코드를 작성을 하다가 초록색 밑줄(경고)나 빨간색 밑줄(에러)가 그이는 것을 가끔 보셨을 텐데, 이것이 인텔리센스에서 제공하는 오류 감지 덕분입니다. 이는 빌드 시 컴파일러가 발생시키는 에러 또는 경고와는 구분됩니다.
C 라이브러리의 많은 함수들, 특히 시스템 콜을 동반하는 함수들은 실패 시 예외 처리를 위해 특정한 값을 반환하는 경우가 많습니다. 예를 들어 scanf
의 경우는 eof 시 -1을 반환하죠. 그리고 C 언어는 그 반환값을 어딘가 변수에 저장하여 확인하거나, 즉시 조건문을 통해 값을 확인하도록 사용자에게 권장하는 경향이 있습니다. 방어적인 프로그래밍의 일환이죠.
gcc 컴파일러에서도 컴파일 옵션 중 이러한 경우를 모두 감지하여 warning을 띄운다거나, 모든 warning(경고)를 에러로 간주하는 옵션이 있는 등, C언어는 low level(특히 포인터&메모리 등)을 다루는 언어이니만큼 이러한 코드 작성 방식에 있어서도 방어적인 방식이 강조됩니다.
이런 종류의 '경고'는 컴파일러에서 빌드 시 띄워줄 수도 있지만, 그런 기능이 인텔리센스에 탑재되어있다고 생각하시면 될 것 같습니다. 빌드하기도 전에 사용자에게 알려주는, 무척 친절한 기능이라고 볼 수 있습니다.
여담으로, 에러 또는 경고 발생 시 아래와 같이 드롭다운 메뉴를 열어 빌드 시에 발생한 것인지 또는 인텔리센스가 발생시킨 것인지 그 출처를 구분하여 조회할 수 있으니, 둘이 동시에 떠 있더라도 구분은 어렵지 않습니다.
1
안녕하세요, 인프런 AI 인턴입니다.
새싹비빔밥님께서 질문하신 사항에 대해 설명드리겠습니다. C 언어에서 scanf
함수는 입력된 데이터의 성공적인 변환과 할당을 체크하기 위해 반환값을 사용합니다. scanf
함수는 성공적으로 읽어 들인 데이터의 수를 반환합니다. 그렇게 때문에, scanf
가 성공적으로 데이터를 읽어 들였는지를 확인하려면 반환값을 체크해야 합니다.
예를 들어, scanf("%f", &library[count].price)
가 실행될 때, 반환값은 읽어 들인 데이터의 개수입니다. 만약 입력이 실패하게 되면, scanf
는 0을 반환하게 됩니다. 이 반환값을 flag
변수에 저장함으로써 입력이 성공했는지 실패했는지를 체크할 수 있습니다.
만약 flag를 통해 입력이 정상적으로 이루어졌는지를 확인하고자 한다면 다음과 같이 활용할 수 있습니다:
int flag = scanf("%f",&library[count].price);
if(flag != 1) {
printf("가격이 입력되지 않았습니다.\n");
break;
}
위 코드에서 flag != 1
은 scanf
가 데이터를 정상적으로 입력받지 못했을 때 발생하는 상황을 체크합니다. 이와 같이 반환값을 활용하면 입력 검증이나 반복문 제어에 도움이 될 수 있습니다.
관련된 과거 질문으로 다음의 링크들을 참고하실 수 있습니다:
- “7.11 최대,최소,평균 구하기 예제”: scanf
함수의 반환 값에 대해 설명한 예시입니다.
- “scanf질문이요”: scanf
의 결과값 체크에 대한 다른 예시입니다.
저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다. 현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏 추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.
세세한 답변 감사합니다! 값이 입력되지 않은 경우(혹은 올바른 값이 입력되지 않은 경우) NULL과 비교하는 것은 부적절하다는 점 확실히 알게 되었습니다.
다만 위에서 설명해주신 부분 중 교수님이 flag를 활용하신 이유를 "
scanf
의 반환값을 변수에 저장하지 않았을 때 인텔리센스가 발생시키는 경고를 보지 않기 위한 목적"이라고 예상하셨는데, 이에 대해서도 조금 더 설명해주실 수 있나요? 비주얼스튜디오 내에 내장된 프로그램인가요?