인프런 커뮤니티 질문&답변

최윤성님의 프로필 이미지
최윤성

작성한 질문수

C 프로그래밍 - 입문부터 게임 개발까지

프로젝트(후반전)

마지막 질문이 되길 바라며~~~ㅜㅠ 죄송함다 선생님~~

작성

·

513

0

1. 선생님~~~

한글로 비밀번호를 입력할 때 말구요. 그냥 저 cmd(라고해야하나..)에서 한글을 입력할 때의 상황인데요.

선생님께서는 입력 순간마다 바로 글자가 표시가 되는데, 저는 한글자를 다 입력하고나서, 다음 글자를 입력시작해야만 전 글자가 표시가 되요.

밑에 비교 영상을 링크로 첨부할테니 꼭 좀 봐주세요~~

1) 선생님

https://drive.google.com/open?id=187LKSdpoWDkxE31c7s3JJnhhxDGMQpyi

2) 저

https://drive.google.com/open?id=1l0rPhEGufVORw9SzpKYbXjeTrn7PTi10

2. 백스페이스바는 잘 해결했습니다.

3. 엔터(줄바꿈)입력에 대해서....

선생님께서 첨부해주신 예제코드는 아주 잘 실행되고, 줄바꿈또한 잘 입력이 됐음을 확인했습니다.

그리고 나서 선생님께서 말씀해주신대로 scanf를 scanf_s로 바꿔서 실행해봤는데요.

(비밀번호 틀린 횟수 검사를 코드로 한번 추가해봤습니다. ㅎㅎ)

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#define max 500

// 비밀번호를 입력받아서
// 맞는 경우? 일기를 읽어와서 보여주고, 계속 작성할 수 있도록 합니다.
// 틀린 경우? 경고 메시지를 표시하고, 종료합니다.

int main()
{
	char line[max]; // 불러오기를 했을 때, 불러올 내용이 저장된 배열(줄).
	char contents[max]; // 일기장에 입력하고 저장할 내용.
	char password[20]; // 비밀번호
	int c; // getch 함수의 리턴값(문자 하나하나가 아스키코드값으로 바뀌어 저장된다.)을 검사할 변수.

	printf("'비밀일기'에 오신 것을 환영합니다.\n");
	printf("비밀번호를 입력하세요. : ");



	int n = 0; // 비밀번호 오류 횟수 검사 변수.

	while (1) { // 비밀번호 오류 횟수 검사를 확인 후, 일기를 쓸 수 있도록.
		if (n == 3) {
			printf("\n==== 비밀번호를 %d회 틀렸어요. ====\n", n);
			printf("==== 비밀일기를 종료합니다. ====\n\n");
			break;
		}
		// 비밀번호 입력 알고리즘
		int i = 0; // 비밀번호 배열의 순서를 의미하는 변수
		while (1) {
			c = getch(); // 입력한 문자들이 getch로 바로바로 입력이 되어, 한 글자씩 변수 c에 저장된다.
			if (c == 13) { // (Enter의 아스키코드가 13이다.) 입력한 문자가 Enter(줄바꿈 : \n)라면. -> 비밀번호 입력 종료를 위한 조건식.
				password[i] = '\0'; // i번째에 데이터를 널문자(끝낼수 있도록)를 넣는다.
				break; // 비밀번호 입력 종료. (반복문 탈출)
			}
			else if (c == 8) { // (백스페이스바의 아스키코드가 8이다.) 백스페이스바를 입력하면, 즉 비밀번호를 지우면
				if (i >= 1) { // 두번째 이상의 위치에 커서 있을 때 백스페이스바를 입력할 때.
					password[i - 1] = '\0'; /*i번째에서 커서거 있고, 그 위치에서 Backspace를 입력하는 것이니,
						그 전 자리인 'i-1'번째 자리의 데이터를 지워야한다.*/
					printf("\b \b"); /*\b는 현재 데이터를 입력하는 위치에서 왼쪽(전)으로 커서를 이동시켜주는 변환문자.
					그러니, 왼쪽으로 한번 커서 이동후에, 스페이스바를 입력하여 빈칸이 되게 만들어주고, 스페이스바를 입력했으니 다시한번 뒤로 커서가 이동해야한다.*/
					//printf("\b");
					//printf(" ");
					//printf("\b");	요렇게 따로 써주어도 될 듯하다.
					i -= 2;
				}
				else {
					i--; /*커서가 첫번째 위치에 있을 때, 즉 i=0일 때, 백스페이스바를 입력하면, 지울 데이터는 없으니 아무것도 하지 않고,
					키를 하나 입력할 때마다, i++로 반복문이 반복되니, 백스페이스바를 입력해도 배열이 앞자리로 이동하지 않도록, i--를 해준다.*/
				}
			}
			else { // Enter와 백스페이스바 둘 다 아니라면.
				password[i] = c; // getch를 써서 계속 입력하여 c에 저장된 글자들이 password 배열에 저장된다.
				printf("*"); // 입력할 때마다, 비밀번호는 감추고, 대신 '*' 요놈을 출력할 것이다.
			}
			i++;
		}
		printf("\n\n==== 비밀번호 확인 중.... ====\n");

		// 1. 비밀번호가 맞다면, 일기를 작성하자. (strcmp는 문자열 함수를 보면 복습할 수 있다.)
		if (strcmp(password, "skehzheld") == 0) {
			printf("==== 비밀번호 확인 완료 ====\n\n");

			// 파일 선언. (비밀번호가 맞아야지만 파일이 생성될테니까 여기에 배치).
			char* fileName = "c:\\Users\\최윤성\\Desktop\\비밀일기.txt";
			FILE* file = fopen(fileName, "a+b");  /*"a+b"는 파일이 없으면 생성하고, 있으면 append(뒤로 내용을 추가)한다는 의미.
				내용 추가가 아니라, 내용 수정을 원한다면 저 뒤의 매개변수를 어떻게 바꿀까?*/

			// 파일 열기.
			if (file == NULL) {
				printf("*****파일 열기 실패*****\n\n");
				return 1;
			}
			else printf("*****파일 열기 성공*****\n\n");

			printf("------------------------오늘의 일기--------------------------\n\n");

			// 여기서부터 이전 일기 출력.
			while (fgets(line, max, file) != NULL) { // 저장된 파일을 불러온다.
				printf("%s", line); // 불러왔으면 출력한다.
			}  // 처음 쓰면 아무것도 불러올 것이 없을 것이고, 쓴 문장이 있었다면, 썼던 문장들이 불러오게 될 것이다.

			printf("\n┗  여기까지가 이전 일기..\n내용을 계속 작성하세요. 종료하시려면 마지막 줄에 \"fin\"을 입력하세요. ┒\n\n");

			// 여기서부터 새로운 (추가)일기 입력 후, 저장하고 끝내기
			while (1) {
				scanf_s("%[^\n]", contents, max); // 줄바꿈(\n)이 나오기 전까지, 모든 문자열을 다 입력한다 뜻의 변환 문자이다. 즉, 한 문장씩 저장을 하겠다는 의미.
				getchar(); // scanf를 사용하기 위해 버퍼에 저장되어 있던 '\n'을 버림처리 한다.
				if (strcmp(contents, "fin") == 0) { // 일기 입력 끝.
					printf("---------------------오늘의 일기 : 끝------------------------\n\n");
					break;
				}
				// 무한반복이니, scanf로 입력하는 모든 문장들은 "fin"이 나오기 전까지, 한 문장씩 전부 기억한다.
				fputs(contents, file); // 그 한 문장 한 문장을 바로바로 저장한다.
				fputs("\n", file);  // 줄바꿈까지 저장한다. 그리고는 "fin"을 입력하여 종료되기 전까지 계속반복.
			}

			//// 잘 저장되어 있는지 출력해서 검사해보자.
			//while (fgets(line, max, file) != NULL) {
			//	printf("%s", line);
			//} // ?? 왜 안되지??

			// 파일 닫기.
			int res = fclose(file); // 파일 닫기 함수 리턴값 검사를 위한 변수.
			if (res != 0) {
				printf("*****파일 닫기 실패*****\n\n");
				return 1;
			}
			else printf("*****파일 닫기 성공*****\n\n"); // 결국 파일이 종료된다. 파일 닫기.

			break; // 비밀번호가 맞았으니, 여기까지 수행한 후, 비밀번호 오류검사 횟수 반복문을 탈출하여 끝낸다.
		}

		// 2. 비밀번호가 틀리다면. 다시 한번 기회를 줘보자....
		else {
			n++;
			if (n <= 2) {
				printf("\n==== 비밀번호를 %d회 틀렸어요. ====\n", n);
				printf("==== 비밀번호를 다시 입력하세요. ====\n\n");
				printf("비밀번호를 입력하세요 : ");
			}
			continue; // 비밀번호가 틀렸으니, 조건문을 처음부터 다시 실행.
		}
	}

	return 0;
}

여기까지가 현 상황입니다.

부탁드림돠 선생님~~~~~~

(열심히 배우려다보니 선생님께 폐를 끼치게 되네요;;)

답변 8

0

최윤성님의 프로필 이미지
최윤성
질문자

아 죄송합니다. 맨 아랫줄의 fputs를 if절 위에 써버렸네요;;; ㅎㅎㅎ

해결됐습니다. ㅎㅎㅎ

캄사합니드아아~~~

0

나도코딩님의 프로필 이미지
나도코딩
지식공유자

EXIT 일 때는 printf 를 통해 종료 구문 출력을 하고 break 를 하여 while 문을 탈출하도록 코드를 드렸는데요, 그렇다면 아래에 있는 fputs 를 안타서 EXIT 가 안찍혀야 정상인데.. 코드는 제가 드린것과 동일하게 작성하셨나요? 여기에 적어주시면 확인 도와드리겠습니다. ^^

0

최윤성님의 프로필 이미지
최윤성
질문자

오우~~~선생님~~~~ 정말 죄송한데 마지막 한번만 귀찮게 할게요~~~~  ㅠㅜ

선생님께서 가르쳐주신 strncmp(.....) 부분이요.

마지막에 EXIT를 입력하니깐 종료가 되는데, 자세히 확인하니까, 일기에 EXIT가 같이 입력이 되서 저장이 되더라구요.

EXIT를 같이 저장하지 않게 하려면 어찌해야 할까요??

0

나도코딩님의 프로필 이미지
나도코딩
지식공유자

수강완료를 진심으로 축하드립니다 ^^

0

최윤성님의 프로필 이미지
최윤성
질문자

아아 fgets("\n", file);을 왜 추가로 안쓰는지 이미 알고있었는데,

거기까진 생각이 미치진 못했어요;; ㅎㅎ

감사합니드아아~~~~~ 아주 감사히 공부했습니다~~

0

나도코딩님의 프로필 이미지
나도코딩
지식공유자

좋은 소식이네요 ^^ 공부하시는 과정에서 이런 시행착오가 분명 큰 도움이 되실 겁니다.

변경된 코드에서는 줄 단위로 문자열을 입력받고 비교하는데, EXIT₩n 와 같이 맨뒤에 줄바꿈이 포함되어 하나의 문자열이 된답니다. 그래서 EXIT 란 문자열과 비교하면 맨 뒷부분 때문에 동일하지 않게 되지요. 그 때문에 문자열 전체를 비교하지 말고 길이를 제한하여 4글자만 비교하도록 한 것이랍니다. 길이 제한하여 문자열을 비교하는데에 사용되는 함수가 strncmp 랍니다.

고생하셨습니다^^

0

최윤성님의 프로필 이미지
최윤성
질문자

선생님~감사합니드아~~ 다해결 됐어요 ㅎㅎ

질문 마지막하나만 더 할게요

strncmp는 되고 strcmp로는 안되는 이유가 뭔가용??

(strcmp로도 해봤는데 안되는군요 ㅎㅎ)

0

나도코딩님의 프로필 이미지
나도코딩
지식공유자

안녕하세요 ^^

저런, 제가 질문을 잘못 이해하고 있었군요?

1. cmd 창 (명령 프롬프트) 에서 한글 입력할 때의 상황이라면, 더더욱 신경쓰실 필요가 없답니다. 이는 소스코드와 아무런 관련이 없으니까요 ^^ 제가 강의를 녹화할 당시 Win7 이었고 지금은 Win10 을 사용중인데요, 제가 직접 테스트 해보니 질문자분과 동일하게 한 글자가 완성되고 나서야 뿅 하고 나타나네요. 다시 말씀드리지만 이 부분은 질문자분의 소스코드에 어떤 잘못이 있다거나 한 것은 전혀 아니며 윈도우의 cmd 프로그램 자체에서 그렇게 동작하는 것이니 아무 걱정 마시고 지나치셔도 됩니다 ^^

2. 해결하셨다니 다행이네요.

3. 엔터 관련하여.. 이전에 드린 예제 코드가 잘 된다니 반가운 소식이군요.

fgets / fputs 도 C 에서 입출력을 위해 사용할 수 있는데요, 이를 활용하여 우리 코드를 좀 바꿔 보겠습니다.

while(1) { ... } 부분의 내용을 주석 처리 하시고 아래 코드로 바꿔보실까요?

while (1)
{
	fgets(contents, sizeof(contents), stdin);
	if (strncmp(contents, "EXIT", 4) == 0) // EXIT뒤에 줄바꿈까지 포함되므로, EXIT 길이만큼 4까지만 비교한다는 의미
	{
		printf("비밀일기 입력을 종료합니다\n\n");
		break;
	}
	fputs(contents, file);
}

scanf 대신 fgets 를 통해 contents 에 입력을 받도록 하였으며 이는 줄단위로 입력을 받게 됩니다. 즉 엔터를 치면 다음 라인으로 넘어가게 됩니다. 여기서 EXIT 를 입력했는지 비교하여 종료 여부를 결정하구요, EXIT 가 아닌 경우 fputs 를 통해 파일에 내용을 작성하게 된답니다. 단, strcmp 가 아닌 strncmp 를 쓴 부분만 유의해주시면 되겠습니다.

이 방법으로 성공하면 좋겠군요. 잘 안되신다면 또 글 남겨주세요.

참고로 프로그래밍에 한 가지 방법만 있는 것은 절!대! 아니므로 꼭 강의에 쓰인 코드만을 사용하실 필요는 없습니다 ^^ 

감사합니다.

최윤성님의 프로필 이미지
최윤성

작성한 질문수

질문하기