1. 배열에서 최소값과 최대값 찾기
find_min_max 함수는 입력된 숫자들 중에서 최소값과 최대값을 탐색하는 역할을 수행합니다. pmin은 최소값이 저장된 메모리 주소를 가리키고, pmax는 최대값이 저장된 메모리 주소를 가리킵니다.
2. 최대값 탐색 및 주소 반환
아래 코드는 배열에서 최대값을 찾아 해당 원소의 주소를 반환하는 예제입니다.
#include <stdio.h>
#define SIZE 5
void read_values(int arr[], int len);
void display_values(int arr[], int len);
int *locate_peak(int arr[], int len);
int main() {
int data[SIZE];
int *peak_ptr;
printf("Enter %d integers:\n", SIZE);
read_values(data, SIZE);
printf("Values entered:\n");
display_values(data, SIZE);
printf("Processing...\n");
peak_ptr = locate_peak(data, SIZE);
printf("Result:\n");
printf("Maximum value = %d\n", *peak_ptr);
return 0;
}
void read_values(int arr[], int len) {
for (int idx = 0; idx < len; idx++) {
scanf("%d", &arr[idx]);
}
}
void display_values(int arr[], int len) {
for (int idx = 0; idx < len; idx++) {
printf("%d ", arr[idx]);
}
printf("\n");
}
int *locate_peak(int arr[], int len) {
int peak_pos = 0;
for (int idx = 1; idx < len; idx++) {
if (arr[idx] > arr[peak_pos]) {
peak_pos = idx;
}
}
return &arr[peak_pos];
}
locate_peak 함수는 배열 내 최대값의 위치를 찾아 해당 원소의 주소를 반환합니다. 반환된 포인터를 통해 간접적으로 최대값에 접근할 수 있습니다.
3. 문자열 배열과 포인터의 차이
문자열을 배열로 선언할 때와 포인터로 선언할 때의 차이를 이해하는 것이 중요합니다.
3.1 문자열 배열 방식
#include <stdio.h>
#include <string.h>
#define MAX_LEN 80
int main() {
char buffer1[MAX_LEN] = "Learning makes me happy";
char buffer2[MAX_LEN] = "Learning makes me sleepy";
char temp[MAX_LEN];
printf("sizeof vs strlen comparison:\n");
printf("sizeof(buffer1) = %zu bytes\n", sizeof(buffer1));
printf("strlen(buffer1) = %zu characters\n", strlen(buffer1));
printf("\nBefore exchange:\n");
printf("buffer1: %s\n", buffer1);
printf("buffer2: %s\n", buffer2);
strcpy(temp, buffer1);
strcpy(buffer1, buffer2);
strcpy(buffer2, temp);
printf("\nAfter exchange:\n");
printf("buffer1: %s\n", buffer1);
printf("buffer2: %s\n", buffer2);
return 0;
}
sizeof(buffer1)은 배열 전체 크기(80바이트)를 반환하고, strlen(buffer1)은 실제 문자열 길이(23자)를 반환합니다. 문자열 상수를 배열 이름에 직접 대입할 수 없으며, strcpy를 통해 내용을 복사해야 합니다.
3.2 문자열 포인터 방식
#include <stdio.h>
#include <string.h>
int main() {
char *ptr1 = "Learning makes me happy";
char *ptr2 = "Learning makes me sleepy";
char *swap;
printf("sizeof vs strlen comparison:\n");
printf("sizeof(ptr1) = %zu bytes (pointer size)\n", sizeof(ptr1));
printf("strlen(ptr1) = %zu characters\n", strlen(ptr1));
printf("\nBefore exchange:\n");
printf("ptr1: %s\n", ptr1);
printf("ptr2: %s\n", ptr2);
swap = ptr1;
ptr1 = ptr2;
ptr2 = swap;
printf("\nAfter exchange:\n");
printf("ptr1: %s\n", ptr1);
printf("ptr2: %s\n", ptr2);
return 0;
}
포인터 방식에서는 문자열 리터럴의 주소를 직접 저장할 수 있습니다. 포인터 값 자체를 교환하므로 실제 메모리의 문자열 데이터는 변경되지 않고, 단지 참조 위치만 바뀝니다.
4. 2차원 배열의 다양한 접근 방식
2차원 배열을 배열 인덱스, 단일 포인터, 배열 포인터 세 가지 방식으로 접근할 수 있습니다.
#include <stdio.h>
int main() {
int matrix[2][4] = {{1, 9, 8, 4}, {2, 0, 4, 9}};
int row, col;
int *elem_ptr;
int (*row_ptr)[4];
printf("Method 1: Direct index access\n");
for (row = 0; row < 2; row++) {
for (col = 0; col < 4; col++) {
printf("%d ", matrix[row][col]);
}
printf("\n");
}
printf("\nMethod 2: Element pointer traversal\n");
int count = 0;
for (elem_ptr = &matrix[0][0]; elem_ptr < &matrix[0][0] + 8; elem_ptr++) {
printf("%d ", *elem_ptr);
if (++count % 4 == 0) printf("\n");
}
printf("\nMethod 3: Row pointer traversal\n");
for (row_ptr = matrix; row_ptr < matrix + 2; row_ptr++) {
for (col = 0; col < 4; col++) {
printf("%d ", (*row_ptr)[col]);
}
printf("\n");
}
return 0;
}
int (*row_ptr)[4]는 4개의 정수로 구성된 배열을 가리키는 포인터로, 2차원 배열의 각 행을 순회하는 데 사용됩니다.
5. 문자열 내 문자 치환
문자열에서 특정 문자를 다른 문자로 대체하는 함수를 구현합니다.
#include <stdio.h>
#define MAX_TEXT 80
void substitute(char *source, char target, char replacement);
int main() {
char sentence[MAX_TEXT] = "Programming is difficult or not, it is a question.";
printf("Original text:\n%s\n\n", sentence);
substitute(sentence, 'i', '*');
printf("Modified text:\n%s\n", sentence);
return 0;
}
void substitute(char *source, char target, char replacement) {
while (*source) {
if (*source == target) {
*source = replacement;
}
source++;
}
}
포인터를 이용해 문자열을 순회하며 대상 문자를 찾아 새로운 문자로 치환합니다. 문자열은 배열 형태로 전달되므로 원본이 직접 수정됩니다.
6. 문자열 특정 위치에서 잘라내기
지정된 문자가 처음 나타나는 위치에서 문자열을 종료시키는 함수입니다.
#include <stdio.h>
#define BUFFER_SIZE 80
char *truncate_at(char *text, char delimiter);
int main() {
char input[BUFFER_SIZE];
char mark;
while (printf("Enter string: "), gets(input) != NULL) {
printf("Enter delimiter character: ");
mark = getchar();
printf("Truncating...\n");
truncate_at(input, mark);
printf("Result: %s\n\n", input);
getchar();
}
return 0;
}
char *truncate_at(char *text, char delimiter) {
while (*text != '\0' && *text != delimiter) {
text++;
}
if (*text == delimiter) {
*text = '\0';
}
return text;
}
추가 getchar() 호출은 이전 입력의 개행문자를 소비하여 다음 입력 루프가 정상적으로 동작하도록 합니다.
7. 주민등록번호 유효성 검사
18자리 주민등록번호 형식을 검증하는 프로그램입니다.
#include <stdio.h>
#include <string.h>
#define ENTRIES 5
int validate_number(char *number);
int main() {
char *candidates[ENTRIES] = {
"31010120000721656X",
"3301061996x0203301",
"53010220051126571",
"510104199211197977",
"53010220051126133Y"
};
for (int i = 0; i < ENTRIES; i++) {
if (validate_number(candidates[i])) {
printf("%s\tValid\n", candidates[i]);
} else {
printf("%s\tInvalid\n", candidates[i]);
}
}
return 0;
}
int validate_number(char *number) {
if (strlen(number) != 18) {
return 0;
}
for (int pos = 0; pos < 18; pos++) {
if (pos == 17) {
char last = number[pos];
if (!((last >= '0' && last <= '9') || last == 'X')) {
return 0;
}
} else {
if (!(number[pos] >= '0' && number[pos] <= '9')) {
return 0;
}
}
}
return 1;
}
총 길이가 18자인지 확인하고, 마지막 자리는 숫자 또는 'X'만 허용하며 나머지는 모두 숫자여야 합니다.
8. 시저 암호 구현
알파벳을 지정된 값만큼 회전시키는 암호화와 복호화 함수입니다.
#include <stdio.h>
#include <string.h>
#define TEXT_LIMIT 80
void encrypt(char *text, int shift);
void decrypt(char *text, int shift);
int main() {
char message[TEXT_LIMIT];
int key;
printf("Enter English text: ");
gets(message);
printf("Enter shift value: ");
scanf("%d", &key);
printf("Encrypted text: ");
encrypt(message, key);
printf("%s\n", message);
printf("Decrypted text: ");
decrypt(message, key);
printf("%s\n", message);
return 0;
}
void encrypt(char *text, int shift) {
int len = strlen(text);
for (int i = 0; i < len; i++) {
if (text[i] >= 'a' && text[i] <= 'z') {
text[i] = ((text[i] - 'a' + shift) % 26) + 'a';
} else if (text[i] >= 'A' && text[i] <= 'Z') {
text[i] = ((text[i] - 'A' + shift) % 26) + 'A';
}
}
}
void decrypt(char *text, int shift) {
int len = strlen(text);
for (int i = 0; i < len; i++) {
if (text[i] >= 'a' && text[i] <= 'z') {
text[i] = ((text[i] - 'a' - shift + 26) % 26) + 'a';
} else if (text[i] >= 'A' && text[i] <= 'Z') {
text[i] = ((text[i] - 'A' - shift + 26) % 26) + 'A';
}
}
}
암호화는 정방향 회전, 복호화는 역방향 회전을 수행합니다. 음수 방지를 위해 26을 더한 후 모듈로 연산을 적용합니다.
9. 명령행 인자 정렬
버블 정렬을 이용해 명령행 인자를 사전순으로 정렬합니다.
#include <stdio.h>
#include <string.h>
void bubble_sort(int count, char *items[]);
int main(int argc, char *argv[]) {
bubble_sort(argc - 1, argv + 1);
for (int i = 1; i < argc; i++) {
printf("Hello, %s\n", argv[i]);
}
return 0;
}
void bubble_sort(int count, char *items[]) {
for (int i = 0; i < count - 1; i++) {
for (int j = 0; j < count - 1 - i; j++) {
if (strcmp(items[j], items[j + 1]) > 0) {
char *swap = items[j];
items[j] = items[j + 1];
items[j + 1] = swap;
}
}
}
}
포인터 배열의 요소만 교환하여 문자열 자체를 복사하지 않고 효율적으로 정렬합니다. argv + 1로 프로그램 이름을 제외한 인자들만 처리합니다.