|
|
[24 파일 입출력]
// [24-1]
// 1) 복사할 파일명과 복사받을 파일명을 입력받아 텍스트파일을 복사하는 프로그램을 작성하라.
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:6031)
#include <stdio.h>
int main(void) {
char src[100], dest[100];
FILE *fp1, *fp2;
char ch;
printf("복사할 파일명: ");
scanf("%s", src);
printf("저장할 파일명: ");
scanf("%s", dest);
fp1 = fopen(src, "r");
fp2 = fopen(dest, "w");
if (fp1 == NULL || fp2 == NULL) {
puts("파일 열기 실패");
return 1;
}
while ((ch = fgetc(fp1)) != EOF)
fputc(ch, fp2);
fclose(fp1);
fclose(fp2);
puts("파일 복사 완료");
return 0;
}
// 2) 프로젝트 폴더 내에 있는 텍스트 파일을 작성한 후 한줄씩 출력하는 프로그램을 작성하시오.
#include <stdio.h>
int main(void) {
FILE *fp = fopen("test.txt", "r");
char str[100];
if (fp == NULL) return 1;
while (fgets(str, sizeof(str), fp) != NULL)
printf("%s", str);
fclose(fp);
return 0;
}
// 3) 키보드로부터 문자열을 입력 받아 파일에 저장하는 프로그램을 작성하시오.
#include <stdio.h>
int main(void) {
FILE *fp = fopen("output.txt", "w");
char str[100];
printf("문자열 입력: ");
fgets(str, sizeof(str), stdin);
fputs(str, fp);
fclose(fp);
return 0;
}
// 4) 텍스트 파일의 내용을 1줄씩 줄바꿈하여 파일에 출력하는 프로그램을 작성하시오.
#include <stdio.h>
int main(void) {
FILE *in = fopen("output.txt", "r");
FILE *out = fopen("result.txt", "w");
char str[100];
while (fgets(str, sizeof(str), in) != NULL)
fprintf(out, "%s", str);
fclose(in);
fclose(out);
return 0;
}
// [24-2]
// 1) 키보드로부터 학생의 이름과 학번, 학점을 입력받아 변수에 저장하고 파일에 출력하는 프로그램을 작성하시오.
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:6031)
#include <stdio.h>
struct Student {
char name[20];
int id;
float grade;
};
int main(void) {
struct Student s;
FILE *fp = fopen("student.txt", "w");
if (fp == NULL) {
puts("파일 열기 실패");
return 1;
}
printf("이름 학번 학점 입력: ");
scanf("%s %d %f", s.name, &s.id, &s.grade);
fprintf(fp, "%s %d %.2f\n", s.name, s.id, s.grade);
fclose(fp);
puts("파일 저장 완료");
return 0;
}
// 2) 메모장에서 input파일을 작성하여 각 학생의 총점과 평균점수를 계산하여 다른 파일에 출력하는 프로그램을 작성하시오.
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:6031)
#include <stdio.h>
struct Student {
char name[20];
int score[3];
int sum;
float avg;
};
int main(void) {
struct Student s;
FILE *in = fopen("input.txt", "r");
FILE *out = fopen("output.txt", "w");
if (in == NULL || out == NULL) {
puts("파일 열기 실패");
return 1;
}
while (fscanf(in, "%s %d %d %d",
s.name, &s.score[0], &s.score[1], &s.score[2]) != EOF) {
s.sum = s.score[0] + s.score[1] + s.score[2];
s.avg = s.sum / 3.0;
fprintf(out, "%s %d %.2f\n", s.name, s.sum, s.avg);
}
fclose(in);
fclose(out);
puts("총점 및 평균 계산 완료");
return 0;
}
// 3) 2번 예제에서 성적순을 추가하여 순차적으로 출력하는 프로그램을 작성하시오.
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:6031)
#include <stdio.h>
struct Student {
char name[20];
int sum;
float avg;
};
int main(void) {
struct Student s[50], temp;
int count = 0;
FILE *fp = fopen("output.txt", "r");
if (fp == NULL) {
puts("파일 열기 실패");
return 1;
}
while (fscanf(fp, "%s %d %f", s[count].name,
&s[count].sum, &s[count].avg) != EOF) {
count++;
}
fclose(fp);
for (int i = 0; i < count - 1; i++) {
for (int j = i + 1; j < count; j++) {
if (s[i].sum < s[j].sum) {
temp = s[i];
s[i] = s[j];
s[j] = temp;
}
}
}
for (int i = 0; i < count; i++) {
printf("%d등: %s %d %.2f\n",i+1, s[i].name, s[i].sum, s[i].avg);
}
return 0;
}
// 4) 아래의 코드의 실행결과를 자세히 설명하시오.
#include <stdio.h>
int main(void)
{
char name[10];
char gender;
int age;
int ret;
FILE* fp = fopen("friend.txt", "r");
if (fp == NULL) { puts("파일오픈 실패!"); return 1; }
while (1) {
ret = fscanf(fp, "%s%c%d", name, &gender, &age);
if (ret == EOF) break;
printf("%s %c %d\n", name, gender, age);
}
fclose(fp);
return 0;
}
// 먼저 fscanf의 3개의 입력문자에서 %s가 구분문자직전까지 데이터를 읽어 저장한 후 %c에서 구분문자를 저장하게 되어
// 데이터의 입력 순서가 한 칸씩 뒤로 밀린다. 따라서 마지막 변수는 적절한 데이터를 찾지 못해 초기화되지 않아
// 쓰레기값을 갖게 되고, 다음 루프로 넘어가 성별 데이터가 이름으로, 다시 구분문자가 성별로, 그 다음에는 나이를 적절하게 저장하는 듯 하지만,
// 이는 적절한 데이터 저장이 아니게 된다. 따라서 문자 단위로 입력을 받을 경우 앞에 공백문자를 붙여 구분문자를 입력받지 않도록 해야 한다.
// [24-3]
// 1) 텍스트파일에 저장된 8자리 정수 10개를 읽어서 바이너리 파일로 출력해 파일의 내용을 확인하시오.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main(void) {
FILE *txt = fopen("num.txt", "rb");
FILE *bin = fopen("num.bin", "wb");
int num;
while (fscanf(txt, "%d", &num) == 1)
fwrite(&num, sizeof(int), 1, bin);
fclose(txt);
fclose(bin);
return 0;
}
// 2) 예제 1번에서 생성한 파일에서 데이터를 읽어 화면에 출력하라.
#include <stdio.h>
int main(void) {
FILE *bin = fopen("num.bin", "rb");
int num;
while (fread(&num, sizeof(int), 1, bin))
printf("%d\n", num);
fclose(bin);
return 0;
}
// 3) 예제 1번에서 생성한 파일의 크기를 바이트단위로 계산하여 출력하는 프로그램을 작성하라.
#include <stdio.h>
int main(void) {
FILE *fp = fopen("num.bin", "rb");
fseek(fp, 0, SEEK_END);
printf("파일 크기: %ld 바이트\n", ftell(fp));
fclose(fp);
return 0;
}
// [24장 정리문제]
// 1) 파일입출력을 설명하라.
// 프로그램이 파일을 통해 테이터를 읽거나 출력하는 것이다.
// 2) 파일입출력의 필요성을 설명하라.
// 프로그램의 출력 데이터를 영구 저장하거나, 프로그램을 실행 중 종료 시에도 데이터를 저장하여 진행상황을 유지할 수 있다.
// 3) 파일입출력과 콘솔 입력출력의 차이가 있다면 설명하라.
// 콘솔 입출력의 경우 데이터를 일회성으로 입출력한 후 저장하지 않지만,
// 파일 입출력의 경우 저장된 데이터는 명시적으로 변경, 삭제하지 않는 한 그대로 유지된다.
// 4) 스트림과 버퍼에 대하여 설명하라.
// 스트림은 데이터가 이동할 경로를 알려주는 가상의 통로이고, 버퍼는 스트림에 소속된 물리적인 메모리로,
// 데이터가 임시로 저장되었다가 특정 단위로 한꺼번에 전송된다.
// 5) FILE구조체의 정의를 찾아서 첨부하고 설명하라.
// 기본적인 파일 구조체의 정의는
typedef struct _iobuf {
char *_ptr;
int _cnt;
char *_base;
int _flag;
int _file;
} FILE;
// 로 첫 변수부터 각각 파일 위치 포인터, 처리 가능한 데이터의 바이트 수를 저장하는 변수,
// 파일 데이터의 시작 주소, 파일의 열린 상태를 저장하는 변수(읽기, 쓰기 모드),
// 파일의 디스크립터 번호를 저장하는 변수로 이루어져 있다.
// 6) stdin, stdout의 정체를 설명하고 정의를 찾아서 첨부하고 설명하라.
// stdin과 stdout은 키보드와 모니터를 대상으로 하는 스트림으로, file* 타입이다.
// 7) 파일의 끝은 나타내는 매크로 상수는 무엇인가?
// 파일의 끝을 나타내는 매크로 상수는 EOF(end of file)로 파일의 데이터 가장 끝에 위치한다.
// 8) 텍스트 파일과 바이너리 파일을 설명하고 예를 하나씩 들어 설명해라.
// 먼저 텍스트 파일은 문자 형태로 데이터가 저장된 파일로, 인코딩 방식이 지정되어 있어
// 사람이 직접 읽고 수정할 수 있는 파일이다.
// 바이너리 파일은 0과 1의 이진 코드가 저장되어있는 파일로, 인코딩 방식이 지정되어 있지 않아 사람이
// 내용을 직접 이해하기 어렵고, 특정 프로그램을 통해서만 해석된다.
// 먼저 .c의 경우 c코드로 작성된 영문 텍스트 파일이다. 메모장이나 코드 편집기로 읽어 사람이 읽고 수정할 수 있다.
// .txt파일은 순수한 문자만 저장하는 파일로 텍스트 편집기에서 내용을 확인 및 수정할 수 있다.
// .hwp파일은 한글 워드 프로세서에서 사용하는 문서 파일로, 그 이외의 프로그램으로 열 경우 2진 데이터로 출력되어 알아볼 수 없다.
// .doc, .docx 파일의 경우 마이크로소프르 워드에서 사용하는 문서 파일로 한글 파일과 동일하다.
// 마지막으로 .exe파일은 실행 파일로, cpu가 이해할 수 있는 기계어 명령어가 이진 데이터의 형태로 저장되어 있다.
[25 메모리 관리와 동적 할당]
// [25-1]
// 1) 아래 코드의 지역변수와 매개변수가 스택에 어떠한 형태로 할당되고 소멸되는지 설명하시오.
// 먼저 메인함수가 시작되고 스택 영역에 num1이 할당된 후, func1의 호출 후 num2가 num1위에 할당된다.
// 그 후 func2의 호출에 의해 num3가 num2위에 할당된다. func2의 수식 계산 후 반환값이 없으므로
// 바로 num3부터 소멸되고 그 후 func1 또한 반환값이없으므로 바로 num2 또한 소멸한다.
// 이후 함수호출문에서 빠져나와 메인함수가 종료되며 num1이 소멸된다.
void func2(int n) {
int num3=n+1;
}
void func1(int n) {
int num2=n+1;
func2(num2);
}
int main(void) {
int num1 = 20;
func1(num1);
return 0;
}
// 2) 동적할당을 이용하여 저장할 실수의 갯수를 입력받고 저장 후 평균값을 계산하여 출력하는 프로그램을 작성하시오.
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:6031)
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int len;
double sum = 0.0;
printf("저장할 실수의 크기를 입력하세요:");
scanf("%d", &len);
double* arr = (double*)malloc(sizeof(double)*len);
printf("%d개의 실수를 입력하시오 : ", len);
for (int i = 0; i < len; i++) {
scanf("%lf", arr + i);
sum += *(arr + i);
}
printf("입력한 실수의 평균값은 %lf입니다.", sum / len);
free(arr);
return 0;
}
// 3) 동적 할당을 이용하여 문자열의 크기와 문자열을 입력받아 저장 후 출력하는 프로그램을 작성하시오.
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:6031)
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int len;
printf("저장할 문자열의 크기를 입력하세요:");
scanf("%d", &len);
getchar();
char* str = (char*)malloc(len + 1);
printf("문자열을 입력하시오:");
fgets(str, len+1, stdin);
printf("입력한 문자열은 %s입니다.", str);
free(str);
}
// 4) 3번 예제의 코드에서 문자열의 대소문자를 반전시켜 출력하시오.
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:6031)
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int len;
printf("저장할 문자열의 크기를 입력하세요:");
scanf("%d", &len);
getchar();
char* str = (char*)malloc(len + 1);
printf("문자열을 입력하시오:");
fgets(str, len+1, stdin);
for (int i = 0; str[i] != '\0'; i++) {
if (str[i] >= 'A' && str[i] <= 'Z') {
str[i] = str[i] + 32;
}
else if (str[i] >= 'a' && str[i] <= 'z') {
str[i] = str[i] - 32;
}
}
printf("대소문자를 변환한 문자열은 %s입니다.", str);
free(str);
}
// 5) 예제 코드를 동적할당 방식으로 변형하여 구현하시오.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
typedef struct point {
int xpos;
int ypos;
} Point;
typedef struct person {
char name[20];
char phoneNum[20];
int age;
} Person;
int main(void) {
Point* pos = (Point*)malloc(sizeof(Point));
Person* man = (Person*)malloc(sizeof(Person));
if (pos == NULL || man == NULL) {
printf("메모리 할당 실패\n");
return 1;
}
*pos = (Point){ 10, 20 };
*man = (Person){ "이승기", "010-1212-0001", 21 };
printf("%d %d\n", pos->xpos, pos->ypos);
printf("%s %s %d\n", man->name, man->phoneNum, man->age);
free(pos);
free(man);
return 0;
}
// [25장 정리문제]
// 1) 정적 할당과 동적 할당의 차이를 설명하시오.
// 먼저 정적 할당의 경우 컴파일 과정에서 변수의 메모리 크기가 결정되어 스택, 또는 데이터 영역에 할당되는 반면,
// 동적 할당의 경우 프로그램이 실행되는 중에 필요에 따라 할단되는 메모리의 크기를 변경할 수 있고, 힙 영역에 할당된다.
// 2) 동적할당의 장점은 무엇인가?
// 입력될 수 있는 데이터의 최댓값이 아닌 필요한 만큼, 즉 입력된 데이터의 크기만큼만 메모리를 할당하여
// 메모리 낭비를 줄일 수 있고, 실행 중에 데이터의 크기를 변경 가능하다.
// 3) void포인터를 설명하시오.
// 자료형이 정해지지 않은 포인터로 가리키는 변수의 타입에 상관없이 그 변수의 주소를 저장할 수 있다.
// 4) malloc함수의 반환형이 void* 이므로 반드시 형변환해서 사용해야 하는 이유를 설명하시오
// void* 타입은 타입정보가 없어 역참조가 불가능하고 역참조를 원할 경우 가리키는 변수의 타입 또는
// 사용 목적에 맞는 타입의 포인터형으로 강제형변환해주어야 한다.
// 5) free함수로 메모리를 해제하지 않으면 어떻게 되는가?
// 할당된 메모리를 사용이 완전히 끝난 후에도 다시 사용할 수 없어 메모리가 부족해지고, 계속될 경우 성능 저하나
// 메모리 부족으로 인한 프로그램 강제 종료가 발생할 수 있다.
// 6) 힙과 스택 영역에 대하여 설명하시오.
// 스택 영역은 지역변수 및 매개변수가 할당되는 공간으로 속도가 빠르지만 크기가 작다.
// 힙 영역은 동적 할당 메모리가 저장되는 영역으로 메모리 공간이 비교적 크지만 접근 속도가 느리다.
|
|
