|
|
[21 문자와 문자열 관련 함수]
// [21-1]
// 1) 스트림과 버퍼의 역할을 각각 설명하시오.
// 스트림: 프로그램과 입출력 장치 간 데이터 이동을 위한 소프트웨어적인 경로
// 버퍼: 스트림 내부에 포함되어 운영체제가 관리하며 운영체제의 설정에 따라 버퍼의 사용 여부가 결정된다.
// 프로그램과 입출력 장치 사이에서 데이터를 임시로 저징하는 물리적인 메모리 공간이다.
// 2) 버퍼의 장점과 단점을 모두 설명하시오.
// 실시간으로 입력되는 데이터를 순차적으로 모아 저장 후 한번에 전송할 데이터의 크기를 정해 전송하면 빠르고
// 입력 데이터의 크기를 규격화시킬 수 있다. 또한 전송 전 데이터의 수정이 가능하다.
// 그러나 버퍼는 별도의 메모리 공간이 필요하며, 데이터를 모아 처리하기 때문에 데이터의 전송이 지연될 수 있고,
// 버퍼의 크기보다 많은 데이터가 입력될 경우 버퍼 오버플로우가 발생해 오류의 원인이 된다.
// 3) 입력 버퍼에 데이터가 이미 존재할 때 scanf함수를 호출한다면 어떻게 동작하는지 설명하시오.
// 입력 버퍼에 있는 데이터를 scanf함수가 바로 읽어들여 의도하지 않은 데이터가 저장되거나 동작이 생략되어 오동작할 수 있다.
// 4) 운영체제가 어떤 경우에 출력 버퍼의 데이터를 모니터로 출력하는지 설명하시오.
// 운영체제가 유휴 상태일 때 출력 버퍼에 데이터가 존재하면 출력한다.
// 5) scanf함수와 printf함수 실행 시 함수와 운영체제의 역할분담에 대하여 설명하라.
// 먼저 운영체제가 데이터를 입력 버퍼에 전달해주면, scanf함수는 입력 버퍼의 데이터를 읽어온다.
// printf함수는 출력 데이터를 출력 버퍼에 전달해주면, 운영체제가 유휴 상태가 되었을 때 출력 버퍼의 데이터를 모니터에 출력해준다.
// 6) 키보드로부터 문자를 입력 받아 화면에 출력해주는 프로그램을 작성하시오. 'q' 또는 'Q'로 종료한다.
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:6031)
#include <stdio.h>
int main(void) {
char ch;
while (1) {
char ch;
printf("문자입력 : ");
scanf(" %c", &ch);
if (ch == 'q' || ch == 'Q') break;
printf("입력된 문자는 %c\n", ch);
}
}
// 7) printf()는 입력 버퍼에서 엔터키를 남겨놓기 때문에 문자를 입력받을 때 입력 버퍼에 엔터키가 남아있을 경우
// 엔터기가 입력되어 코드가 바로 넘어가 정상작동하지 않는다 이를 방지하기 위해서는 %c 앞에 한 칸을 띄워 작성해
// 불필요한 문자가 있을 경우 무시하도록 한다.
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:6031)
#include <stdio.h>
int main(void) {
int x;
char name[10];
char blood_type;
printf("이름을 입력하시오: ");
scanf("%s", name);
printf("혈액형을 입력하시오: ");
scanf(" %c", &blood_type);
printf("이름: %s\n", name);
printf("혈액형: %c\n", blood_type);
}
// 8) 첫 번째 입력으로 문자열 "abcde"를 입력했을 때, 아래 코드의 실행결과를 자세히 설명하라.
// 먼저 문자열 "abcde"를 입력하면 for문이 5번 반복하면서 입력 버퍼의 문자를 하나씩 받아가는데
// 이때 이미 문자 5개가 입력 버퍼에 존재하므로 추가적인 입력 대기 없이 5번이 반복되어 한번의 입력 후
// for 문을 빠져나가게 되어 결과 출력 후 프로그램이 종료된다.
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:6031)
#include <stdio.h>
int main(void) {
char ch;
int i;
for (i = 0; i < 5; i++) {
printf("문자 입력:");
scanf("%c", &ch);
printf("문자: %c\n", ch);
}
}
// 9) 문자열을 라인 단위로 모두 읽어 저장하는 코드를 작성하시오.
#pragma warning(disable:6031)
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main(void) {
char str[20], ch;
int i = 0;
printf("문자열을 입력하시오: ");
while (1) {
scanf("%c", &ch);
if (ch == '\n' || i >= 19) break;
str[i++] = ch;
}
str[i] = '\0';
printf("입력한 문자열: %s\n", str);
return 0;
}
// [21-2]
// 1) 표준 입출력 스트림을 접근하는 방법을 설명하라
// 표준 입출력 스트림의 주소는 stdin, stdout, stdarr 이며 자료형은 FILE* 로 표준 입출력 장치를 가리키는 포인터이다.
// 2) 공백을 포함한 문자열을 입력 받을 때 사용가능한 함수는 무엇인가
// 공백을 포함한 문자열을 입력받는 함수는 gets()와 fgets()가 있다.
// 3) gets 함수사용시 가장 큰 문제점은 무엇인가
// 입력데이터의 최대 크기를 지정해줄 수 없어 데이터를 저장할 메모리보다 큰 데이터가 입력되도 모두 저장하려고 시도하여 실행오류가 발생한다.
// 4) fgets 함수 사용시 문제점은 무엇인가
// 입력 버퍼에 있는 엔터키까지 저장한 후 널 문자를 추가하기 때문에 문자열 출력 시 원치않는 줄바꿈이 일어날 수 있다.
// 5) 널문자 ('\0') 와 널포인터 (NULL)의 용도를 설명하시오
// 널문자는 문자열의 끝에 위치하여 문자열의 끝을 알려주는 문자로 아무것도 의미하지 않는 문자이고,
// 널포인터는 아무것도 가리키지 않는 포인터에 저장되어 아무것도 가리키지 않는 포인터(주소)이다.
// 6) 문자 입출력 전용함수만 사용해서 키보드로부터 문자를 입력 받아
// 화면에 출력해주는 프로그램을 작성하시오. 'q' 또는 'Q'로 종료한다.
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:6031)
#include <stdio.h>
int main(void) {
char ch;
while (1) {
printf("문자입력 : ");
ch = getchar();
getchar();
if (ch == 'q' || ch == 'Q') break;
printf("입력된 문자는 %c\n", ch);
}
}
// 7) 문자열 입출력 전용함수만 사용해서 이름과 주소, 차번호를 저장 후 출력하는 프로그램을 작성하시오.
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:6031)
#include <stdio.h>
int main(void) {
char name[20], add[20], num[20];
printf("이름:");
fgets(name, sizeof(name), stdin);
printf("주소:");
fgets(add, sizeof(add), stdin);
printf("자동차번호:");
fgets(num, sizeof(num), stdin);
printf("<결과출력>\n");
printf("이름: %s", name);
printf("주소: %s", add);
printf("자동차번호: %s", num);
}
// 8) fgets함수로 입력받은 후 배열의 끝에 있는 엔터를 널문자로 변경하는 프로그램을 작성하시오.
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:6031)
#include <stdio.h>
int main(void) {
char str[20];
int i = 0;
printf("문자열 입력:");
fgets(str, sizeof(str), stdin);
while (str[i] != '\0') {
if (str[i] == '\n') {
str[i] = '\0';
break;
}
i++;
}
printf("%s", str);
}
// 9) 공백을 포함하는 문자를 입력 받아 입력받은 단어의 수를 계산하여 출력하는 프로그램을 작성하시오.
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:6031)
#include <stdio.h>
int main(void) {
char str[30];
int i = 0, cnt = 0, isspace = 0;
printf("문자열 입력:");
fgets(str, sizeof(str), stdin);
while (str[i] != '\0') {
if (str[i] == ' ') {
isspace = 1;
}
else if (str[i] != '\n' && isspace == 1) {
cnt++;
isspace = 0;
}
i++;
}
printf("단어수 : %d", cnt + 1);
}
// [21-3]
// 1) 반복해서 키보드로부터 문자열을 입력 받아 이전문자열에 연결하여 화면에 출력해주는 프로그램을 작성하시오.
// quit을 입력받아 프로그램을 중단한다.
#include <stdio.h>
#include <string.h>
int main(void) {
char input[20], output[100] = "";
while (1) {
printf("문자열 입력 : ");
fgets(input, sizeof(input), stdin);
if (strcmp(input, "quit\n") == 0)
break;
for (int i = 0; input[i] != '\0'; i++) {
if (input[i] == '\n') {
input[i] = ' ';
break;
}
}
if (strlen(output) + strlen(input) < sizeof(output)) {
strcat(output, input);
printf("누적된 문자열: %s\n", output);
}
else {
printf("문자열 길이 초과!");
return 0;
}
}
}
// 2) strlen함수를 구현하시오.
#include <stdio.h>
int my_strlen(char* str);
void removeBSN(char* str);
int main(void) {
char str[20];
printf("문자열 입력 : ");
fgets(str, sizeof(str), stdin);
printf("길이 : %d, 내용 : %s\n", my_strlen(str), str);
removeBSN(str);
printf("길이 : %d, 내용 : %s\n", my_strlen(str), str);
return 0;
}
int my_strlen(char* str) {
int i = 0;
while (str[i] != '\0') { i++; }
return i;
}
void removeBSN(char* str) {
int i = 0;
while (str[i] != '\0') {
if (str[i] == '\n') { str[i] = '\0'; break;}
i++;
}
}
// 3) strcpy함수를 구현하시오.
#include <stdio.h>
void my_strcpy(char* note, char* data);
int main(void) {
char str1[20] = "1234567890";
char str2[20];
my_strcpy(str2, str1);
puts(str2);
return 0;
}
void my_strcpy(char* note, char* data) {
int i = -1;
while (data[++i] != '\0') {
note[i] = data[i];
}
note[i] = '\0';
}
// 4) strcat함수를 구현하시오.
#include <stdio.h>
void my_strcat(char* note, char* data);
int main(void) {
char str1[20] = "First~";
char str2[20] = "Second";
my_strcat(str1, str2);
puts(str1);
return 0;
}
void my_strcat(char* note, char* data) {
int i = -1, j = 0;
while (note[++i] != '\0') {}
while (data[j] != '\0') {
note[i] = data[j];
i++;
j++;
}
note[i] = '\0';
}
// 5) strcmp함수를 이용하여 문자열의 대소를 구분해 최대 최소 문자열을 출력하시오.
#include <stdio.h>
#include <string.h>
int main(void) {
char str[5][20];
int first = 0, last = 0;
int i;
for (i = 0; i < 5; i++) {
printf("문자열 입력 : ");
fgets(str[i], sizeof(str[i]), stdin);
str[i][strcspn(str[i], "\n")] = '\0';
if (i > 0) {
if (strcmp(str[i], str[first]) < 0) first = i;
if (strcmp(str[i], str[last]) > 0) last = i;
}
}
printf("제일 앞 : %s\n", str[first]);
printf("제일 뒤 : %s\n", str[last]);
return 0;
}
// 6) 문자열을 입력받아 그 안에 존재하는 숫자의 총 함을 계산해서 출력하는 프로그램을 작성하시오.
#include <stdio.h>
int main(void) {
char str[20];
int i = -1, sum = 0;
printf("문자열 입력 : ");
fgets(str, sizeof(str), stdin);
while (str[++i] != '\0') {
if (str[i] >= '1' && str[i] <= '9')
sum += (str[i] - '0');
}
printf("문자열 내 숫자의 합은 %d", sum);
return 0;
}
// 7) 문자열을 담는 배열 3개를 선언한 후 fgets함수를 이용하여 문자열 2개를 입력받은 후
// 다른 하나의 배열에 둘을 이어붙인 문자열을 저장하는 프로그램을 작성하시오.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
void removeBSN(char* str);
int main(void) {
char str1[20];
char str2[20];
char str3[40] = "";
printf("문자열 입력 : ");
fgets(str1, sizeof(str1), stdin);
printf("문자열 입력 : ");
fgets(str2, sizeof(str2), stdin);
removeBSN(str1);
removeBSN(str2);
strcpy(str3, str1);
strcat(str3, str2);
printf("%s", str3);
}
void removeBSN(char* str) {
int i = -1;
while (str[++i] != '\0') {
if (str[i] == '\n') { str[i] = '\0'; break; }
}
}
// 8) 데이터를 입력 받을 때 여러 사람의 이름과 나이를 이름 나이 와 같은 형식으로 입력받고, 각 사람은 개행문자로 분리하여
// 한꺼번에 입력 받을 때 두 사람의 정보를 입력 받아 이름과 나이가 각각 같은지 아닌지를 판단하여 출력하는 프로그램을 작성하시오.
#include <stdio.h>
#include <string.h>
void split(char* str, char* name, char* age);
int main(void) {
char str1[20], str2[20];
char name1[10], name2[10];
char age1[3], age2[3];
fgets(str1, sizeof(str1), stdin);
fgets(str2, sizeof(str2), stdin);
split(str1, name1, age1);
split(str2, name2, age2);
printf("두 사람은 이름이 ");
if (strcmp(name1, name2)) printf("같지 않고, ");
else printf("같고, ");
printf("나이가 ");
if (strcmp(age1, age2)) printf("같지 않습니다.");
else printf("같습니다.");
}
void split(char* str, char* name, char* age) {
int i = 0, j = 0;
while (str[i] != ' ' && str[i] != '\n' && str[i] != '\0')
name[i] = str[i++];
name[i] = '\0';
i++;
while (str[i] >= '0' && str[i] <= '9')
age[j++] = str[i++];
age[j] = '\0';
}
// [21장 정리문제]
// 1) 문자는 컴퓨터에서 어떻게 저장되는가
// 문자는 아스키 코드(ASCII)와 같은 문자 코드값으로 변환되어 이진수 형태로 메모리에 저장된다.
// 2) 문자 입력함수를 아는 대로 설명하라
// scanf("%c", &ch) : 문자 1개 입력, 공백·엔터도 입력으로 처리
// getchar() : 표준 입력에서 문자 1개를 읽음
// fgetc(stdin) : 파일 또는 표준 입력에서 문자 1개 입력
// 3) 문자 출력함수를 아는 대로 설명하라
// printf("%c", ch) : 문자 출력
// putchar(ch) : 문자 1개 출력
// fputc(ch, stdout) : 파일 또는 표준 출력으로 문자 출력
// 4) 다음 문장을 실행할 때 문제점을 설명하라
// scanf("%d", &num);
// scanf("%c", &ch);
// 첫 번째 scanf에서 입력한 엔터키(\n)가 입력 버퍼에 남아 두 번째 scanf("%c")가 의도하지 않은 엔터를 입력받는다.
// 5) 4 번의 해결방법을 설명하라
// 문자 입력 전에 버퍼에 남아 있는 엔터를 제거하거나 %c 앞에 스페이스바를 추가해 엔터를 의도적으로 입력받지 않게 한다
// 6) 널문자의 역할을 설명하시오.
// 널 문자는 문자열의 끝에 위치하여 문자열의 끝임을 알려주는 문자로, 아무 의미를 가지지 않는 문자이다.
// 7) 널문자를 자동으로 저장해주는 경우를 설명하라
// "(문자열)" 의 형태로 배열에 초기할 때나 문자열 입력 함수들은 입력을 끝낸 후 자동으로 '\0'을 넣어 저장한다.
// 8) scanf 함수로 문자열을 입력 받을 때 종료문자는 무엇인가?
// 공백, 엔터, 탭과 같은 공백 문자이다.
// 9) gets 함수로 문자열을 입력 받을 때 종료문자는 무엇인가?
// 엔터문자('\n') 이다.
// 10) scanf 와 gets 함수의 차이점을 설명하시오
// scanf 함수는 모든 공백문자를 종료문자로 지정되어있지만, gsts함수는 엔터함수만을 종료문자로 받는다.
// 또한 scanf 함수는 버퍼의 크기를 제한할 수 있지만 gets함수는 불가능해 안전성이 떨어진다.
// 11) 문자열 출력함수를 설명하라
// 문자열 전용 출력함수는 puts(), fputs()가 있다.
// 먼저 puts는 문자열의 포인터를 받아 문자열 출력 후 줄바꿈을 해주고
// fputs는 문자열의 포인터, 출력 스트림을 받아 출력 스트림에 문자열만 출력해준다.
// 또한 두 함수 모두 동작이 정상적으로 완료되면 0이 아닌 값이, 실패하면 EOF(-1)이 반환된다.
// 12) C 표준라이브러리 함수인 strcpy , strlen , strcat 과 똑같은 기능을 갖는 함수를 작성하고 활용하라
// [21-3] 1~3번 예제와 동일
// 13) 문자열 저장시 아래 2 문장 모두 가능하다 . 2 가지방법의 차이를 설명하라
// char str[20] = "apple";
// char *p = "pineapple";
// 배열에 저장하는 방법은 메모리공간을 미리 확보하고 그 후 초기화하는 방식으로 이후 문자열을 편집하거나
// 바꿀 수 있다. 그러나 두 번째 방법은 읽기 전용 메모리에 문자열을 먼저 할당하고 그 메모리 공간의
// 첫 번째 주소를 저장하는 것으로 읽기 전용 메모리에 저장되는 데이터는 모두 상수이기 때문에
// 다른 주소를 가리키도록 재할당은 가능하지만 문자열의 일부를 바꾸거나 변경할 수는 없다.
|
|

첫댓글 함수의 매개변수에 이중포인터를 사용해야하는 경우를 설명해보시오
함수의 매개변수에 이중포인터를 사용해야 하는 경우는 2차원 배열을 인자로 받아 인자의 값을 변경해야 하는 경우 2차원 배열의 주소를 담는 포인터는 이중 포인터이므로 이중 포인터를 사용해야 하고, 포인터를 인자로 받아 포인터가 가리키는 변수를 변경해야 할 경우 포인터에 저장되어있는 주소(값)을 변경해야 하기 때문에 포인터의 주소에 의한 호출, 즉 이중포인터를 매개변수로 사용하여 포인터의 주소를 인자값으로 전달받아야 한다.