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번 문제는 너무 어려워서 보류.. 실력을 쌓고 돌아오겠다.)

 

 

+ Recent posts