필자는 SDL2를 사용하였기 때문에 SDL2 기준으로 글을 작성하지만 최근 버전인 SDL3 또한 동일한 방법으로 환경을 설정할 수 있기에 2를 설치하던지 3을 설치하던지 상관 없다. 

 

1. SDL 라이브러리 다운로드

Release 2.28.1 · libsdl-org/SDL · GitHub

 

Release 2.28.1 · libsdl-org/SDL

This is a stable bugfix release, with the following changes: Added support for the Nintendo Online Famicom controllers Improved support for third-party Nintendo Switch controllers Fixed setting th...

github.com

 

 

해당 링크에 들어가 위 그림과 같이 SDL2-devel-2.28.1-VC.zip을 클릭하여 다운받고 해당 솔루션 폴더에 압축을 해제한다.

파일이름이 길어서 말하기 번거로우니 파일 이름을 SDL로 변경했다


2. 동적링크라이브러리 파일 옮기기

파일 탐색기를 통해 SDL > lib > x64 폴더에 들어가게 되면 SD2.dll 파일이 있을것이다.

 그걸 복사해서 VS의 해당 솔루션 파일의 x64 > Debug 파일에 붙여넣기 하면 된다


3. 프로젝트 생성 및 속성 창

해당 솔루션 내에 프로젝트를 생성한다. 

프로젝트를 생성하고 코드로 #include <SDL.h>를 작성하면 해당 코드에 빨간 줄이 그어질 것이다. -> 아직 안되었다는 뜻

이후, 창의 프로젝트 - 속성을 누르거나 솔루션 탐색기에서 프로젝트 위에서 오른쪽 클릭을 통해 속성 창을 띄운다


4. C/C++ 의 추가 포함 디렉터리

속성 창에서 "C/C++"를 선택하고 "추가 포함 디렉터리"의 편집을 누르고 $(ProjectDir)..\SDL\include 을 작성한 후 확인을 누른다.

여기서 $(ProjectDir)은 현재 프로젝트 디렉토리를 가리킨다.


5. 링커의 일반

그 후 속성 창에서 "링커"의 "일반" 선택하고 "추가 라이브러리 디렉터리"에 위와 같은 방법으로 편집하여 $(ProjectDir)..\SDL\lib\x64을 작성한다. 


6. 링커의 입력

그 다음, "링커"의 "입력"을 선택하고 "추가 종속성"에 편집으로 SDL2.lib 와 SDL2main.lib를 적으면 된다. (파일탐색기의 해당 솔루션 파일의 SDL > lib > x64 파일 속 확장자가 .lib인 파일을 모두 적으면 된다)


7. 확인

SDL 개발 환경이 잘 설정되었지 확인하기 위해 해당 코드를 프로젝트에 작성해보고 실행한다

#include <stdio.h>
#include <SDL.h>

#define WIDTH 800  // 화면 너비
#define HEIGHT 600 // 화면 높이

SDL_Window* window; // SDL 창과 렌더러를 가리키는 포인터
SDL_Renderer* renderer;

int main(int arc, char** argv) {
	SDL_Event event;
	int quit = 0;

	SDL_Init(SDL_INIT_VIDEO); // 비디오 서브 시스템 초기화

	window = SDL_CreateWindow("galaga", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, WIDTH, HEIGHT, 2); // WIDTH 와 HEIGHT의 크기만큼, "galga"라는 제목의 윈도우를 가운데 정렬되게 생성
	renderer = SDL_CreateRenderer(window, -1, 0); // 윈도우에 대한 렌더러(그래픽 요소를 그리기 위해 사용됨) 생성

	while (!quit) {
		//이벤트 처리
		while (SDL_PollEvent(&event)) {
			if (event.type == SDL_QUIT) { // 윈도우의 x 표시를 누르면
				quit = 1;
			}
		}
		SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); // 렌더러의 그리기 색상을 검정색으로
		SDL_RenderClear(renderer); // 렌더러에 설정된 색상으로 화면을 지움
		SDL_RenderPresent(renderer); // 렌더러에 그려진 내용을 실제 화면에 표시
	}
	SDL_DestroyRenderer(renderer); // 렌더러와 윈도우 해제
	SDL_DestroyWindow(window); 
	SDL_Quit(); // SDL을 종료하고 관련된 리소스를 해제한다.

}

해당 창이 성공적으로 뜨면 SDL 설치가 제대로 된것이다. 

01. malloc() 함수를 사용하여 int 변수, short 변수, float 변수를 저장할 수 있는 동적 메모리를 만들고 사용자로부터 해당 값을 입력받아서 저장한다. 동적 메모리에 저장된 값을 꺼내서 출력한다.

#include <stdio.h>
#include <stdlib.h>

int main() {
	int* a = (int*)malloc(sizeof(int));
	short* b = (short*)malloc(sizeof(short));
	float* c = (float*)malloc(sizeof(float));

	printf("정수(int형)을 입력하시오: ");
	scanf("%d", a);
	printf("정수(short형)을 입력하시오: ");
	scanf("%d", b);
	printf("실수(float형)을 입력하시오: ");
	scanf("%f", c);

	printf("\n입력된 값은 %d, %d, %.2f입니다.", *a, *b, *c);
    free(a);
    free(b);
    free(c);
}

02. 사용자가 입력한 n개의 실수의 합을 계산하기 위한 C 프로그램을 작성해보자. 사용자로부터 실수의 개수를 먼저 입력받도록 해보자. 실수의 개수만큼 동적 메모리를 할당하고, 실수들을 동적 메모리에 저장한다.

#include <stdio.h>
#include <stdlib.h>

int main() {
	int a;
	double sum = 0;
	double* p;
	printf("실수의 개수: ");
	scanf("%d", &a);
	p = (double*)malloc(sizeof(double) * a);
	for (int i = 0; i < a; i++) {
		printf("실수를 입력하시오: ");
		scanf("%lf", p + i);
	}

	for (int i = 0; i < a; i++) {
		sum += p[i];
	}
	printf("합은 %.1lf입니다. ", sum);
    free(p)

}

03. 정수 100개를 저장할 수 있는 동적 메모리를 할당받고 여기에 0부터 99 사이의 난수를 저장한다. 난수 중에서 최대값을 찾아서 출력해보자.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define size 100

int main() {
	srand((unsigned)time(NULL));
	int* a = (int*)malloc(sizeof(int) * size);
	int max;

	for (int i = 0; i < size; i++) {
		a[i] = rand() % 100;
	}

	max = a[0];
	for (int i = 1; i < size; i++) {
		if ( max < a[i]) {
			max = a[i];
		}
	}
	printf("난수 중에서 최대 값은 %d입니다.", max);
    free(a)
}

04. malloc()함수를 사용하여 문자열을 저장할 수 있는 동적 메모리를 생성하고 사용자가 입력한 문자열을 저장한 후에 화면에 출력한다. 문자열을 입력받기 전에 문자열의 최대 길이를 먼저 입력받는다.

#include <stdio.h>
#include <stdlib.h>

int main() {
	char* p = NULL;
	int len;
	printf("문자열의 최대 길이를 입력하시오: ");
	scanf("%d", &len);
	getchar();
	p = (char*)malloc(sizeof(char) * (len+1));
	printf("문자열을 입력하시오: ");
	gets_s(p, sizeof(char) * (len + 1));
	printf("\n입력된 문자열은 %s입니다.", p);
    free(p);
}

05. 처음에 20바이트를 동적 할당받아서 "hangookuniv"를 저장한다. realloc()를 이용하여 동적 할당 메모리의 크기를 30바이트로 증가시키고, 이미 있던 문자열에 ".com"을 추가해보자. 저장된 문자열과 동적 할당 메모리의 주소를 출력해보자.

 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main() {
	char* p = (char*)malloc(sizeof(char) * 20);
	strcpy(p, "hangookuniv");
	printf("문자열 = %s, 주소 = %u \n", p, p);
	p = (char*)realloc(p, sizeof(char) * 30);
	strcat(p, ".com");
	printf("문자열 = %s, 주소 = %u \n", p, p);
    free(p)
}

06. 다음과 같은 구조체를 동적 메모리 할당으로  생성하는 프로그램을 작성해보자. 동적으로 생성된 구조체에는 { 10, 3.14, 'a'}를 저장한다.

typedef struct rec {
	int i;
    float PI;
    char A;
} my_record;

#include <stdio.h>
#include <stdlib.h>

typedef struct rec {
    int i;
    float PI;
    char A;
} my_record;

int main() {
    my_record* p = (my_record*) malloc(sizeof(my_record));
    *p = { 10,3.14,'a' };
    printf("i = %d \n", (*p).i);
    printf("PI = %.2f \n", p->PI);
    printf("A = %c \n", p->A);

}

07. 성적을 나타내는 구조체가 다음과 같다. 사용자에게 구조체의 개수를 입력하도록 요청하고 개수만큼의 동적 메모리를 할당받은 후에 구조체에 값을 저장한다. 입력이 끝나면 구조체에 저장된 값을 화면에 출력한다. 

struct course {
	char subject[30];
    double marks;
};

#include <stdio.h>
#include <stdlib.h>

struct course {
    char subject[30];
    double marks;
};

int main() {
    int len;
    struct course* p;
    printf("구조체의 개수: ");
    scanf("%d", &len);
    p = (struct course*)malloc(sizeof(struct course) * len);
    for (int i = 0; i < len; i++) {
        printf("과목 이름과 성적: ");
        scanf("%s %lf", p[i].subject, &p[i].marks); // &(p + i)->marks 도 가능
    }
    printf("\n");

    for (int i = 0; i < len; i++) {
        printf("%-10s %.1lf \n", p[i].subject, p[i].marks);
    }
    
    free(p);
}

01. 다음 소스에 대한 질문에 답하라.

double power(int x, int y) {
	double result = 1;
	int i;

	for (i = 0; i < y; i++) {
		printf("result=%f\n", result);
		result *= x;
	}

	return result;
}

 

(a) 전처리 지시자 #ifdef을 사용하여 DEBUG가 정의되어 있는경우에만 화면 출력이 나오도록 해보자.

#define DEBUG

double power(int x, int y) {
	double result = 1;
	int i;

	for (i = 0; i < y; i++) {
#ifdef DEBUG
		printf("result=%f\n", result);
#endif
		result *= x;
	}

	return result;
}

 

(b) #if를 사용하여 DEBUG가 2이고 LEVEL이 3인 경우에만 화면 출력이 나오도록 수정해보자.

#define DEBUG 2
#define LEVEL 3

double power(int x, int y) {
	double result = 1;
	int i;

	for (i = 0; i < y; i++) {
#if DEBUG==2 && LEVEL 3
		printf("result=%f\n", result);
#endif
		result *= x;
	}

	return result;
}

int main() {
	power(2, 10);

}

 

(c) 문장 (1)을 수정하여 소스 파일에서 현재의 행 번호가 함께 출력되도록 해보자.

#define DEBUG 2
#define LEVEL 3

double power(int x, int y) {
	double result = 1;
	int i;

	for (i = 0; i < y; i++) {
#if DEBUG==2 && LEVEL 3
		printf("현재 행 번호 %d : result=%f\n",__LINE__, result);
#endif
		result *= x;
	}

	return result;
}

int main() {
	power(2, 10);

}

 

(d) #if를 이용하여 문장 (1)을 주석 처리하여보자.

#define DEBUG 2
#define LEVEL 3

double power(int x, int y) {
	double result = 1;
	int i;

	for (i = 0; i < y; i++) {
#if 0
#if DEBUG==2 && LEVEL 3
		printf("현재 행 번호 %d : result=%f\n",__LINE__, result);
#endif
#endif
		result *= x;
	}

	return result;
}

int main() {
	power(2, 10);

}

02. 3개의 정수 중에서 최소값을 구하는 매크로 GET_MIN(x, y, z)를 정의하고 이것을 이용하여서 사용자로부터 받은 3개의 정수 중에서 최소값을 계산하여서 출력하는 프로그램을 작성한다. 

#include <stdio.h>

#define GET_MIN(x,y,z) ((x)<(y)&&(x)<(z))?(x):((y)<(z)?(y):(z))

int main() {
	int x, y, z;
	printf("3개의 정수를 입력하시오: ");
	scanf("%d %d %d", &x, &y, &z);
	printf("최소값은 %d입니다. \n", GET_MIN(x, y, z));

}

03. 배열 원소의 값을 모두 지정된 값으로 초기화하는 ARRAY_INIT(array, size, value)를 작성하여 테스트하여보자.

#include <stdio.h>

#define ARRAY_INIT(array, size, value) {for(int i = 0; i < size; i++){ \
	array[i] = value;}}

int main() {
	int array[10];
	int size = sizeof(array) / sizeof(array[0]);

	ARRAY_INIT(array, 10, 0);

	printf("[ ");
	for (int i = 0; i < size; i++) {
		printf("%d ", array[i]);
	}
	printf("] \n");
}

04. 원기둥의 부피는 PI * r^2 * h 이다. 사용자로부터 반지름과 높이를받아서 원기둥의 부피를 구하는 프로그램을 작성한다. 파이는 단순 매크로로 정의한다. 원기둥의 부피를구하는 공식은 함수 매크로로 정의한다.

#include <stdio.h>
#define PI 3.141592
#define VOLUME(r,h) { \
	printf("원기둥의 부피: %.2f", PI * r *r *h);}

int main() {
	int r, h;
	
	printf("원기둥의 반지름을 입력하시오: ");
	scanf("%d", &r);
	printf("원기둥의 높이를 입력하시오: ");
	scanf("%d", &h);
	VOLUME(r, h);
}

05. c가 공백 문자(탭, 스페이스, 줄바꿈 문자)이면 참이되는 매크로 IS_SPACE(c)를 정의하여서 사용자가 입력한 문자열 중에서 공백문자의 개수를 출력하여보자.

#include <stdio.h>

#define SIZE 100
#define IS_SPACE(c) { \
	int count = 0; \
	for (int i = 0; i < SIZE-1; i++) \
		if(c[i]== ' ' || c[i] == '\t' || c[i]== '\n') count++; \
	printf("공백문자의 개수: %d", count);}

int main() {
	char a[100];
	printf("문자열을 입력하시오: ");
	gets_s(a, SIZE);
	IS_SPACE(a);


}

06. 정수값을 받아서 2진수 형태로 출력하는 함수 display_bit(int value)를 작성하여보자. 본문에서 정의한 함수 매크로 GET_BIT(n, pos)를 사용한다.

#include <stdio.h>

#define GET_BIN(n,i) (((n) >> (31-(i))) & 0x1)

void display_bit(int value);

int main() {
	int a;
	printf("정수값을 입력하시오: ");
	scanf("%d", &a);
	display_bit(a);

}

void display_bit(int value) {
	for (int i = 0; i < 32; i++) {
		if (GET_BIN(value, i))
			printf("1");
		else
			printf("0");
	}
}

07. 사용자로부터 입력받은 정수를 비트 이동시키는프로그램을 작성하여보자. 먼저 정수 변수의 값을 입력받은 후에 이동시킬 방향, 이동할 거리를 사용자로부터 입력받는다. 비트 이동 전후에 정수의 값을 비트로 출력하도록 한다. 앞 문제에서 작성한 display_bit() 함수를 사용한다.       

   

#include <stdio.h>

#define GET_BIN(n,i) ((n >> (31-i)) & 0x1)
#define RIGHT_BIN(a, r) ((a)>>(r))
#define LEFT_BIN(a, r) ((a)<<(r))
void display_bit(int value);

int main() {
	int a, m, r;
	printf("정수값을 입력하시오: ");
	scanf("%d", &a);
	printf("왼쪽 이동은 0, 오른쪽 이동은 1을 입력하시오: ");
	scanf("%d", &m);
	printf("이동시킬 거리: ");
	scanf("%d", &r);

	printf("이동 전: ");
	display_bit(a);


	printf("이동 후: ");
	if (m == 1) {
		display_bit(RIGHT_BIN(a, r));
	}
	else {
		display_bit(LEFT_BIN(a, r));
	}


}

void display_bit(int value) {
	for (int i = 0; i < 32; i++) {
		if (GET_BIN(value, i))
			printf("1");
		else
			printf("0");
	}
	printf("\n");
}

08. 비트 연산자를 이용하여 대소문자를 변경할 수 있다. 대문자의 아스키 코드는 모두 여섯 번재 비트가 0이고 소문자의 경우에는 여섯 번재 비트가 모두 1이다. 따라서 XOR 연산을 이용하여 문자의 여섯 번째 비트를 바꿔주면 대소문자가 바뀌게 된다. 이 성질을 이용하여 사용자가 입력한 문자열의 대소문자를 바꾸는 프로그램을 작성하라.

#include <stdio.h>
#define CHANGE(x) ((0x01<<5)^(x))

int main() {
	char a[100];
	printf("문자열을 입력하시오: ");
	gets_s(a, sizeof(a));

	printf("결과 문자열: ");
	for (int i = 0; a[i] != '\0'; i++) {
		printf("%c", CHANGE(a[i]));
	}
}

09. 암호화 방법 중의 한나는 암호화할 값을 키 값과 비트 XOR 연산을 하는 것이다. 원래의 값을 복원하려면 다시 비트 XOR 연산을 하면 된다. 이암호화 방법을 사용하여 사용자로부터 문자열을 암호화하고 다시 복호화하는 프록램을 작성하라. 다중 소스 파일 형태로 작성하라. 

(유의할점: 복호화/암호화 하고 마지막에 꼭 '\0'를 넣어야한다. )

//header.h

#pragma once
#define CHANGE(x,k) (x)^(k)

void encode(char* a, char* b, char key);
void decode(char* b, char* c, char key);
//encoder.c

#include <stdio.h>
#include "header.h"


void encode(char* a, char* b, char key) {
	int i;
	for (i = 0; a[i] != '\0'; i++) {
		b[i] = CHANGE(a[i], key);
	}
	b[i] = '\0';

}


void decode(char* b, char* c, char key) {
	int i;
	for (i = 0; b[i] != '\0'; i++) {
		c[i] = CHANGE(b[i], key);
	}
	c[i] = '\0';

}
//main.c

#include <stdio.h>
#include "header.h"

int main() {
	char a[100] = "I am a boy";
	char b[100];
	char c[100];
	char key = 'K';

	encode(a, b, key);
	decode(b, c, key);

	printf("%s가 %s로 엔코딩됨 \n", a, b);
	printf("%s가 %s로 디코딩됨 \n", b, c);
}

10. 다음과 같은 2개의파일로 이루어진 프로그램을 자것ㅇ하고 컴파일하여 실행해보자.

- 정수 2개를 받아서 합계를 반환하는 함수 add(int x, int y)을가지고 있는 add.c

- add()를 호출하여 10과 20의 합을 계산하는 문장이 포함된 main.c

(extern을 써도 되고 생략해도 됨)

 

//main.c

#include <stdio.h>

extern int add(int x, int y);

int main() {
	printf("합계 = %d \n", add(10, 20));
}
//add.c

int add(int x,int y){
	return x + y;
}

11. 배열에관한 각종 연산을 포함하는 array.c를작성한다. 예를 들어서 배열 원소들의 합을 계산하는 함수 get_sum_of_array(), 배열 원소들을 화면에 출력하는 함수 print_array() 등의 함수를 포함하라. 다시 main.c 파일을생성하고 여기서 array.c에 포함된 함수들을 호출하여 보라. array.c가 제공하는 함수들의 원형은 array.h 헤더 파일에 저장한다.   

//array.h

#pragma once

int get_sum_of_array(int *arr, int size);
void print_array(int *arr, int size);
//array.c

#include <stdio.h>
#include "array.h"

int get_sum_of_array(int *arr, int size) {
	int sum = 0;
	for (int i = 0; i < size; i++) { 
		sum += arr[i];
	}
	return sum;
}



void print_array(int *arr, int size) {
	printf("[ ");
	for (int i = 0; i < size; i++) {
		printf("%d ", arr[i]);
	}
	printf("] \n");
}
//main.c

#include <stdio.h>
#include "array.h"

int main() {
	int array[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int size = sizeof(array) / sizeof(array[0]);

	print_array(array, size);
	printf("배열 요소의 합=%d", get_sum_of_array(array, size));

}

 

유의할점

int get_sum_of_array(int arr[]) {
	int sum = 0;
	for (int i = 0; i < sizeof(arr)/sizeof(arr[0]); i++) { // sizeof 연산 불가능, 매개변수를 통해 size 넘겨줘야함
		sum += arr[i];
	}
	return sum;
}

12. 이제까지 학습한 내용을 바탕으로 화면에 달력을 출력하는 프로그램을 만들어보자. 화면에 현재월을 출력한다. 전처리기를 사용하여서 영어 버전과 한국어 버전을 작성해본다. 

 

01. 텍스트 파일 proverbs.txt를 읽어서 각 줄의 앞에 줄 번호를 붙여서 화면에 출력하는 프로그램을 작성하라.

#include <stdio.h>
    
int main() {
	FILE* fp = NULL;
	int count = 0;
	char buffer[100];
	
	fp = fopen("proverbs.txt", "r");
	if (fp == NULL) {
		fprintf(stderr, "파일을 열 수 없습니다.");
		return 1;
	}

	while (fgets(buffer,100,fp)) {
		count++;
		printf("%d: %s", count, buffer);
	}
    fclose(fp);
}

02. 텍스트 파일을 열어서 파일 안에 들어 있는 문자들을 모두 대문자로 변경하여 새로운 파일에 저장하는 프로그램을 작성한다. 새로운 파일을 화면에출력해서 확인하자.

#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <ctype.h>

int main() {
    char f1[100];
    char f2[100];
    char buffer[100];
    int len;
    printf("첫 번째 파일 이름: ");
    scanf("%s", f1);
    printf("두 번째 파일 이름: ");
    scanf("%s", f2);

    FILE* fp1 = fopen(f1, "r");
    FILE* fp2 = fopen(f2, "w");

    if (fp1 == NULL || fp2 == NULL) {
        fprintf(stderr, "파일을 열 수 없습니다.");
    }

    while (fgets(buffer, 100, fp1)) {

        len = sizeof(buffer);
        for (int i = 0; i < len; i++) {
            buffer[i] = toupper(buffer[i]);
        }
        fputs(buffer, fp2);
        printf("%s", buffer);
    }
    fclose(fp1);
    fclose(fp2);
}

/* fgets()의 반환값을 읽은 바이트 수가 아니기 때문에 이 방법은 불가능

    while (len = fgets(buffer, 100, fp1)) {
        for (int i = 0; i < len; i++) {
            buffer[i] = toupper(buffer[i]);
        }
    }
*/

03. 두 개의 텍스트 파일을 서로 비교하는 프로그램을 작성하여보자. 파일의 이름은 사용자에게 입력받는다. 만약 두 개의 파일이 일치하면 "파일은 서로 일치함"을 출력하며 일치하지 않으면 일치하지 않는 첫 번째 문장을 다음과 같이 출력한다.

#include <stdio.h>
#include <ctype.h>
#include <string.h>

int main() {
    char f1[100];
    char f2[100];
    char buffer1[100], buffer2[100];
    int len;
    int same = 1;
    printf("첫 번째 파일 이름: ");
    scanf("%s", f1);
    printf("두 번째 파일 이름: ");
    scanf("%s", f2);

    FILE* fp1 = fopen(f1, "r");
    FILE* fp2 = fopen(f2, "r");

    if (fp1 == NULL || fp2 == NULL) {
        fprintf(stderr, "파일을 열 수 없습니다.");
    }

    while (fgets(buffer1, 100, fp1) && fgets(buffer2, 100, fp2)) {
        if (strcmp(buffer1, buffer2) != 0) {
            same = 0;
            break;
        }
    }
    if (same == 1) {
        printf("파일은 서로 일치함 \n");
    }
    else {
        printf("<< %s", buffer1);
        printf(">> %s", buffer2);
    }

    fclose(fp1);
    fclose(fp2);
}

04. 다음과 같이 학생들의 교과목 성적이 저장되어 있는 텍스트 파일을 읽어서 성적의 평균을 구하여 다른 파일에 쓰는프로그램을 작성해보자.  평균은소수점 2자리 까지 출력하도록 하라.

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <ctype.h>
#include <string.h>

struct student {
	char name[100];
	int kor;
	int math;
	int eng;
};

int main() {
	FILE* f1, * f2;
	struct student temp;
	int sum = 0;

	f1 = fopen("input.txt", "r");
	f2 = fopen("output.txt", "w");

	if (f1 == NULL || f2 == NULL) {
		fprintf(stderr, "에라이");
		return 1;
	}

	while (!feof(f1)) {
		fscanf(f1, "%s %d %d %d", temp.name, &temp.kor, &temp.math, &temp.eng);
		sum = temp.kor + temp.math + temp.eng;
		fprintf(f2, "%s %.2f\n", temp.name, (double)sum / 3);
	}
    fclose(f1);
    fclose(f2);
}

 


05.  사용자로부터 받은 파일 이름으로 텍스트 파일을 연 후에 파일 안에 들어 있는 문자들의 개수와 단어들의 개수를 계산하여 출력해보자.

#include <stdio.h>
#include <ctype.h>

int main() {
	char file_name[100];
	FILE* fp;
	int c;
	int c_count = 0, w_count = 0;
	int word = 0;

	printf("파일 이름: ");
	scanf("%s", file_name);

	fp = fopen(file_name, "r");
	if (fp == NULL) {
		fprintf(stderr, "%s 파일을 열 수 없습니다. \n", file_name);
	}

	while ((c = getc(fp)) != EOF) {
		if (isprint(c)) {
			c_count++;
		}

		if (isspace(c)) {
			word = 0;
		}
		else if (word == 0) {
			word = 1;
			w_count++;
		}
	}
	fclose(fp);

	printf("문자의 개수는 %d \n", c_count);
	printf("단어의 개수는 %d \n", w_count);

}

06. 사용자가 입력하는 텍스트를 파일에 저장하여 주는 프로그램을 작성하여보자. 사용자가 Ctrl-Z를 입력하면 종료하는것으로 가정한다.

#include <stdio.h>

int main() {  
	FILE* fp = fopen("test.c", "w");
	int c;
	while ((c = getchar())!= EOF) {
		fputc(c, fp);
	}

	fclose(fp);
}
#include <stdio.h>

int main() {
	FILE* fp;
	char file_name[100];
	char buffer[100];

	printf("파일 이름: ");
	gets_s(file_name, sizeof(file_name)); // scanf() x

	fp = fopen(file_name, "w");
	if (fp == NULL) {
		fprintf(stderr, "%s파일을 열수 없습니다.", file_name);
		return 1;
	}

	while (fgets(buffer, sizeof(buffer), stdin) != NULL) {
		fputs(buffer, fp);
	}
	fclose(fp);
}

07.  명령 프롬프트에서 인수로 주어진 2개의 텍스트 파일을 합하여 하나의 파일로 저장하는 프로그램을 작성해보자.

#include <stdio.h>

int main(int argc, char *argv[]) {
	FILE* fp1, * fp2, * fp3;
	char buffer[1024];

	if (argc != 4) {
		fprintf(stderr, "사용법: %s <파일1> <파일2> <결과파일> \n", argv[0]);
        return 1;
	}

	fp1 = fopen(argv[1], "r");
	if (fp1 == NULL) {
		fprintf(stderr, "파일 %s를 열 수 없습니다. \n", argv[1]);
		return 1;
	}

	fp2 = fopen(argv[2], "r");
	if (fp2 == NULL) {
		fprintf(stderr, "파일 %s를 열 수 없습니다. \n", argv[2]);
		fclose(fp1);
		return 1;
	}

	fp3 = fopen(argv[3], "w");
	if (fp3 == NULL) {
		fprintf(stderr, "파일 %s를 열 수 없습니다. \n", argv[3]);
		fclose(fp1);
		fclose(fp2);
		return 1;
	}

	while (fgets(buffer, sizeof(buffer), fp1)) {
		fputs(buffer, fp3);
	}
	while (fgets(buffer, sizeof(buffer), fp2)) {
		fputs(buffer, fp3);
	}

	fclose(fp1);
	fclose(fp2);
	fclose(fp3);
	printf("C> fileadd %s %s %s \n", argv[1], argv[2], argv[3]);
	printf("%s 파일과 %s 파일을 합하여 %s 파일로 저장합니다.\n", argv[1], argv[2], argv[3]);

}

08. 텍스트 파일 proverbs.txt를 읽어서 사용자가 지정하는 줄을 삭제하는 프로그램을 작성해보자.  

#include <stdio.h>

int main() {
	FILE* fp1 = fopen("proverbs.txt", "r");
	FILE* fp2 = fopen("test.txt", "w");
	char buffer[100];
	int del;
	int cur_line = 0;

	if (fp1 == NULL || fp2 == NULL) {
		printf("파일을 열 수 없습니다. \n");
		return 1;
	}
	printf("삭제룰 원하는 줄 번호: ");
	scanf("%d", &del);

	while (fgets(buffer, sizeof(buffer), fp1)) {
		cur_line++;
		if (del == cur_line) {
			continue;
		}
		fputs(buffer, fp2);
	}
	printf("test.txt로 저장되었습니다. \n");
	fclose(fp1);
	fclose(fp2);
	

}

09. 텍스트 파일에서 특정한 단어를 찾아서 다른단어로 변경하여 출력 파일에 쓰는 프로그램을 작성해보자.

 

#include <stdio.h>
#include <string.h>

int main() {
	FILE* fp1 = fopen("test.txt", "r");
	FILE* fp2 = fopen("result.txt", "w");
	char buffer[100];
	char* pos;
	char old_word[] = "Android";
	char new_word[] = "안드로이드";

	if (fp1 == NULL || fp2 == NULL) {
		fprintf(stderr, "파일을 열 수 없습니다. \n");
		return 1;
	}

	while (fgets(buffer, sizeof(buffer), fp1) != NULL) {
		while ((pos = strstr(buffer, old_word)) != NULL) {
			*pos = '\0';
			fprintf(fp2, "%s%s", buffer, new_word);
			strcpy(buffer, pos + strlen(old_word));
		}

		fputs(buffer, fp2);
	}

	fclose(fp1);
	fclose(fp2);
}

10. 사용자가 지정하는 텍스트 파일을 읽어서 시저 암호 방법으로 암호화된 파일을 생성하는 프로그램을 작성해보자.

#include <stdio.h>
#include <string.h>

int main() {
	FILE* fp1, * fp2;
	char name[100];
	int key, c;

	printf("파일 이름을 입력하시오: ");
	scanf("%s", name);

	fp1 = fopen(name, "r");
	fp2 = fopen("test_enc.txt", "w");
	if (fp1 == NULL || fp2 == NULL) {
		fprintf(stderr, "파일을 열 수 없습니다. \n");
		return 1;
	}

	printf("이동 거리를 입력하시오: ");
	scanf("%d", &key);

	while ((c = fgetc(fp1)) != EOF) {
		if (c >= 'A' && c <= 'Z') {
			c += key;
			if (c > 'Z'){
				c -= 26;
			}
		}
		else if (c >= 'a' && c <= 'z') {
			c += key;
			if (c > 'z') {
				c -= 26;
			}
		}
		fputc(c, fp2);
	}
	printf("암호화된 파일은 %s입니다.", "test_enc.txt");
	fclose(fp1);
	fclose(fp2);
}

11. 하드 디스크에서 파일을 삭제하는 프로그램을 작성해보자.

#include <stdio.h>
#include <string.h>

int main() {
	char name[100];
	
	printf("파일 이름을 입력하시오: ");
	scanf("%s", name);

	if (remove(name) == 0) {
		printf("%s가 성공적으로 삭제되었습니다. \n", name);
	}
	else { // remove(name) == -1 
		printf("%s가 삭제되지 않았습니다. \n", name);
	}
}

12.

(1) 사람들의 이름과 전화번호를파일에 저장하는 프로그램을 작성해보자. 사람들의 이름은 aa부터 zz까지 676(26X26)개의 이름을 자동으로 생성한다. 전화번호도 100부터 775까지를 자동으로 생성한다.

#include <stdio.h>

int main() {
	FILE* fp;
	int start = 100;

	fp = fopen("phone.txt", "w");
	if (fp == NULL) {
		fprintf(stderr, "phone.txt 파일을 열 수 없습니다. \n");
		return 1;
	}

	for (int i = 'a'; i <= 'z'; i++) {
		for (int j = 'a'; j <= 'z'; j++) {
			fprintf(fp, "%c%c %d\n", i, j, start );
			start++;

		}
	}
	fclose(fp);

}

 

(2) 위에서 생성된 전화번호부 파일 phone.txt를 읽고, 여기에서 사용자가 지정하는 사람의 전화번호를 찾아서 화면에 표시하고 종료하는 프로그램을 작성해보자.

#include <stdio.h>
#include <string.h>

int main() {
	FILE* fp;
	char find_name[3], name[3];
	int tel;
	
	fp = fopen("phone.txt", "r");
	if (fp == NULL) {
		fprintf(stderr, "phone.txt 파일을 열 수 없습니다. \n");
		return 1;
	}

	printf("찾고자 하는 사람의 이름: ");
	scanf("%s", find_name);

	
	// fscanf()의 반환 값은 읽은 값의 개수이다.
	while (fscanf(fp,"%s %d", name, &tel)== 2) {
		if (strcmp(find_name, name) == 0) {
			printf("%s의 전화번호는 %d입니다. \n", find_name, tel);
			break;
		}
	}

	fclose(fp);

}

13. 자기가 소유하고 있는도서를 관리하는 프로그램을 작성하여보자. 다음과 같으 메뉴 화면을 가진다.  

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


struct book {
	char name[100];
	char writer[100];
	char publisher[100];
};

void print();
void add(FILE* fp);
void search(FILE* fp);
//void save(FILE* fp);
//void read(FILE* fp);

int main() {
	FILE* fp;
	struct book list;
	int menu;

	fp = fopen("library.txt", "a+");
	if (fp == NULL) {
		fprintf(stderr, "파일을 열 수 없습니다. \n");
		return 1;
	}

	while (1) {
		print();
		printf("정수값을 입력하시오: ");
		scanf("%d", &menu);
		getchar();

		switch (menu) {
		case 1:
			add(fp);
			break;
		case 2:
			search(fp);
			break;
		//case 3:
		//	save(fp);
		//	break;
		//case 4:
		//	read(fp);
		//	break;
		case 5:
			fclose(fp);
			return 0;
		default:
			printf("잘못된 입력입니다. \n");
		}
	}


}

void print() {
	printf("======================\n");
	printf(" 1. 추가 \n");
	printf(" 2. 검색 \n");
	printf(" 3. 파일로 저장 \n");
	printf(" 4. 파일에서 일기 \n");
	printf(" 5. 종료 \n");
	printf("======================\n");
}

void add(FILE* fp) {
	struct book temp;
	printf("도서의 이름: ");
	gets_s(temp.name, sizeof(temp.name));
	printf("저자: ");
	gets_s(temp.name, sizeof(temp.name));
	printf("출판사: ");
	gets_s(temp.name, sizeof(temp.name));

	fseek(fp, 0, SEEK_END);
	fprintf(fp, "%s %s %s\n", temp.name, temp.writer, temp.publisher);
}

void search(FILE* fp) {
	struct book temp;
	char find[100], line[100];

	printf("찾는 책의 이름을 입력하시오: ");
	gets_s(find, sizeof(find));

	fseek(fp, 0, SEEK_SET);

	while (fgets(line,sizeof(line),fp)) {
		sscanf(line, "%[^|]%[^|]%[^|]", temp.name, temp.writer, temp.publisher);
		if (strcmp(find, temp.name) == 0) {
			printf("도서의 이름: %s \n", temp.name);
			printf("저자: %s \n", temp.writer);
			printf("출판사: %s \n", temp.name);
			break;
		}
	}
	printf("찾으시는 책이 없습니다. \n");
}

답이 없다.. ;ㅁ;


14. 이진 파일의 가장 전형적인 예는이미지 파일이다. 이미지 파일 안에는 이미지 픽셀 값들이 이진값으로 저장된다. 많은 이미지 파일은 앞에 헤더가 있어서 헤더를 해석해야만이 이미지 픽셀값들을꺼내서 사용할수 있다. 다행하게도 RAW 파일 형식은 이미지 헤더가 없고 픽셀값이 8비트 이진데이터로 저장되어 있다. "lena(256x256).raw" 파일을읽어서 화면에 표시하는 프로그램을 작성해보자. "lena(256x256).raw"파일은 출판사 홈페이지나 인터넷에서 구할 수 있다.        

 

01. 정수 배열 { 30,80,100,50,60,20,40,90,70,10 }을 내림차순으로 정렬하는 프로그램을 작성해보자. 라이브러리 함수 qsort()를 사용한다. 

#include <stdio.h>
#include <stdlib.h>

int array[] = { 30,80,100,50,60,20,40,90,70,10 };

int compare(const void *a, const void *b) {
	return (*(int*)b - *(int*)a);
}

int print() {
	for (int i = 0; i < sizeof(array) / sizeof(array[0]); i++) {
		printf("%d, ", array[i]);
	}
	printf("\n");
}

int main() {

	printf("정렬되지 않은 배열: \n");
	print();

	qsort(array, sizeof(array)/sizeof(array[0]), sizeof(int), compare);

	printf("내림차순으로 정렬된 배열: \n");
	print();
}

02. 학생(학번 int number, 이름 char name[10], 성적 double score)을 나타내는구조체 Student를 정의한다. 구조체 Student의 배열에 학생 30명의 정보를 저장한다. 모든 정보는 난수로 생성해보자. 라이브러리 함수 qsort()를 사용하여 성적을 기준으로 정렬하는 프로그램을 작성해보자.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

typedef struct {
	int number;
	char name[10];
	double score;
}Student;

void generate_name(char* name, int size);
int compare(const void* a, const void* b);
void print(Student* student, int size);


int main() {
	srand((unsigned)time(NULL));
	Student list[30];
	int name_size = sizeof(list[0].name) / sizeof(list[0].name[0]);
	int student_size = sizeof(list) / sizeof(list[0]);

	// 구조체 배열에 값 넣기
	for (int i = 0; i < student_size; i++) {
		list[i].number = i;
		generate_name(list[i].name, name_size);
		list[i].score = (double)(rand() % 1000) / 1000; // 0.0 ~ 1.0의 랜덤 점수
	}


	qsort(list, 30, sizeof(Student), compare);

	printf("성적으로 정렬한 결과 \n");
	print(list, student_size);
}

//이름 생성 함수
void generate_name(char* name, int size) {
	char alpha[] = "abcdefghijklmnopqrstuvwxyz"; 
	int key;

	for (int i = 0; i < size - 1; i++) { 
		key = rand() % (sizeof(alpha) - 1);
		name[i] = alpha[key];
	}
	name[size - 1] = '\0';
}


int compare(const void* a, const void* b) {
	double result;
	Student* student_a = (Student*)a; // a = &list
	Student* student_b = (Student*)b;

	result = (*student_a).score - student_b->score;

	if (result < 0) {
		return -1;	
	}
	else if (result == 0) {
		return 0;
	}
	else {
		return 1;
	}
}

void print(Student* student, int size) {
	for (int i = 0; i < size; i++) {
		printf("%4d %lf %s \n", (student+i)->number, (student+i)->score, student[i].name);
	}
}

03. 10개 정도의 속담을 문자열의 형태로 함수 set_proverb() 내부에 저장하고있다가 사용자가 set_proverb()을 호출하면인수로 받은 이중 포인터를 이용하여 외부에 있는 char형포인터 s를 설정하는 set_proverb()을 작성하고 테스트하라.

       

#include <stdio.h>

void set_proverb(char** q, int n);

int main() {
	int user;
	char* p = NULL;
	printf("몇 번째 속담을 선택하시겠습니까? ");
	scanf("%d", &user);
	
	set_proverb(&p, user);
	printf("선택된 속담 =  %s ", p);
}

void set_proverb(char** q, int n) {
	static char* array[10] = {
		"A bad workman shearer never had a good sickle.",
		"A bad workman (always) blames his tools.",
		"A bad workman quarrles with his tools.",
		"A bad thing never dies.",
		"a",
		"b",
		"c",
		"d",
		"f",
		"g" };

	*q = array[n-1];
}

04. 2차원 배열에 정수가 저장되어 있다고 가정한다. 우리가 가지고 있는 단 하나의 함수는 1차원 배열에 저장된정수의 합을 구하는 int get_sum(int array[], int size) 라고 가정하자. 2차원배열의 각 행에 대하여 get_sum() 을 호출하여서 각 행의 합을 구한후에, 이것들을 모두 합쳐서 전체 2차원 배열에 저장된정수들의 합을 구하는 프로그램을 작성하여보자.

(hint: 2차원배열은 m[][] 이라고 하면 m[0]은 첫 번째 행이고, m[1]은 두 번째 행을 가리킨다. 이것들은 또 1차원 배열이기도하다. 즉, 2차원 배열은 1차원 배열들의 모임이라고 생각할 수 있다.)   

#include <stdio.h>

int get_sum(int array[], int size) {
	int sum = 0;
	for (int i = 0; i < size; i++) {
		sum += array[i];
	}
	return sum;
}

int main() {
	int array[3][6] = {
		{10,10,10,10,10,10},
		{10,10,10,10,10,10},
		{10,10,10,10,10,10}
	};
	int sum_col_array[4] = { 0 };
	int row = sizeof(array) / sizeof(array[0]);
	int col = sizeof(array[0]) / sizeof(array[0][0]);

	for (int i = 0; i < row; i++) {
		sum_col_array[i] = get_sum(array[i], col);
	}

	for (int i = 0; i < row; i++) {
		sum_col_array[3] += sum_col_array[i];
	}

	printf("정수의 합 = %d", sum_col_array[3]);
}

05. 학생들의 성적이 scores라는 2차원 배열에 저장되어 있다고 가정하자. scores의 행은 한 학생에 대한 여러 번의 시험 성적을나타낸다. scores의 열은 한 시험에대한 여러 학생들의 성적이다. 학생별로 성적의 평균을 구하려고 한다 . 2차원배열의 각행이 1차원 배열임을 이용하여 다음과 같이 1차원 배열의 평균을 구하는 함수 get_average()를 호출하여 각 학생에 대한 평균 성적을 계산하여보자. 

double get_average(int list[], int n);

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define ROWS  3
#define COLS  6

double get_avg(int array[][COLS], int n) {
	int* p, * endp;
	p = &array[n][0];
	endp = &array[n][COLS - 1];
	int sum = 0;

	while (p <= endp)
		sum += *p++;

	return (double)sum / COLS;
}


int main() {
	int array[ROWS][COLS] = {
	{10,10,10,10,10,10},
	{10,10,10,10,10,20},
	{10,10,10,10,10,30}
	};

	for (int i = 0; i < ROWS; i++) {
		printf("%d행의 평균값 = %.0f \n", i, get_avg(array, i));
	}

}

06. 문자열의배열을 인수로 받아서 저장된 문자열을 전부 출력하는pr_str_array() 함수를작성하여 테스트하여보자. pr_str_array()는 다음과 같은 원형을 가진다.

void pr_str_array(char **dp, int n);

#include <stdio.h>

void pr_srt_array(char** dp, int n);

int main() {
	char *p[] = 
	{
		"A bad workman shearer never had a good sickle.",
		"A bad workman (always) blames his tools.",
		"A bad workman quarrles with his tools.",
		"A bad thing never dies.",
		"a",
		"b",
		"c",
		"d",
		"f",
		"g" 
	};
	int size = sizeof(p) / sizeof(p[0]);

	pr_srt_array(p, size);

}

void pr_srt_array(char** dp, int n) {
	for (int i = 0; i < n; i++) {
		printf("%s \n", *(dp+i)); //dp[i] 도 가능
	}
}

07. int형 배열과 int형 포인터를 받아서 포인터가 배열의 가장 큰 값을 가리키게 하는함수 set_max_ptr()을 구현하고 테스트하여보자. 

#include <stdio.h>

void get_max(int** q, int arr[], int size) {
	*q = arr;

	for (int i = 1; i < size; i++) {
		if (**q < arr[i])
			*q = arr + i;
	}
}

int main() {
	int m[6] = { 1,2,3,4,5,6 };
	int* p;
	get_max(&p, m, 6);

	printf("%d", *p);

}

08. 문자열을 가리키고 있는 포인터의 배열을 인수로 받아서 문자열을 알파벳 순으로 정렬시키는 함수 sort_strings()를 작성하고 테스트하여 보라. 다음과 같은 원형을 가진다.

#include <stdio.h>
#include <string.h>

void sort_strings(char* list[], int size);

int main() {
	char* s[] = { "src", "dst", "mycopy" };
	int size = sizeof(s) / sizeof(s[0]);

	sort_strings(s, size);

	for (int i = 0; i < size; i++) {
		printf("%s \n", s[i]);
	}
}

void sort_strings(char* list[], int size) {
	char* temp;
	for (int i = 0; i < size - 1; i++) {
		for (int j = 0; j < size - 1; j++) {
			if (strcmp(list[j], list[j + 1]) > 0) {
				temp = list[j];
				list[j] = list[j + 1];
				list[j + 1] = temp;
			}
		}
	}
}

09. 디지털 영상은 보통 2차원 배열로 표현된다. 각 배열 요소는 픽셀이라고 불린다. 흑백 영상의 경우, 하나의 픽셀은 보통 0에서 255의 값을 가지며 0은 검정색을, 255는 흰색을 나타낸다. 중간값은 회색을 나타낸다. 영상은 unsigned char image[ROW][COLS]에 저장되어 있다고 가정하고 픽셀 값이 128 미만이면 0으로 만들고 128 이상이면 255로 만들어보자.

 

 

1) 2차원 배열의 함수 매개변수 (가장 무난한 방법, 실력 향상엔 도움 X )

#include <stdio.h>

#define ROWS 6
#define COLS 8

void process_image(unsigned char image[][COLS]) { 
    for (int i = 0; i < ROWS; i++) {
        for (int j = 0; j < COLS; j++) {
            if (image[i][j] < 128) { 
                image[i][j] = 0;
            }
            else {
                image[i][j] = 255;
            }
        }
    }
}

int main() {
    
   

    unsigned char img_data[ROWS][COLS] = {
        {0, 255, 255, 255, 255, 0, 255, 255},
        {0, 0, 255, 255, 255, 255, 0, 255},
        {0, 0, 0, 255, 255, 255, 0, 255},
        {0, 0, 0, 0, 255, 255, 0, 255},
        {255, 255, 0, 0, 255, 255, 0, 255},
        {255, 255, 255, 0, 0, 0, 0, 255}
    };

    process_image(img_data);

    for (int i = 0; i < ROWS; i++) {
        for (int j = 0; j < COLS; j++) {
            printf("%3d ", img_data[i][j]);
        }
        printf("\n");
    }
}

 

 

2) 배열 포인터(문제의 의도와 가장 가까움)  

#include <stdio.h>

#define ROWS 6
#define COLS 8

void process_image(unsigned char (*image)[COLS]) {
    for (int i = 0; i < ROWS; i++) {
        for (int j = 0; j < COLS; j++) {
            if (image[i][j] < 128) {
                image[i][j] = 0;
            } else {
                image[i][j] = 255;
            }
        }
    }
}

int main() {
    unsigned char img_data[ROWS][COLS] = {
        {0, 255, 255, 255, 255, 0, 255, 255},
        {0, 0, 255, 255, 255, 255, 0, 255},
        {0, 0, 0, 255, 255, 255, 0, 255},
        {0, 0, 0, 0, 255, 255, 0, 255},
        {255, 255, 0, 0, 255, 255, 0, 255},
        {255, 255, 255, 0, 0, 0, 0, 255}
    };

    process_image(img_data);

    for (int i = 0; i < ROWS; i++) {
        for (int j = 0; j < COLS; j++) {
            printf("%3d ", img_data[i][j]);
        }
        printf("\n");
    }

    return 0;
}

 

3) 이차원 배열과 일반 포인터 (2차원 배열이 어떻게 구성되는지 이해하기 좋은 코드이다) 

#include <stdio.h>

#define ROWS 6
#define COLS 8

void process_image(unsigned char* image) { // 매개변수 확인
    for (int i = 0; i < ROWS; i++) {
        for (int j = 0; j < COLS; j++) {
            if (image[i * COLS + j] < 128) { //인덱스 확인
                image[i * COLS +j] = 0;
            }
            else {
                image[i* COLS + j] = 255;
            }
        }
    }
}

int main() {
    
   

    unsigned char img_data[ROWS][COLS] = {
        {0, 255, 255, 255, 255, 0, 255, 255},
        {0, 0, 255, 255, 255, 255, 0, 255},
        {0, 0, 0, 255, 255, 255, 0, 255},
        {0, 0, 0, 0, 255, 255, 0, 255},
        {255, 255, 0, 0, 255, 255, 0, 255},
        {255, 255, 255, 0, 0, 0, 0, 255}
    };

    process_image(img_data);

    for (int i = 0; i < ROWS; i++) {
        for (int j = 0; j < COLS; j++) {
            printf("%3d ", img_data[i][j]);
        }
        printf("\n");
    }
}

 

4) 이중 포인터 와 동적 할당활용

#include <stdio.h>
#include <stdlib.h>

#define ROWS 6
#define COLS 8

void process_image(unsigned char** image) { // 매개변수 확인
    for (int i = 0; i < ROWS; i++) {
        for (int j = 0; j < COLS; j++) {
            if (image[i][j] < 128) {
                image[i][j] = 0;
            }
            else {
                image[i][j] = 255;
            }
        }
    }
}

int main() {
    
    
    //* 2차원 배열 동적 할당
    //unsigned char* image[ROWS]; //아래와 역할 동일
    unsigned char **image = (unsigned char**)malloc(ROWS * sizeof(unsigned char*));
    for (int i = 0; i < ROWS; i++) {
        image[i] = (unsigned char*)malloc(COLS * sizeof(unsigned char));
    }
 

    unsigned char img_data[ROWS][COLS] = {
        {0, 255, 255, 255, 255, 0, 255, 255},
        {0, 0, 255, 255, 255, 255, 0, 255},
        {0, 0, 0, 255, 255, 255, 0, 255},
        {0, 0, 0, 0, 255, 255, 0, 255},
        {255, 255, 0, 0, 255, 255, 0, 255},
        {255, 255, 255, 0, 0, 0, 0, 255}
    };

    // 동적 할당된 배열에 예시 이미지 데이터를 복사
    for (int i = 0; i < ROWS; i++) {
        for (int j = 0; j < COLS; j++) {
            image[i][j] = img_data[i][j];
        }
    }

    // 이미지 처리 함수 호출
    process_image(image);

    // 처리된 결과 출력
    for (int i = 0; i < ROWS; i++) {
        for (int j = 0; j < COLS; j++) {
            printf("%3d ", image[i][j]);
        }
        printf("\n");
    }

    //* 메모리 해제
    for (int i = 0; i < ROWS; i++) {
        free(image[i]);
    }


}

 


10. 크기가 3 X 3인 2차원 배열을 다른 2차원 배열로 복사하는 함수 void array_copy(int src[][WIDTH], int dst[][WIDTH])를

구현하고 테스트하여보라. 수행 속도를 위하여 배열 첨자 방법 대신에포인터를 사용해보자.

#include <stdio.h>

#define HEIGHT 3   
#define WIDTH 3

void array_copy(int src[][WIDTH], int dst[][WIDTH]);
void print_array(int a[][WIDTH]);

int main() {
	int src[HEIGHT][WIDTH] = { 100,30,67,89,50,12,19,60,90 };
	int dst[HEIGHT][WIDTH];
	array_copy(src, dst);
	
	printf("<원본 2차원 배열>\n");
	print_array(src);
	printf("<복사본 2차원 배열> \n");
	print_array(dst);
}

void array_copy(int src[][WIDTH], int dst[][WIDTH]) {
	int* p = src;  // &src[0][0] 도 가능
	int* endp = &src[HEIGHT - 1][WIDTH - 1];
	
	int* dst_p = dst;

	while (p <= endp) {
		*dst_p = *p++;
		dst_p++;
	}
}

void print_array(int a[][WIDTH]) {
	for (int i = 0; i < HEIGHT; i++) {
		for (int j = 0; j < WIDTH; j++) {
			printf("%d ", a[i][j]);
		}
		printf("\n");
	}
}

11. (ADVANCED) 생명게임(game of life)라고 불리는 인구 증가 게임을 구현하여보자. John H, Conway에 의해 발명된 생명 게임은 출생과 생존, 죽음의 모델을 가정한다. 이 게임은 가로와 세로로 20개씩의 셀을 갖는 보드 위에서 게임을 한다 각 셀은 비어 있거나, 생명체를 나타내는 0값을가질 수 있다. 각 셀은 8개의 이웃을 갖는다. 생명체의 다음세대는 다음 규칙에 따라 결정된다.  

 

보드는 2차원 배열을 이용하여 생성하고 포인터를 최대한 많이사용하여 생명 게임의 속도를 높이도록 하라. 

 

( 11번 문제는 너무 어려워서 보류.. 실력을 쌓고 돌아오겠다.)

 

 

01. 책을 구조체로 표현하자. 책에 대한 정보는 제목(문자열, 최대 100문자), 저자(문자열, 최대 100문자), 장르(열거형) 등으로 구성된다. 구조체 book을 이용하여 책 정보를 표현해보자. 책의 장르는 COMIC, SF, DOCU, DRAMA 중의 하나로 분류하고 열거형으로 구현된다. {"바람과 함꼐 사라지다", "마가렛 미첼", DRAMA }의 값을 가지는 구조체 변술르 생성했다가 다시 화면에 출력해보자.

#include <stdio.h>

typedef enum { COMIC, SF, DOCU, DRAMA }GENRE;

struct book {
	char title[100];
	char author[100];
	GENRE type;
};

int main() {
	char* genre[] = { "COMIC", "SF","DOCU", "DRAMA" };
	struct book a = { "바람과 함께 사라지다", "마가렛 미첼", DRAMA };

	printf("{ %s, %s, %s }", a.title, a.author, genre[a.type]);
}

02. 1번 문제에서 정의한 2개의 구조체를 받아서 책의 저자가 일치하는지를 검사하는함수 equal_author()을 작성해보자. equal_author()은 다음과 같은 원형을 가진다. b1과 b2의 저자가 같으면 1을 반환하고 그렇지 않으면 0을 반환한다. 함수를 작성하여 테스트 한다.

#include <stdio.h>
#include <string.h>

typedef enum { COMIC, SF, DOCU, DRAMA }GENRE;

struct book {
	char title[100];
	char author[100];
	GENRE type;
};

int equal_author(struct book b1, struct book b2) {
	if (strcmp(b1.author,b2.author)==0) {  // b1.author == b2.author (X)
		return 1;
	}
	return 0;
}

int main() {
	char* genre[] = { "COMIC", "SF","DOCU", "DRAMA" };
	struct book b1 = { "노인과 바다", "헤밍웨이", DRAMA };
	struct book b2 = { "누구를 위하여 종을 울리나", "헤밍웨이", DRAMA };

	printf("b1 = { %s, %s, %s} \n", b1.title, b1.author, genre[b1.type]);
	printf("b2 = { %s, %s, %s} \n", b2.title, b2.author, genre[b2.type]);
	printf("equal_author()의 반환값: %d \n",equal_author(b1, b2));

}

03. 구조체를 이용하여 이메일을 표현할 수 있는 구조체를 정의하고, 적당한 초기값을 부여하고 출력하는 프로그램을 작성하라, 구조체의 멤버는 제목(title), 수신자(sender), 발신자(receiver), 내용(content), 날짜(date), 우선순위(pri) 등으로 구성된다.

#include <stdio.h>

struct mail {
	char title[50];
	char sender[50];
	char receiver[50];
	char content[100];
	char date[20];
	int pri;
};

int main() {
	struct mail a = { "안부 메일","chulsoo@hankuk.ac.kr","hsh@hankuk.ac.kr","안녕하십니까? 새해 복 많이 받으세요.","2023/1/1",1 };
	printf("제목: %s \n", a.title);
	printf("수신자: %s \n", a.sender);
	printf("발신자: % s \n", a.receiver);
	printf("내용: %s \n", a.content);
	printf("날짜: %s \n", a.date);
	printf("우선순위: %d \n", a.pri);
}

04. 구조체를 이용하여 복소수를 다음과 같이 정의하고 복소수의 덧셈을 수행하는 함수를 작성하고 테스트하시오.

#include <stdio.h>

struct complex {
	double real;
	double imag;
};

struct complex complex_add(struct complex c1, struct complex c2);

int main() {
	struct complex c1, c2, c3;
	c1 = (struct complex){ 1,2 };
	c2 = (struct complex){ 2,3 };
	c3 = complex_add(c1, c2);

	printf("%.2f+%.2fi \n", c1.real, c1.imag);
	printf("%.2f+%.2fi \n", c2.real, c2.imag);
	printf("%.2f+%.2fi \n", c3.real, c3.imag);
}

struct complex complex_add(struct complex c1, struct complex c2) {
	struct complex c3;
	c3.real = c1.real + c2.real;
	c3.imag = c1.imag + c2.imag;

	return c3;
}

05. 2차원 평면에서 점은 (x, y) 좌표로 나타낼 수 있다. 따라서 하나의 점은 다음과 같은 point라는 구조체로 정의할 수 있다. 이 point 구조체를 받아서 두 점의 좌표가 일치하면 1을 반환하고 그렇지 않으면 0을 반환하는 함수 int equal(struct point p1, struct point p2)를 작성하고 테스트하라.

#include <stdio.h>

struct point {
	int x, y;
};

int equal(struct point p1, struct point p2);

int main() {
	struct point a = { 1,2 };
	struct point b = { 3,5 };
	
	if (equal(a, b)) {
		printf("(%d, %d) == (%d, %d) \n", a.x, a.y, b.x, b.y);
	}
	else {
		printf("(%d, %d) != (%d, %d) \n", a.x, a.y, b.x, b.y);
	}
}

int equal(struct point p1, struct point p2) {
	if ((p1.x == p2.x) && (p1.y == p2.y)) {
		return 1;
	}
	return 0;
}

06. 앞의문제에서 equal() 함수를 다음과 같이 구조체의 포인터를 받도록 변경하여서 작성하고 테스트하라.

#include <stdio.h>

struct point {
	int x, y;
};

int equal(struct point *p1, struct point *p2);

int main() {
	struct point a = { 1,2 };
	struct point b = { 3,5 };

	if (equal(&a, &b)) {
		printf("(%d, %d) == (%d, %d) \n", a.x, a.y, b.x, b.y);
	}
	else {
		printf("(%d, %d) != (%d, %d) \n", a.x, a.y, b.x, b.y);
	}
}

int equal(struct point *p1, struct point *p2) {
	if ((p1->x == p2->x) && ((*p1).y == (*p2).y)) {
		return 1;
	}
	return 0;
}

07. 2차원 공간에 있는 점의 좌표를 받아서 이 점이 속하는 사분면의 번호를 반환하는 함수 int quadrant(struct point p)를 작성하고 테스트하라. 앞의 point 구조체를 사용한다.

#include <stdio.h>

struct point {
	int x, y;
};

int quadrant(struct point p);

int main() {
	struct point p = { -1,2 };
	printf("(%d, %d)의 사분면 = %d \n", p.x, p.y, quadrant(p));
}

int quadrant(struct point p) {
	if (p.x > 0 && p.y > 0) return 1;
	else if (p.x < 0 && p.y > 0) return 2;
	else if (p.x < 0 && p.y < 0) return 3;
	else return 4;

}

08. 원의 중심을 나타내는 point 구조체를 사용할 수 있다. 원을나타내는 circle 구조체를 정의해보자. 이 circle 구조체를 받아서 다음과 같은기능을 하는 함수를 작성하고 테스트해보자.

#define PI 3.14

(a) 원의 면적을 계산하는 함수 double area(struct circle c)

double area(struct circle c) {
	return c.radius * c.radius * PI;
}

(b) 원의 둘레를 계산하는 함수 double perimeter(struct circle c)

double perimeter(struct circle c) {
	return c.radius * 2 * PI;
}

 

(c) typedef을 사용하여 struct circle을 CIRCLE로 정의 한 후에 (a)와 (b)를 다시 작성해보자. 

#include <stdio.h>

#define PI 3.14

struct point {
	int x, y;
};

typedef struct circle {
	struct point center;
	double radius;
}CIRCLE;

double area(CIRCLE c); 
double perimeter(CIRCLE c);

int main() {
	CIRCLE c = { 0,0,10}; // {0,0,10} { .center.x = 0, .center.y = 0, .radius = 10} 둘다 가능
	
	printf("원의 중심점: (%d, %d) \n", c.center.x, c.center.y);
	printf("원의 반지름: %.0lf \n", c.radius);
	printf("원의 면적=%.2lf \n", area(c));
	printf("원의 둘레=%.2lf \n", perimeter(c));
}


double area(CIRCLE c) {
	return c.radius * c.radius * PI;
}

double perimeter(CIRCLE c) {
	return c.radius * 2 * PI;
}

09. 각각의 음식에 대하여 음식의 이름, 칼로리 정보를 구조체로 표현한다. 사용자가 하루 동안 먹은음식들을 입력받아 구조체의 배열에 저장하고 하루 동안 먹은 음식의 칼로리를 계산하는 프로그램을 작성해보자.

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

struct food {
	char name[100];
	int calories;
};

int sum_calories(struct food* food_array, int size);

int main() {
	struct food food_array[3] = { { "hambuger", 900 },{ "bulgogi", 500 },{ "sushi", 700 } };
	
	int size = sizeof(food_array) / sizeof(struct food);
	printf("총 칼로리=%d \n", sum_calories(food_array, size));
}

int sum_calories(struct food* food_array, int size) {
	int sum = 0;
	for (int i = 0; i < size; i++) { //  sizeof 연산불가
		sum += food_array[i].calories;  // (food_array+i)->calories 도 가능
	}
	return sum;
}

// if 매개변수가 (struct food food_array[]) , (struct food *food_array) -> sizeof 연산 불가능
// 매개변수가 (char *s),(char s[]) 의 경우도 sizeof 불가 -> starlen 사용하기 (단, char *s[] 의 경우 가능)

 


10. 직원을 나타내는 구조체 employee가 사번(정수), 이름(문자열), 전화번호(문자열), 나이(정수) 등으로 구성된다. 구조체의 배열을 선언하고 10명의 데이터로 초기화해보자. 이중에서 나이가 20 이상 30이하인 직원을 찾아서 출력하도록 해보자. typedef을 사용하여서 구조체 타입을 정의해서 사용해보자.

#include <stdio.h>

typedef struct {
	int num;
	char name[100];
	int age;
	char tel[100];
}EMPLOYEE;

int main() {
	EMPLOYEE people[10] = {
		 { 1, "홍길동1", 20, "111-1111" },
		 { 2, "홍길동2", 25, "111-1112" },
		 { 3, "홍길동3", 60, "111-1113" },
		 { 4, "홍길동4", 40, "111-1114" },
		 { 5, "홍길동5", 50, "111-1115" },
		 { 6, "홍길동6", 45, "111-1116" },
		 { 7, "홍길동7", 32, "111-1117" },
		 { 8, "홍길동8", 23, "111-1118" },
		 { 9, "홍길동9", 29, "111-1119" },
		 { 10, "홍길동10", 62, "111-1120" } 
	};

	for (int i = 0; i < sizeof(people) / sizeof(people[0]); i++) {
		if ((people[i].age >= 20) && (people[i].age <= 30)) {
			printf("이름: %s 나이=%d \n", people[i].name, people[i].age);
		}
	}
}

11. 전화번호부를 구성하기 위하여 이름, 집전화번호, 휴대폰 번호로 구성되는 구조체를 정의한 후에 이 구조체의 배열을 선언하여 전화번호부를 구성한다. 3명의 데이터를 사용자로부터 받아서 저장하여 보라. 사용자로부터 이름을 입력받아서 전화번호를검색하는 프로그램을 작성해보자.

#include <stdio.h>
#include <string.h>

struct tel_book {
	char name[20];
	char home_tel[100];
	char cel_tel[100];
};

int main() {
	struct tel_book list[3];
	char find_name[100];
	int size = sizeof(list) / sizeof(list[0]);

	for (int i = 0; i < size; i++) {
		printf("이름을 입력하시오: ");
		scanf("%s", list[i].name);
		printf("집전화번호: ");
		scanf("%s", list[i].home_tel);
		printf("휴대폰 번호: ");
		scanf("%s", list[i].cel_tel);
		printf("\n");
	}

	printf("검색할 이름: ");
	scanf("%s", find_name);
	for (int i = 0; i < size; i++) {
		if (strcmp(find_name, list[i].name) == 0) {
			printf("집전화번호: %s \n", list[i].home_tel);
			printf("휴대폰 번호: %s \n", list[i].cel_tel);
			break;
		}
	}

}

12. 포커 게임에서 사용되는 카드를 구조체 card로 정의하고 52개의 카드를 구조체의 배열로 나타내라. 52개의 카드를 적절한 값으로 초기화 하고 값들을 출력하는 프로그램을 작성해보자. card 구조체는 다음과 같은 멤버값을 가진다고 가정해보자. 먼저 카드의 수는 정수로 표현되며 멤버의 이름은 value라고 하라. vlaue는 1부터 13까지의 값을 가질 수 있다. 카드의 타입은 하나의 문자로 표현되며 멤버의 이름은 suit라고 하라. suit는 'c', 'd', 'h', 's'의 값을 가질 수 있다.

#include <stdio.h>

struct card {
	char suit;
	int value;
};


int main() {
	struct card cards[52];
	int size_st = sizeof(cards) / sizeof(struct card);

	int arr[] = { 'c', 'd','h', 's' };
	int* p = arr;

	for (int i = 0; i < size_st; i++) { 
		cards[i].suit = *p;
		cards[i].value = (i % 13 + 1);

		if ((i % 13 + 1) == 13) {
			p++;
		}
	}


	for (int i = 0; i < size_st; i++) {
		printf("%d:%c ", cards[i].value, cards[i].suit);
	}
}

13. 삼각형, 사각형, 원을 동시에 표현할 수 있는 공용체를 설계하라. 삼각형은 밑변과 높이, 사각형은 가로와 세로, 원은 반지름만을 저장하도록해보자. 현재의 공용체가 표현하고 있는 도형의 종류는 열거형 변수를 사용하여 나타낸다. 사용자로부터 도형의 종류와 도형의 데이터를 받아서 저장하여보자.

#include <stdio.h>

enum type_list{TRI, RECT, CIRC};

struct shape {
	int type;
	union {
		struct { int base, height; }tri;
		struct { int width, height; }rect;
		struct { int radius; }circ;
	}data;
};

int main() {
	struct shape p;
	
	printf("도형의 타입을 입력하시오(0,1,2): ");
	scanf("%d", &p.type);

	switch (p.type) {
	case TRI:
		printf("밑변과 높이를 입력하시오(예를 들어서 100 200): ");
		scanf("%d %d", &p.data.tri.base, &p.data.tri.height);
		printf("면적은 %d \n",(int)(0.5 * p.data.tri.base * p.data.tri.height));
		break;
	case RECT:
		printf("밑변과 높이를 입력하시오(예를 들어서 100 200): ");
		scanf("%d %d", &p.data.rect.width, &p.data.rect.height);
		printf("면적은 %d \n", (int)(p.data.rect.width * p.data.rect.height));
		break;
	case CIRC:
		printf("반지름을 입력하시오: ");
		scanf("%d", &p.data.circ.radius);
		printf("면적은 %d \n", (int)(3.14 * p.data.circ.radius * p.data.circ.radius));
		break;
	default: 
		printf("도형의 타입을 잘못 입력했습니다.");
	}
}


// (int) 형변환 필수
// ex) printf("%d",3.14); - > 이상한 값 출력, printf("%d,(int)3.14);

14. 데이터베이스의 기능을 하는 간단한 프로그램을 작성하여보자. 이 프로그램은 mpc와 같은 음악파일을 관리한다. 사용자는 음악 파일을 추가, 삭제, 출력할수 있으며 제목을 가지고 특정 곡을 탐색할수 있다. 사용자 인터페이스는 다음과 같다.

#include <stdio.h>
#include <string.h>

enum genre_type {SONG, POP, CLASSIC, MOVIE};
enum menu_list { ADD = 1, PRINT, SEARCH, END };

typedef struct music_component {
	char title[100];
	char singer[100];
	char location[100];
	enum genre_type genre;
}MUSIC;

void print_menu();
void add(MUSIC *music, int count);
void print(MUSIC* music, int count);
void search(MUSIC* music, int count);

int main() {
	MUSIC music[30] = { 0 };
	enum menu_list user;
	int count = 0;

	while (1) {
		print_menu();
		scanf("%d", &user);
		getchar(); // scanf() 다음에 gets_s를 쓰는 경우 getchar()로 버퍼를 비워야함
		switch (user) {
			case ADD:
				add(music,count);
				count++;
				break;

			case PRINT:
				print(music,count);
				break;

			case SEARCH:
				search(music,count);
				break;

			case END:
				return 0; // switch문에서는 break로 무한반복문을 빠져나갈수 없으므로 goto 혹은 return 을 사용하여 종료한다.

			default:
				printf("메뉴에 없는 번호입니다. 다시 입력해주세요 \n");
		}
		printf("\n");
	}
}

void print_menu() {
	printf("================== \n");
	printf("1. 추가 \n");
	printf("2. 출력 \n");
	printf("3. 검색 \n");
	printf("4. 종료 \n");
	printf("================== \n");
	printf("정수값을 입력하시오: ");
}

void add(MUSIC* music,int count) {
	printf("제목: ");
	gets_s(music[count].title, sizeof(music[0].title));
	printf("가수: ");
	scanf("%s", music[count].singer);
	printf("위치: ");
	scanf("%s", music[count].location);
	printf("장르(0:가요, 1:팝, 2:클래식, 3: 영화음악)");
	scanf("%d", &music[count].genre);
}

void search(MUSIC *music, int count) {
	char user[100];
	char* genre_list[] = { "가요","팝","클래식","영화음악" };
	
	printf("제목을 입력하시오: ");
	gets_s(user, sizeof(user));

	for (int i = 0; i < count; i++) {
		if (strcmp(user, music[i].title) == 0) {
			printf("제목: %s \n", music[i].title);
			printf("가수: %s \n", music[i].singer);
			printf("위치: %s \n", music[i].location);
			printf("장르: %s \n", genre_list[music[i].genre]);
			return;
		}
	}
}

void print(MUSIC *music,int count) {
	char* genre_list[] = { "가요","팝","클래식","영화음악" };
	for (int i = 0; i < count; i++) {
		printf("제목: %s \n", music[i].title);
		printf("가수: %s \n", music[i].singer);
		printf("위치: %s \n", music[i].location);
		printf("장르: %s \n", genre_list[music[i].genre]);
	}
}

15. 도서관에서 소장 도서들을 관리할 수 있는 프로그램을 작성해보자. 책 정보를 저장할 수 있는 구조체를 정의한다. 구조체는책 번호, 제목, 대출 여부 등의 정보를 저장할 수 있어야 한다. 많은 책을 저장하려면 구조체의 배열을 생성하여야 할 것이다. 다음과 같은 메뉴를 생성한 후에 각 메뉴 항목을 구현한다. (14번과 푸는 방식이 동일하다)

#include <stdio.h>
#include <string.h>

enum menu_list {FIND_NUM = 1, FIND_WRITER, FIND_TITLE , ADD, PRINT_NUM , END };

typedef struct {
	int num;
	char writer[50];
	char title[50];
}LIBRARY;

void print_menu();
void find_num(LIBRARY *book,int count);
void find_writer(LIBRARY* book, int count);
void find_title(LIBRARY* book, int count);
void add(LIBRARY* book, int count);
void print_num(int count);

int main() {
	LIBRARY book[50];
	enum menu_list u;
	int count = 0;

	while (1) {
		print_menu();
		scanf("%d", &u);
		getchar();

		switch (u) {
		case FIND_NUM:
			find_num(book, count);
			break;
		case FIND_WRITER:
			find_writer(book, count);
			break;
		case FIND_TITLE:
			find_writer(book, count);
			break;
		case ADD:
			add(book, count);
			count++;
			break;
		case PRINT_NUM:
			print_num(count);
			break;

		case END:
			return 0;

		default:
			printf("메뉴를 잘못 입력하였습니다. 다시 입력해주세요 \n");
		}
		printf("\n");
	}
}


void print_menu() {
	printf("======================\n");
	printf(" 1. 도서 번호로 책 찾기 \n");
	printf(" 2. 저자 이름으로 책 찾기 \n");
	printf(" 3. 제목으로 책 찾기 \n");
	printf(" 4. 새로운 책 추가 \n");
	printf(" 5. 도서관이 소장한 도서의 수 표시 \n");
	printf(" 6. 종료 \n");
	printf("======================\n");
	printf("메뉴 중 하나를 선택하시오: ");
}

void find_num(LIBRARY* book, int count) {
	int user_num;
	printf("도서 번호를 입력하시오: ");
	scanf("%d", &user_num);
	for (int i = 0; i < count; i++) {
		if (user_num == book[i].num) {
			printf("도서 번호: %d \n", book[i].num);
			printf("저자 이름: %d \n", book[i].writer);
			printf("제목: %d \n", book[i].title);
			return;
		}
	}
	printf("해당 도서 번호의 책이 없습니다.");
}

void find_writer(LIBRARY* book, int count) {
	char user_writer[50];
	printf("저자 이름을 입력하시오: ");
	gets_s(user_writer, sizeof(user_writer));
	for (int i = 0; i < count; i++) {
		if (strcmp(user_writer, book[i].writer) == 0) {
			printf("도서 번호: %d \n", book[i].num);
			printf("저자 이름: %d \n", book[i].writer);
			printf("제목: %d \n", book[i].title);
			return;
		}
	}
	printf("해당 저자의 책이 없습니다.");
}

void find_title(LIBRARY* book, int count) {
	char user_title[50];
	printf("제목을 입력하시오: ");
	gets_s(user_title, sizeof(user_title));
	for (int i = 0; i < count; i++) {
		if (strcmp(user_title, book[i].title) == 0) {
			printf("도서 번호: %d \n", book[i].num);
			printf("저자 이름: %d \n", book[i].writer);
			printf("제목: %d \n", book[i].title);
			return;
		}
	}
	printf("해당 제목의 책이 없습니다.");
}

void add(LIBRARY* book, int count) {
	printf("도서 번호를 입력하시오: ");
	scanf("%d", &book[count].num);
	getchar(); 
	printf("저자 이름을 입력하시오: ");
	gets_s(book[count].writer, sizeof(book[count].writer));
	printf("제목을 입력하시오: ");
	gets_s(book[count].title, sizeof(book[count].title));

}

void print_num(int count) {
	printf("도서관이 소장한 도서의 수는 %d 입니다. \n", count);
}

16. 어느 학교나 학기가 끝나면학과 내에서 가장 평점이 높은 학생을 선발하여서 장학금을 수여한다. 가장 평점이 높은 학생을 찾아서 학생의 이름과 학번, 평점을 화면에 출력하는 프로그램을 작성하여보자. 학생에 대한 정보는 구조체를 이용하여서 표현한다. 학생들이 여러 명이므로 구조체의 배열을사용하는 것이 좋겠다. 적당한 값으로 초기화를 시키자. 평점이최대인 학생을 찾는 알고리즘은정수의 배열에서 최대값을 찾는 것과 동일하다.           

 

(방법 1)

#include <stdio.h>

struct student {
	int number;
	char name[50];
	double score;
};

struct student list[] = { { 20180001, "홍길동", 4.2 },
{ 20180002, "김철수", 3.2 },
{ 20180002, "김영희", 3.9 } };

int main() {
	struct student list[] = { 
		{ 20180001, "홍길동", 4.2 },	
		{ 20180002, "김철수", 3.2 },
		{ 20180002, "김영희", 3.9 } };
	int max = 0;
	for (int i = 0; i < sizeof(list) / sizeof(list[0]); i++) {
		if (list[i].score > list[max].score) {
			max = i;
		}
	}
	
	printf("평점이 가장 높은 학생은 (이름: %s, 학번: %d, 평점: %.2f)입니다. ", list[max].name, list[max].number, list[max].score);

}

 

(방법 2, 문제에서 원하는 풀이법)

#include <stdio.h>

struct student {
	int number;
	char name[50];
	double score;
};

struct student list[] = { { 20180001, "홍길동", 4.2 },
{ 20180002, "김철수", 3.2 },
{ 20180002, "김영희", 3.9 } };

int main() {
	struct student list[] = { 
		{ 20180001, "홍길동", 4.2 },	
		{ 20180002, "김철수", 3.2 },
		{ 20180002, "김영희", 3.9 } };
	
	struct student max = list[0];

	for (int i = 0; i < sizeof(list) / sizeof(list[0]); i++) {
		if (list[i].score > max.score) {
			max = list[i];
		}
	}
	
	printf("평점이 가장 높은 학생은 (이름: %s, 학번: %d, 평점: %.2f)입니다. ", max.name, max.number, max.score);

}

01. 사용자로부터 문자열을 입력받아서 역순으로 출력하는 프로그램을 작성하라.

방법1 

#include <stdio.h>

void print() {
	static int a = 0;
	char c = getchar();
	if (c != '\n') {
		if (a == 0) {
			a = 1;
			printf("역순 문자열: ");
		}
		print();
		putchar(c);
	}
}

int main() {
	printf("문자열을 입력하시오: ");
	print();
}

방법 2

#include <stdio.h>
#include <string.h>

void reverse_print(char a[], int len) {
	for (int i = len - 1; i >= 0; i--) {
		printf("%c", a[i]);
	}
}


int main() {
	char a[20];
	printf("문자열을 입력하시오: ");
	scanf("%s", a);
	reverse_print(a, strlen(a));
}

방법 3

#include <stdio.h>
#include <string.h>

void reverse(char *s, int len) {
	for (int i = 0; i < len; i++) {
		printf("%c", s[len - 1 - i]);
	}
}

int main() {
	char a[20];
	printf("문자열을 입력하시오: ");
	scanf("%s", a);
	reverse(a, strlen(a));
}

02. 문자열을입력으로 받아서 문자열에 포함된 모든 공백 문자를삭제하는 함수를 작성하고 테스트하라

#include <stdio.h>

int main() {
	char a[100];
	char b[100];
	int j = 0;
	printf("문자열을 입력하시오: ");
	gets_s(a, sizeof(a));

	for (int i = 0; a[i] != '\0'; i++) {
		if (a[i] != ' ') {
			b[j] = a[i];
			j++;
		}
	}
	b[j] = '\0';

	printf("공백 제거 문자열 = %s", b);
}

03. 문자열을 입력으로 받아서 사용자가 지정하는 문자를 삭제하는 함수를 작성하고 테스트하라.

#include <stdio.h>

int main() {
	char a[50], b[50];
	char c;
	int j = 0;
	printf("문자열을 입력하시오: ");
	scanf("%s", a);
	printf("제거할 문자: ");
	scanf("%c", &c);

	for (int i = 0; a[i] != '\0'; i++) {
		if (a[i] != c) {
			b[j] = a[i];
			j++;
		}
	}
	b[j] = '\0';

	printf("결과 문자열 = %s ", b);
}

04. 문자열 안에 포함된 특정한 무자의 개수를세는 함수 int str(char *s, int c)를 작성하라. s는 문자열이고 c는 개수를 셀 문자이다.  strlen(*s) x-> strlen(s) o

#include <stdio.h>

int str_chr(char* s, int c) {
	int count = 0;
	for (int i = 0; s[i] != '\0'; i++) {
		if (s[i] == c)
			count++;
	}
	return count;
}

int main() {
	char a[50];
	int c, count;
	printf("문자열을 입력하시오: ");
	gets_s(a, sizeof(a));
	printf("문자를 입력하시오: ");
	c = getchar();
	count = str_chr(a, c);
	printf("\na의 개수: %d", count);
}

05. 사용자로부터 받은 문자열에서 각 문자가 나타나는 빈도를 계산하여 출력하는프로그램을작성하시오.

#include <stdio.h>

int main() {
	char a[100];
	int alpha[26] = { 0 };
	printf("문자열을 입력하시오: ");
	gets_s(a, sizeof(a));
	for (int i = 0; a[i] != '\0'; i++) {
		if (a[i] != ' ')
			alpha[a[i] - 'a']++;
	}
	for (int i = 'a'; i <= 'z'; i++) {
		printf("%c: %d  \n", i, alpha[i - 'a']);
	}
}

06. 문자열을사용자로부터 받아서 알파벳 문자의 개수, 숫자의 개수, 기타 특수 문자의 개수를 출력하는 프로그램을 작성하여보자.

#include <stdio.h>
#include <ctype.h>

int main() {
	char a[100];
	int al = 0, num = 0, etc = 0;

	printf("문자열을 입력하시오: ");
	scanf("%s", &a);
	printf("\n");

	for (int i = 0; a[i] != '\0'; i++) {
		if (isalpha(a[i]))
			al++;
		else if (isdigit(a[i]))
			num++;
		else
			etc++;
	}
	printf("문자열 안의 알파벳 문자의 개수: %d \n", al);
	printf("문자열 안의 숫자의 개수: %d \n", num);
	printf("문자열 안의 기타 문자의 개수: %d \n", etc);
}

07. 사용자에게 질문을 제시하고 답변을 받아서 긍정적이면 1을 반환하고 부정이면 0을 반환하는 함수 get_response(char *prompt)를 작성하고 테스트하라. 여기서 매개 변수 prompt는 사용자에게 제시하는 질문이다. 긍정을 의미하는 문자열은 "YES", "Yes" , "yes",  "OK", "ok"로 가정하라. 부정을 의미하는 문자열은 은 "NO", "No", "no"로 가정하라. 대소문자는 구별하지 않는다. (고려할점: tolower 혹은 toupper를 문자 하나씩만 바꾸는 것이기에  문자열을 바꿀 경우 반복문이 필요하다.) 

 

 

#include <stdio.h>
#include <ctype.h>
#include <string.h>

int get_response(char* prompt) {
	for (int i = 0; prompt[i] != '\0'; i++) {
		prompt[i] = tolower(prompt[i]);
	}

	if (strcmp(prompt, "yes")==0||strcmp(prompt,"ok")==0) {
		return 1;
	}
	else {
		return 0;
	}
}

int main() {
	char a[10];
	printf("게임을 하시겠습니까: ");
	scanf("%s", &a);

	if (get_response(a)) {
		printf("긍정적인 답변입니다. ");
	}
	else {
		printf("부정적인 답변입니다.");
	}
}

08. 사용자가 입력한 문자열에서 단어의 개수를 계산하여 화면에 출력하는프로그램을 작성하여보자.
(단어의 개수 구하는 문자열: char b = " ,\n\t")

#include <stdio.h>
#include <string.h>

int main() {
	int count = 0;
	char a[100];
	char tok[] = " ,\t\n";
	char* token;
	printf("문자열을 입력하시오: ");
	gets_s(a, sizeof(a));
	
	token = strtok(a, tok);
	while (token != NULL) {
		count++;
		token = strtok(NULL, tok);
	}

	printf("단어의 수는 %d입니다.", count);
}

09. 흔히 패스워드를 입력받을 때는 사용자가 입력한 문자 대신에 *문자를 표시한다. _getch()를 이용하여 사용자가 입력한 문자를 비밀스럽게 입력받는 프로그램을 작성하여보자. 

#include <stdio.h>
#include <conio.h>

int main() {
	int c, i;
	char a[9];
	printf("패스워드를 입력하시오: ");
	for (i = 0; i < sizeof(a) - 1; i++) { //  sizeof(a) -1 임을 유의하자, 문자열 배열이기 때문에 '\0'문자를 위해 1 빼야함
		c = _getch();
		if (c == '\r')
			break;
		a[i] = c;
		printf("*");
	}
	a[i] = '\0';
	printf("\n입력된 패스워드는 %s입니다.", a);
}

10. 사용자가 입력한 문자열에서 특정한 단어의 개수를 게산하여 화면에 출력하는 프로그램을 작성하여보자. 

#include <stdio.h>
#include <string.h>

int main() {
	char a[100], b[10];
	int count = 0; 
	char* ad;
	
	printf("문자열을 입력하시오: ");
	gets_s(a, sizeof(a));
	printf("단어: ");
	scanf("%s", b);

	ad = strstr(a, b);
	while (ad != NULL) {
		count++;
		ad = strstr(ad + 1, b);
	}
	printf("\n%s의 개수: %d", b, count);
}
// 잘못된 코드 

int main() {
	char a[100], b[10];
	int count = 0;
	char* token;   

	printf("문자열을 입력하시오: ");
	gets_s(a, sizeof(a));
	printf("단어: ");
	scanf("%s", b);
	token = strtok(a, b);
	while (token) {
		printf("%s \n", token);
		count++;
		token = strtok(NULL, b);
		
	}
	printf("\n%s의 개수: %d", b, count);
}

// strtok(a, "the")는 "the"를 기준으로 토큰을 구하는게 아니라 각각 "t", "h", "e"를 기준으로 토큰을 구함

11. 간단한 철자 교정 프로그램을 작성하여보자. 문자열을입력으로 받아서 문자열 안에 마침표가 있으면문자열의 첫 번째 문자가 대문자인지를 검사한다. 만약 대문가 ㅏ아니면 대문자로 변환한다. 또한 문장의 끝에 마침표가 존재하는지를 검사한다. 역시 마침표가 없으면 넣어준다. 즉, 입력된 문자열이 "pointer is easy"라면 "Pointer is easy."로 변환하여 화면에 출력한다.

#include <stdio.h>
#include <ctype.h>
#include <string.h>

int main() {
	char a[100];
	printf("문자열을 입력하시오: ");
	gets_s(a, sizeof(a));
	if (islower(a[0])) {
		a[0] = toupper(a[0]);
	}
	if (a[strlen(a) - 1] != '.') {
		strcat(a, ".");
	}
	printf("수정된 텍스트: %s", a);
}

12. 회문이란 바로 읽거나 거꾸로 읽어도 같은글이 되는 단어이다. 예를 들면 "madam"와 같은 문자열이 회문이다 사용자로부터 문자열을 받아서 회문여부를 판별하여 그 결과를화면에 출력하는 프로그램을 작성해여 보라 .

 

#include <stdio.h>
#include <string.h>
#include <ctype.h>

int is_palindrome(char* s) {
	for (int i = 0; i < strlen(s) / 2; i++) {
		if (tolower(s[i]) != tolower( s[strlen(s) - 1 - i]))
			return 0;
	}
	return 1;
}

int main() {
	char s[100];
	printf("문자열을 입력하시오: ");
	scanf("%s", s);

	if (is_palindrome(s))
		printf("회문입니다.");
	else
		printf("회문이 아닙니다.");
}
#include <stdio.h>
#include <string.h>
#include <ctype.h>

int is_palindrome(const char* str) {
    int left = 0;
    int right = strlen(str) - 1;

    while (left < right) {
        if (tolower(str[left]) != tolower(str[right])) 
            return 0; 
        left++;
        right--;
    }
    return 1;
}

int main() {
    char input[100];
    printf("문자열을 입력하세요: ");
    scanf("%s", input);

    if (is_palindrome(input))
        printf("회문입니다.");
    else 
        printf("회문이 아닙니다.");
}

13. 사용자로부터 한줄의 문자열을 입력받아서 문자열에 포함된단어들을 역순으로 배열하여 출력하는 프로그램을 작성하시오.

#include <stdio.h>
#include <string.h>


int main() {
	int a[100];
	char* token[100];
	int i = 0;

	printf("문자열을 입력하시오: ");
	gets_s(a, sizeof(a));
	
	token[0] = strtok(a, " ");
	while (token[i] != NULL) {
		i++;
		token[i] = strtok(NULL, " ");
	}

	for (int j = i-1; j >= 0; j--) {
		printf("%s ", token[j]);
	}
}

14. 사용자에게 영어 이름을 성과 이름으로 나누어서 대문자로 입력하도록 하여서 성과 이름의 위치를 바꾸고 소문자로변환하여 추력하는 프로그램을 작성하라.

#include <stdio.h>
#include <string.h>
#include <ctype.h>

int main() {
	char name[100];
	char* name_[2];

	printf("성과 이름을 대문자로 입력하시오: ");
	gets_s(name, sizeof(name));

	for (int i = 0; i <= strlen(name) - 1; i++) {
			name[i] = tolower(name[i]);
	}

	name_[0] = strtok(name, " ");
	name_[1] = strtok(NULL, " ");
	
	printf("%s, %s", name_[1], name_[0]);
}


 // for문 내에 대신해서 가능
 // if (name >= 'A' && name <= 'Z') {
	//name[i] = name[i] - 32;
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <ctype.h>


int main() {
	char name[100];
	char* name_[2];

	gets_s(name, sizeof(name));

	for (int i = 0; i < strlen(name); i++) {
		name[i] = tolower(name[i]);
	}

	name_[0] = strtok(name, " ");
	name_[1] = strtok(NULL, " ");
	strcat(name_[1], ", ");
	strcat(name_[1], name_[0]);


	printf("%s \n", name_[1]);
}

15. 사용자로부터 문자열을 받아서 문자열에 포함된 구두점의 개수를 세는 프로그램을 작성하라. 여기서구두점에는 마침표와 쉼표만이 포함된다고 가정하자.

#include <stdio.h>
#include <string.h>

int main() {
	char a[100];
	char b[] = ",.";
	char* token;
	int count = 0;

	printf("문자열을 입력하시오: ");
	gets_s(a, sizeof(a));

	token = strtok(a, b);
	while (token != NULL) {
		count++;
		token = strtok(NULL, b);
	}
	printf("구두점의 개수는 %d입니다. ", count);
}

16. 간단한 "찾아 바꾸기" 기능을 구현하여보자. 첫 번째로 사용자에게 최대 80 문자의 문자열을입력하도록 한다. 두 번째로 찾을 문자열을 입력받는다. 세 번째로바꿀 문자열을 입력받는다. 문자열을 찾아서 바꾼 후에 결과 문자열을 화면에 출력한다.

#include <stdio.h>
#include <string.h>
#include <conio.h>

int main() {
	char seps[] = " ";
	char s[200], find[100], replace[100], target[200] = "";
	char* token;

	printf("문자열을 입력하시오: ");
	gets_s(s,sizeof(s));
	printf("찾을 문자열: ");
	gets_s(find,sizeof(find));
	printf("바꿀 문자열: ");
	gets_s(replace, sizeof(replace));

	token = strtok(s, seps); 

	while (token != NULL) {
		if (strcmp(token, find) == 0)
			strcat(target, replace);

		else
			strcat(target, token);

		token = strtok(NULL, seps);
		strcat(target, " ");
	}
	printf("수정된 문자열: %s\n", target);
	return 0;
}
#include <stdio.h>
#include <string.h>

int main() {
	char s[200], find[100], replace[100], target[200] = "";
	char* p;

	printf("문자열을 입력하시오: ");
	gets_s(s, sizeof(s));
	printf("찾을 문자열: ");
	gets_s(find, sizeof(find));
	printf("바꿀 문자열: ");
	gets_s(replace, sizeof(replace));

	
	p = strstr(s, find);
	while (p != NULL) {
		strncpy(p, replace, strlen(replace));
		p = strstr(p, find);
	}
	printf("수정된 문자열: %s", s);
}

17. 사용자로부터 받은 문자열을 버블 정렬 방법을 이용하여 정렬한 후에 출력하는 프로그램을작성하라.

#include <stdio.h>
#include <string.h>

void bubble(char a[][100], int len) {
	char temp[100];
	for (int i = 0; i < len-1; i++) {
		for (int j = 0; j < len-1; j++) {
			if (strcmp(a[j], a[j + 1]) > 0) {
				strcpy(temp, a[j]);
				strcpy(a[j], a[j + 1]);
				strcpy(a[j + 1], temp);
			}
		}
	}
}
int main() {
	char a[10][100];
	int len;
	int row = sizeof(a) / sizeof(a[0]);
	int col = sizeof(a[0]) / sizeof(a[0][00]);
	
	printf("문자열의 개수: ");
	scanf("%d", &len);

	for (int i = 0; i < len; i++) {
		printf("문자열을 입력하시오: ");
		scanf("%s", a[i]);
	}

	bubble(a, len);
	printf("정렬된 문자열은 다음과 같습니다. \n");
	for (int i = 0; i < len; i++) {
		printf("%s ", a[i]);
	}

}

18. 다음과 같이 연산의 이름을 문자열로 받아서 해당 연산을 실행하는 프로그램을 작성하라 연산을 나타내는 문자열은 "add", "sub", "mul", "div"으로 하라.

#include <stdio.h>
#include <string.h>

int add(int num1, int num2);
int sub(int num1, int num2);
int mul(int num1, int num2);
int div(int num1, int num2);

int main() {
	char* a[] = { "add","sub","mul","div" };
	char cal[4];
	int num1, num2, result;
	int (*calculate[4])(int, int) = { add,sub,mul,div };
	printf("연산을 입력하시오: ");
	scanf("%s %d %d", cal, &num1, &num2);

	for (int i = 0; i < sizeof(a) / sizeof(a[0]); i++) {
		if (strcmp(cal, a[i]) == 0)
			result = calculate[i](num1, num2);
	}
	
	printf("연산의 결과: %d", result);
}

int add(int num1, int num2) {
	return num1 + num2;
}
int sub(int num1, int num2) {
	return num1 - num2;
}
int mul(int num1, int num2) {
	return num1 * num2;
}
int div(int num1, int num2) {
	return num1 / num2;
}

19. 요즘 길거리에서는 글자들이 흘러가는 LED 전광판을 볼수 있다. 이것을 프로그램으로 구현하여보자 .   

#include <stdio.h>
#include <string.h>

int main() {
	char text[100];
	int len;
	printf("텍스트를 입력하시오: ");
	gets_s(text, sizeof(text));
	printf("\n");

	len = strlen(text);
	for (int i = 0; i < len; i++) {
		for (int j = i; j < len + i; j++) {
			if (j < len)
				putchar(text[j]);
			else
				putchar(text[j - len]);
		}
		puts("");
	}
}

20. 암호화 방법 중에 XOR 암호화가 있다. 이 방법은평문의 각 문자에 키값을 XOR하여서 암호문을 얻는 방법이다. 암호화할때 사용한 XOR 키를 알면 암호화된 값에 다시 XOR해서 평문을 없을 수 있다. 평문과 키값을 사용자로붕터 받아서 XOR 암호화하여 출력하는 프로그램을 작성해보자.

#include <stdio.h>
#include <string.h>

void secret(char* text, char* key) {
	int key_len = strlen(key);

	for (int i = 0; text[i] != '\0'; i++) {
		if (key[0] == text[i])  // key값과 text가 같으면 NULL이 되어버림 
			continue;
		text[i] = text[i] ^ key[i % key_len];
	}
}

int main() {
	char text[100];
	char key[100];
	printf("텍스트를 입력하시오: ");
	gets_s(text, sizeof(text));
	printf("키를 입력하시오: ");
	gets_s(key, sizeof(key));
	puts("");

	secret(text, key);
	printf("암호화된 문자열: %s \n", text);
	secret(text, key);
	printf("복원된 문자열: %s", text);
}

 


21. 단어 애나그램 게임을 작성해보자. 영어 단어를 이루는 글자들이 뒤죽박죽 섞인 것을 받아서 순서대로 재배치하는 게임을 애나그램 게임이라고 한다.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>

#define SOL "apple"

int main() {
	srand((unsigned)time(NULL));
	char ques[100] = SOL;
	char user[100];
	char temp;
	int pos1, pos2, len;

	len = strlen(ques);
	for (int i = 0; i < len; i++) {
		pos1 = rand() % len;
		pos2 = rand() % len;
		temp = ques[pos1];
		ques[pos1] = ques[pos2];
		ques[pos2] = temp;
	}
	do {
		printf("%s의 원래 단어를 맞춰보세요: ", ques);
		scanf("%s", user);


	} while (strcmp(user,SOL)!=0);
	printf("축하합니다.");

}

22. 런길이 인코딩을 이용한 간단한 텍스트 압축 프로그램을 작성해본다 텍스트는 사용자로부터 직접 입력된다. 알파벳 영문자로 한정한다. 권장하는 방법은 런길이 인코딩이다. 런길이 인코딩은 무손실 압축 방법 중 하나로서, 텍스트를 압축할 때 반복되는 문자가 있으면, 이것을 반복되는 개수와 반복되는 무자로 바꾸는 방법이다. 예를 들어서"wwwssssssssschh"는 "3w9s1c2h" 로 압축하는 것이다. 전체 데이터 양이 줄얻느것을 알 수 있다. 

 

#include <stdio.h>

void print(char *s) {
	int len = strlen(s);
	int count;

	for (int i = 0; i < len; i++) {
		count = 1;
		while (i < len - 1 && s[i] == s[i + 1]) { 
			count++;
			i++;
		}
		printf("%d%c", count, s[i]);
	}

}

int main() {
	char s[100];
	printf("문자열을 입력하시오: ");
	scanf("%s", s);
	
	print(s);


}

01. 실수를 받아서 정수부와 소수부로 분리하는 함수  get_frac(double f, int *pi, double *pd) ;을 작성하고 테스트해보자.

 

#include <stdio.h>

void get_frac(double f, int* pi, double* pd) {
	*pi = (int)f;
	*pd = f - *pi; 
	// *pf = f % 1 불가능 (실수형은 % 연산자 사용 불가)
}

int main() {
	int a;
	double n, b;
	printf("실수를 입력하시오: ");
	scanf("%lf", &n);

	get_frac(n, &a, &b);
	printf("get_frac(%.2lf)이 호출되었습니다.\n", n);
	printf("정수부는 %d입니다. \n", a);
	printf("소수부는 %.2lf입니다. \n", b);

}

02. 크기가 3인  int형 배열을 생성하고 사용자로부터 정수를 받아서 배열을 채운다. 배열 요소의 주소와 값을 다음과 같이 출력하는 프로그램을 작성해보자.

 

#include <stdio.h>

int main() {
	int a[3];
	int size = sizeof(a) / sizeof(a[0]);

	for (int i = 0; i < size; i++) {
		printf("정수를 입력하시오: ");
		scanf("%d", &a[i]);
	}

	printf("====================== \n");
	printf(" 주소      값 \n");
	printf("====================== \n");

	for (int i = 0; i < size; i++) {
		printf("%u %d \n", a + i, a[i]);
	}
}

03. 정수 배열을 받아서 요소들을 난수로 채우는 함수 array_fill()를 작성하고 테스트하라. 난수는 라이브러리 함수인  rand()를 사용하여 생성한다.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

void array_fill(int A[], int size) {
	for (int i = 0; i < size; i++) {
		A[i] = rand();
	}
}

int main() {
	srand((unsigned)time(NULL));
	int arr[10];
	int size = sizeof(arr) / sizeof(arr[0]);
	array_fill(arr, size);
	for (int i = 0; i < size; i++) {
		printf("%d ", arr[i]);
	}
}

04. 문자형 배열을 생각해보자. 배열의 요소에는 문자 H, E, L, L, O R가 저장되어 있고 맨 끝에는 0을 저장시킨다. 저장된 문자들의 개수를 세어서 반환하는 함수 my_strlen(char *p)를 작성하고 테스트해보자. 이것은 실제로  C언어가 문자열을 저장하는 방법이다.

#include <stdio.h>

int strlen(char *p){
	int i = 0;
	while (*p != '\0') {
		i++;
		p++;
	}
	return i;
}

int main() {
	char a[] = "HELLO";
	printf("저장된 문자열 = %s \n", a);
	printf("문자열의 길이 = %d", strlen(a));
}

05. 큰 배열을 할당받아서 우리 마음대로 메모리를 사용하고자 한다. 크기가 1000인 char형 배열을 생성한다. 배열의 첫 번재 바이트에는 'a'를 저장하고, 다음 4바이트에는 정수 100을 저장하고, 다음 4바이트에는 float형 실수 3.14를 저장할 수 있는가? 다시 꺼내서 출력해보자.

 

#define _CRT_SECURE_NO_WARNINGS	
#include <stdio.h>

int main() {
	char buffer[1000];
	char* p;
	int* pi;
	float* pf;

	p = buffer;
	*p = 'a';

	pi = (int*)(p + 4);
	*pi = 100;

	pf = (float*)(pi + 1);
	*pf = 3.14;

	printf("%c ", *p);
	printf("%d" , *pi);
	printf("%f ", *pf);
}

06. 정수 배열의 요소들을 화면에 출력하는 함수 array_print()를 작성하고 테스트하라. 출력 형식은 다음과 같은 형식이 되도록 하라.

 

#include <stdio.h>

void array_print(int* A, int size) {
	printf("A[] = { ");
	for (int i = 0; i < size; i++) {
		printf("%d, ", A[i]);
	}
	printf("}");
}

int main() {
	int A[10] = { 1,2,3,4,5 };
	int size = sizeof(A) / sizeof(A[0]);
	array_print(A, size);
}

07. 배열에 저장된 값을 역순으로 출력하는 프로그램을 작성하라. 단 인덱스를 사용하지 않고 포인터만을 사용해보자.

#include <stdio.h>

void array_print(int* A, int size) {
	printf("A[] = ");
	for (int i = 0; i < size; i++) {
		printf("%d ", *(A + i));
	}
	printf("\n");
}

void array_print_reverse(int* A, int size) {
	printf("A[] = ");
	for (int i = size - 1; i >= 0; i--) {
		printf("%d ", *(A+i));
	}
	printf("\n");
}

int main() {
	int A[10];
	int size = sizeof(A) / sizeof(A[0]);
	for (int i = 0; i < size; i++) {
		A[i] = i;
	}
	array_print(A, size);
	array_print_reverse(A, size);
}

08. 배열에 double형의 실수값들이 저장되어 있다. 이 실수값 중에서 최대값이 저장된 요소를 찾아서 요소와 주소를 반환하는 다음과 같은 함수를 구현하고 테스트해보자.

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>


double* find_max(double* arr, int size) {
	double* max = arr;
	for (int i = 1; i < size; i++) {
		if (*max < arr[i])
			max = arr + i;
	}
	return max;
}

int main() {
	double A[] = { 1.23, 3.14, 9.16, 100.9 };
	printf("%.2lf", *find_max(A, sizeof(A) / sizeof(A[0])));
}

09. 학생들의 평점은 4.3점이 만점이라고 하자. 배열 grades[ ]에 학생 10명의 학점이 저장되어 있다. 이것을 100점 만점으로 변환하여서 배열 scores[ ]에 저장하는 함수를 작성하고 테스트하라.

#include <stdio.h>

void print_array(double* arr, int size) {
	for (int i = 0; i < size; i++) {
		printf("%.2lf ", arr[i]);
	}
	printf("\n");
}

void convert(double* grades, double* scores, int size) {
	for (int i = 0; i < size; i++) {
		scores[i] = grades[i] / 4.3 * 100;
	}
}

int main() {
	double grades[] = { 0,0.5,1.0,1.5,2.0,2.5,3.0,3.5,4.0,4.3 };
	double scores[10];
	
	print_array(grades, 10);
	convert(grades, scores, 10);
	print_array(scores, 10);
}

10. 정수 배열 A[]를 다른 정수 배열 B[]에 복사하는 함수를 작성하고 테스트하라.

#include <stdio.h>

void array_copy(int* A, int* B, int size) {
	for (int i = 0; i < size; i++) {
		B[i] = A[i];
	}
}

void print_array(int* arr, int size) {
	for (int i = 0; i < size; i++) {
		printf("%d ", *(arr + i));
	}
	printf("\n");
}

int main() {
	int A[10] = { 1,2,3 };
	int B[10];
	array_copy(A, B, 10);
	printf("A[] = ");
	print_array(A, 10);
	printf("B[] = ");
	print_array(B, 10);
}

11. 직원들의 기본급이 배열 A[ ]에 저장되어 있다. 배열 B[ ]에는 직원들의 보너스가 저장되어 있다. 기본급과 보너스를 합하여 이번 달에 지급할 월급의 총액을 계산하고자 한다. A[ ] 와 B[ ]를 더하여 배열 C[ ]에 저장하는 함수를 작성하고 테스트하라. 즉 모든 i에 대하여 C[ i ] = A[ i ] + B[ i ]가 된다.

#include <stdio.h>

void print_array(int* a, int size) {
	for (int i = 0; i < size; i++) {
		printf("%d ", a[i]);
	}
	printf("\n");
}

void array_add(int* A, int* B, int* C, int size) {
	for (int i = 0; i < size; i++) {
		C[i] = A[i] + B[i];
	}
}

int main() {
	int A[10] = { 1,2,3 };
	int B[10] = { 4,5,6 };
	int C[10];

	array_add(A, B, C, 10);
	printf("A[] = ");
	print_array(A, 10);
	printf("B[] = ");
	print_array(B, 10);
	printf("C[] = ");
	print_array(C, 10);
}

12. 직원들의 월급이 배열 A[ ] 에 저장되어 있다고 가정하자. 이번 달에 회사에서 지급할 월급의 총액을 계산하고자 한다/ 정수형 배열 요소들의 합을 구하여 반환하는 함수를 작성하고 테스트하라.

#include <stdio.h>

void print_array(int* a, int size) {
	for (int i = 0; i < size; i++) {
		printf("%d ", a[i]);
	}
	printf("\n");
}

int array_sum(int* A, int size) {
	int sum = 0;
	for (int i = 0; i < size; i++) {
		sum += A[i];
	}
	return sum;
}

int main() {
	int A[10] = { 1,2,3 };
	printf("A[] = ");
	print_array(A, 10);
	printf("월급의 합: %d", array_sum(A, 10));
}

13. 직원들의 월급이 저장된 배열에서 월급이 200만원인 사람을 찾고 싶을 때가 있다. 주어진 값을 배열 A[]에서 탐색하여 배열 요소의 인덱스를 반환하는 함수를 작성하고 테스트하라.

#include <stdio.h>

int search(int* A, int size,int search_value) {
	for (int i = 0; i < size; i++) {
		if (A[i] == search_value) {
			return i;
		}
	}
	
}

int main() {
	int A[10] = {0, 100,300,200,400,500,600,700,800,900};
	printf("월급 200만원인 사람의 인데스=%d", search(A, 10, 200));
}

14. 2개의 정수의 합과 차를 동시에 반환하는 함수를 작성하고 테스트하라. 포인터 매개 변수를 사용한다.

#include <stdio.h>

void get_sum_diff(int x, int y, int* p_sum, int* p_diff) {
	*p_sum = x + y;
	*p_diff = x - y;
}

int main() {
	int x = 100, y = 200;
	int p_sum, p_diff;
	get_sum_diff(x, y, &p_sum, &p_diff);
	printf("원소들의 합 = %d \n", p_sum);
	printf("원소들의 차 = %d \n", p_diff);
}

15. 우리가 프로그램을 하다 보면 사용자로부터 2개의 정수를 받아오는 경우가 많다. 이것을 함수로 구현해두고 필요할 때마다 사용하면 편리할 것이다. 하지만 한 가지 문제가 있다. C에서 함수는 하나의 값만 반환할 수 있다. 2개 이상의 값을 반환하려면 다른 방법을 사용해야 하는데 다음과 같이 포인터도 사용할 수 있다.

void get_two_int(int *px, int *py);

위와 같은 원형을 가지는 함수를 작성하고 이것을 이요해서 정수의 합을 계산하는 프로그램을 작성해보자.

#include <stdio.h>

void get_two_int(int* px, int* py) {
	printf("정수 2개를 입력하시오: ");
	scanf("%d %d", px, py);
}

int sum(x, y) {
	return x + y;
}


int main() {
	int x, y;
	get_two_int(&x, &y);
	printf("정수의 합은 %d", sum(x, y));
}

16. 2개의 정렬된 정수 배열 A[ ]와 B[ ]가 있다고 가정하자. 이 2개의 배열을 합쳐서 하나의 정렬된 배열 C[]로 만드는 함수를 작성하고 테스트한다. 다음과 같은 함수 원형을 가진다고 가정하라.

void merge(int *A,int *B, int *C, int size){ }

여기서 배열 A[ ], B[ ]는 똑같은 크기로 정의되어 있다고 가정한다. 배열 C[ ]에는 충분한 공간이 확보되어 있다고 가정하자. 합치는 알고리즘은 다음과 같다. 먼저 A[0]와 B[0]를 비교한다. 만약 A[0]가 B[0]보다 작으면 A[0]를 C[0]에 복사한다.  다음에는 A[1]과 B[0]를 비교한다. 이번에는 B[0]가 A[1]보다 작다면 B[0]를 C[1]에 저장한다. 똑같은 방식으로 남아있는 요소들을 비교하여 더 작은 요소를 C[ ]로 복사한다. 만약 A[ ]나 B[ ] 중에서 어느 하나가 먼저 끝나게 되면 남아있는 요소들을 전부 C[ ]로 이동한다.

#include <stdio.h>

void array(int* A, int* B, int* C, int size) {

	int j = 0;
	int k = 0;

	for (int i = 0; i < size; i++) {
		if (j < size / 2 && k < size / 2) {
			if (A[j] < B[k]) C[i] = A[j++];

			else C[i] = B[k++];
		}
		else if (j == size / 2)
			C[i] = B[k++];

		else if (k == size / 2)
			C[i] = A[j++];
	}
}

void print_arr(int *arr, int size) {
	for (int i = 0; i < size; i++) {
		printf("%d ", arr[i]);
	}
	printf("\n");
}

int main() {
	int A[4] = { 2,5,7,8 };
	int B[4] = { 1,3,4,6 };
	int C[10];
	array(A, B, C, 8);

	printf("A[] = ");
	print_arr(A, 4);
	printf("B[] = ");
	print_arr(B, 4);
	printf("C[] = ");
	print_arr(C, 8);
}

+ Recent posts