본문 바로가기
대외활동/시스템프로그래밍

1주차 C 기초부터 이중연결리스트까지

by hoshi03 2024. 7. 18.

배열 선언할때 크기+1로 널문자를 포함해주기 - 안하면 어디서 끝나는지를 모른다

 

• 헤더파일 분할

 

vs환경에서 헤더 파일 분할에 헤더파일을 생성한다

정수를 인자로 받아서 팩토리얼을 구해주는 함수를 fac.h에 생성한다

 

-fac.h

#include <stdio.h>

int factorial(int input) {
	if (input == 1) return 1;
	return input * factorial(input - 1);
}

 

main 함수에서 사용자가 만든 헤더를 #include "fac.h" 형태로 삽입해서 사용한다

#define _CRT_SECURE_NO_WARNINGS	
#include <stdio.h>
#include "fac.h"

int main(void) {
	int a;
	scanf("%d", &a);
	printf("%d", factorial(a));
	return 0;
}

 

• C 문자열 처리

 

- 공백 구분해서 입력받기

scanf에 정규식으로 엔터를 입력하기 전까지 입력받는 조건 - scanf("[^\n]s", %input); 형태로 받거나

fgets(입력받을 배열, 길이, stdin) 형태로 사용한다

정규식으로 하는 건 까먹을 수도 있으니 fgets 메서드 사용법도 알아두자

int main(void) {
	char str1[20];
	char str2[20];
	char str3[20];
	fgets(str1, 20, stdin);
	strcpy(str2, str1);
	printf("str1 내용 : %s", str1);
	printf("str2 내용 : %s", str2);
	scanf("%[^\n]s", &str3);
	printf("scanf로 공백 구분해서 입력받은 str3\n%s", str3);
}

 

• 포인터

 

#define _CRT_SECURE_NO_WARNINGS	
#include <stdio.h>
#include "swap.h"


void scoreEnter(int* score) {
	for (int i = 0; i < 10; i++)
	{
		scanf("%d", &score[i]);
	}
}

void scorePrint(int* score) {
	for (int i = 0; i < 10 ; i++)
	{
		printf("%d ", score[i]);
	}
	printf("\n");
}

void scoreSearch(int* score, int target) {
	for (int i = 0; i < 10; i++)
	{
		if (score[i] == target) {
			printf("찾은 숫자 인덱스 : %d\n", i);
			return;
		}
	}
	printf("그런건 없어요\n");
}

int main(void) {

	int current = 0;
	int max = 0;
	int score[10];

	while (1) {
		printf("1 : 입력\n");
		printf("2 : 출력\n");
		printf("3 : 검색\n");
		printf("4 : 종료\n");
		printf("선택 --> ");

		int num = 0;
		scanf("%d", &num);

		switch (num)
		{
		case 1: //입력
			scoreEnter(score);
			break;
		case 2: //출력
			scorePrint(score);
			break;
		case 3: //출력
		{
			int dd;
			scanf("%d", &dd);
			scanf("%d", &num);
			scoreSearch(score, num);
			break;
		}
		case 4: //종료
			printf("종료합니다\n");
			break;
		default:
			break;
		}
	}
}

 

• 다차원 배열

int main(void) {
	char names[2][10];
	for (int  i = 0; i < 2; i++)
	{
		fgets(names[i], 10, stdin); 
		names[i][strlen(names[i])-1] = '\0'; //개행 문자 제거하기
		for (int j = 0; j < strlen(names[i]); j++)
		{
			printf("%c ", names[i][j]);
		}
		printf("\n");
	}
}

 

• 포인터 배열

char* ptr[3];
	ptr[0] = "hello";
	ptr[1] = "hi";
	ptr[2] = "hola";

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

 

여기서 ptr[i] 앞에 *를 붙이면 

배열은 포인터의 시작 주소를 가지고 있으니

배열의 시작 주소에 있는 값 = ptr[i] 번째에 들어있는 문자를 가져오게 된다;

 

• 함수 포인터,

 

포인터를 선언하고 int( int, int) 형 함수를 사용하기 위해서 반환형과 매개변수를 넣어준다

#define _CRT_SECURE_NO_WARNINGS	
#include <stdio.h>

int sum(int a, int b) {
	return a + b;
}

int main(void) {

	int (*fp)(int, int);
	fp = sum;

	int res = 0;
	res = (*sum)(10, 10);
	printf("%d", res);

	return 0;
}

 

• 동적할당

 

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

int main() {
	int* pi;
	int a;
	scanf("%d", &a);
	pi = (int*)malloc(sizeof(int) * a);
	if (pi != NULL)
	{
		for (int i = 0; i < 5; i++) scanf("%d", &pi[i]);
		for (int i = 0; i < 5; i++) printf("%d", pi[i]);
	}

	free(pi);
}

 

 

• 구조체

 

member를 관리할 struct를 선언하고 헤더로 빼서 main에 넣어서 사용했다

#pragma once

struct member
{
	int age;
	char name[20];
};
#define _CRT_SECURE_NO_WARNINGS	
#include <stdio.h>
#include "myStruct.h"

int main(void) {

	struct member members[5];

	for (int i = 0; i < 5; i++)
	{
		printf("나이 : ");
		scanf("%d", &members[i].age); getchar();
		printf("이름 : ");
		fgets(members[i].name, 20, stdin);
		members[i].name[strlen(members[i].name) - 1] = '\0';
	}

	for (int i = 2; i < 4; i++) members[i] = members[i + 1];
	for (int i = 0; i < 4; i++) printf("%d, %s\n", members[i].age, members[i].name);

	return 0;
}

 

구조체를 이용해서 만든 성적 관리 프로그램

MAX명의 성적을 입력받고 이름으로 조회, 삭제가 가능하게 했다

삭제의 경우에는 이름이 맞는 인덱스부터 배열을 한칸씩 땡기고 조회시 삭제된 사람만큼 빼서 조회하는 식으로 처리했다

#define _CRT_SECURE_NO_WARNINGS	
#include <stdio.h>
#include "myStruct.h"
#define MAX 3

int max = MAX;

void scoreEnter(struct score stScore[MAX]) {
	for (int i = 0; i < MAX; i++) {
		while (getchar() != '\n') getchar(); // 입력받을때 버퍼에 남아있는 개행문자 쳐내기
		
		float tmp = 0;
		printf("이름 : ");
		fgets(stScore[i].name, 20, stdin);
		stScore[i].name[strlen(stScore[i].name) - 1] = '\0'; 

		printf("국 : ");
		scanf("%d", &stScore[i].kor);

		printf("영 : ");
		scanf("%d", &stScore[i].eng);

		printf("수 : ");
		scanf("%d", &stScore[i].math);

		tmp += stScore[i].kor;
		tmp += stScore[i].eng;
		tmp += stScore[i].math;
		stScore[i].avg = (float)(tmp / 3);
	}
}

void scorePrint(struct score stScore[MAX]) {
	printf("현재 인원수 : %d \n", max);
	for (int i = 0; i < max; i++) {
		printf("이름 : %s\n", stScore[i].name);
		printf("국 : %d\n", stScore[i].kor);
		printf("영 : %d\n", stScore[i].eng);
		printf("수 : %d\n", stScore[i].math);
		printf("평균 : %.1f\n", stScore[i].avg);
	}
	printf("\n");
}

void scoreSearch(struct score stScore[MAX], char* target) {
	for (int i = 0; i < max; i++) {
		if (strcmp(stScore[i].name, target) == 0) {
			printf("이름 : %s\n", stScore[i].name);
			printf("국 : %d\n", stScore[i].kor);
			printf("영 : %d\n", stScore[i].eng);
			printf("수 : %d\n", stScore[i].math);
			printf("평균 : %.1f\n", stScore[i].avg);
			return;
		}
	}
	printf("그런 학생은 없어요\n");
}

void deleteStudent(struct score stScore[MAX], char* target) {

	int tmp = -1;
	for (int i = 0; i < MAX; i++) {
		if (strcmp(stScore[i].name, target) == 0) {
			tmp = i;
			printf("%d번 학생 %s 데이터 삭제\n", i, stScore[i].name);
			break;
		}
	}


	if(tmp == -1) printf("그런 학생은 없어요\n");

	else {
		max--;
		for (int i = tmp; i < MAX; i++) stScore[i] = stScore[i + 1];
	}
}

int main() {
	struct score stScore[MAX];

	while (1) {
		printf("1 : 입력\n");
		printf("2 : 출력\n");
		printf("3 : 검색\n");
		printf("4 : 삭제\n");
		printf("5 : 종료\n");
		printf("선택 --> ");

		int num = 0;
		scanf("%d", &num);

		switch (num) {
		case 1: // 입력
			scoreEnter(stScore);
			break;
		case 2: // 출력
			scorePrint(stScore);
			break;
		case 3: // 검색
		{
			getchar();
			char name[20];
			printf("검색할 학생 이름을 입력하세요: ");
			fgets(name, 20, stdin);
			name[strlen(name) - 1] = '\0'; 
			scoreSearch(stScore, name);
			break;
		}

		case 4:
			getchar();
			char name[20];
			printf("삭제할 학생 이름을 입력하세요: ");
			fgets(name, 20, stdin);
			name[strlen(name) - 1] = '\0';
			deleteStudent(stScore, name);
			break;

		case 5: // 종료
			printf("종료합니다");
			return 0;
		default:
			break;
		}
	}
}

 

• 구조체 포인터

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

int main() {
	struct simple {
		int id;
		double dnum;
		struct simple* next;
	};

	struct simple s1 = { 100, 123.45 , NULL}, s2 = { 200, 854.125, NULL }, * ptr;
	printf("s1 값 %d, %lf\n", s1.id, s1.dnum);
	ptr = &s1;
	ptr->next = &s2;
	printf("ptr을 이용한 s1 포인터 접근 %d, %lf\n", ptr->id, ptr->dnum);
	printf("ptr.next를 타고 s2 접근 %d, %lf\n", ptr->next->id, ptr->next->dnum);
}

 

• 링크드 리스트

 

구조체를 만들어서 다음 책의 정보를 넣고 출력하는 형태로 링크드 리스트를 만들어보자

 

리스트의 맨 앞인 head, 맨 뒤인 tail 포인터와 현재 가리키는 책인 temp 구조체 포인터 변수를 선언하고

head와 tail이 널 이면 빈 리스트에 삽입한 원소니 head로 넣어주고 head = tail = temp로 초기화

그렇지 않으면 tail.next로 삽입해준다

 

순회하는 것은 head부터 null 포인터가 나올때 까지 순회해서 tail까지 출력되게 설정했다

#pragma once

struct link {
	int id;
	char bookname[30];
	struct link* next;
};

 

#define _CRT_SECURE_NO_WARNINGS	
#include <stdio.h>
#include <stdlib.h>
#include "myList.h"

int main() {
	int max = 5;
	int cur = 0;
	struct link* HEAD, * TAIL, * temp;
	HEAD = TAIL = NULL;



	while (cur++ < max) {
		temp = (struct link*)malloc(sizeof(struct link));
		if (temp == NULL) {
			printf("메모리 할당 실패\n");
			exit(1);
		}

		printf("id : ");
		scanf("%d", &temp->id); // 멤버가 int형이니 scanf때 &로 참조하기
		getchar();

		printf("이름 : ");
		fgets(temp->bookname, 20, stdin);
		temp->bookname[strlen(temp->bookname) - 1] = '\0';

		temp->next = NULL;

		if (HEAD == NULL)
		{
			HEAD = temp;
			TAIL = temp;
		}

		else
		{
			TAIL->next = temp;
			TAIL = temp;
		}
	}

	temp = HEAD;
	while (temp != NULL)
	{
		printf("id : %d, 이름 : %s\n", temp->id, temp->bookname);
		temp = temp->next;
	}
}

 

• 이중 연결 리스트

처음에 이중 포인터로 head와 tail을 넘겨주지 않아 enter나 insertNode 메서드에서 변수로 만든 구조체의 값을

전달하지 못했다가 이중 포인터로 바꿔서 값 전달

파일 입출력을 적용해서 list.txt에 데이터를 읽고 쓸 수 있게 했다

#define _CRT_SECURE_NO_WARNINGS    
#include <stdio.h>
#include <stdlib.h>
#include <string.h> // strlen 함수 사용을 위해 추가
#include "myList.h"



void printList(struct link* HEAD) {
    struct link* temp = HEAD;
    while (temp != NULL) {
        printf("id : %d, 이름 : %s\n", temp->id, temp->bookname);
        temp = temp->next;
    }
}

void search(char* name, struct link* HEAD) {
    struct link* temp = HEAD;
    while (temp != NULL) {
        if (strcmp(temp->bookname, name) == 0) {
            printf("찾은 책 id : %d\n", temp->id);
            return;
        }
        temp = temp->next;
    }
    printf("해당 책 없음\n");
}

void deleteNode(char* name, struct link** HEAD, struct link** TAIL) {
    struct link* temp = *HEAD;
    struct link* prev = NULL;

    while (temp != NULL) {
        if (strcmp(temp->bookname, name) == 0) {
            printf("id %d인 노드 삭제\n", temp->id);
            if (temp == *HEAD) {
                *HEAD = temp->next;
                if (temp == *TAIL) *TAIL = NULL;
            }
            else if (temp == *TAIL) {
                *TAIL = prev;
                if (prev != NULL) {
                    prev->next = NULL;
                }
            }
            else {
                temp->prev->next = temp->next;
                temp->next->prev = temp->prev;
            }
            free(temp);
            return;
        }
        prev = temp;
        temp = temp->next;
    }
    printf("해당 책 없음\n");
}

void insertNode(int id, struct link** HEAD, struct link** TAIL) {
    struct link* temp = *HEAD;
    struct link* prev = NULL;

    while (temp != NULL) {
        if (temp->id == id) {
            struct link* new = (struct link*)malloc(sizeof(struct link));
            new->prev = NULL;
            new->next = NULL;
            if (new == NULL) {
                printf("메모리 할당 실패\n");
                return;
            }
            printf("id : ");
            scanf("%d", &new->id);
            getchar();
            printf("이름 : ");
            fgets(new->bookname, 20, stdin);
            new->bookname[strlen(new->bookname) - 1] = '\0';
            if (temp == *HEAD) { //머리일때
                (*HEAD)->prev = new;
                new->next = (*HEAD);
                *HEAD = new;
                return;
            }

            else if (temp == *TAIL) { //꼬리일때
                (*TAIL)->next = new;
                new->prev = (*TAIL);
                *TAIL = new;
                return;
            }
            if (prev != NULL) { // 중간일때
                new->next = prev->next;
                prev->next = new;
                new->prev = prev;
                return;
            }
            new->next = temp;
            return;
        }
        prev = temp;
        temp = temp->next;
    }
}

void Enter(struct link** HEAD, struct link** TAIL) {
    struct link* temp = (struct link*)malloc(sizeof(struct link));
    if (temp == NULL) {
        printf("메모리 할당 실패\n");
        exit(1);
    }

    printf("id : ");
    scanf("%d", &temp->id); // 멤버가 int형이니 scanf때 &로 참조하기
    getchar();

    printf("이름 : ");
    fgets(temp->bookname, 20, stdin);
    temp->bookname[strlen(temp->bookname) - 1] = '\0';

    temp->next = NULL;
    temp->prev = NULL;

    if (*HEAD == NULL) {
        *HEAD = temp;
        *TAIL = temp;
    }
    else {
        (*TAIL)->next = temp;
        temp->prev = *TAIL;

        *TAIL = temp;
    }
}

void load(struct link** HEAD, struct link** TAIL) {
    FILE* f = fopen("list.txt", "r");

    printf("filename : %s\n", __FILE__);
    printf("function name : %s\n", __FUNCTION__);



    if (f == NULL) {
        fprintf(stderr, "파일 열리지 않음\n");
        exit(1);
    }

    int id;
    char bookname[80];
    while (fscanf(f, "%d %s", &id, bookname) != EOF) {
        struct link* newNode = (struct link*)malloc(sizeof(struct link));
        if (newNode == NULL) {
            fprintf(stderr, "메모리 할당 실패\n");
            exit(1);
        }

        newNode->id = id;
        strcpy(newNode->bookname, bookname, sizeof(newNode->bookname) - 1);
        newNode->bookname[sizeof(newNode->bookname) - 1] = '\0'; 
        newNode->next = NULL;
        newNode->prev = NULL;

        if (*HEAD == NULL) {
            *HEAD = newNode;
            *TAIL = newNode;
        }
        else {
            (*TAIL)->next = newNode;
            newNode->prev = *TAIL;
            *TAIL = newNode;
        }
    }
    fclose(f);
}


void save(struct link** HEAD) {
    FILE* f = fopen("list.txt", "w");
    if (f == NULL)
    {
        fprintf(stderr, "파일 열리지 않음");
        exit(1);
    }
    struct link* temp = *HEAD;
    while (temp != NULL) {
        fprintf(f, "%d %s\n", temp->id, temp->bookname);
        printf("%d %s\n", temp->id, temp->bookname);
        temp = temp->next;
    }
    fclose(f);
}

int main() {
    struct link* HEAD = NULL;
    struct link* TAIL = NULL;

    load(&HEAD, &TAIL);

    while (1) {
        printf("1 : 입력\n");
        printf("2 : 출력\n");
        printf("3 : 검색\n");
        printf("4 : 삭제\n");
        printf("5 : 삽입\n");
        printf("9 : 종료\n");
        printf("선택 --> ");

        int num = 0;
        scanf("%d", &num);

        switch (num) {
        case 1: // 입력
            Enter(&HEAD, &TAIL);
            break;
        case 2: // 출력
            printList(HEAD);
            break;
        case 3: // 검색
        {
            getchar();
            char name[20];
            printf("검색할 책 이름을 입력하세요: ");
            fgets(name, 20, stdin);
            name[strlen(name) - 1] = '\0';
            search(name, HEAD);
            break;
        }
        case 4: // 삭제
        {
            getchar();
            char name[20];
            printf("삭제할 책 이름을 입력하세요: ");
            fgets(name, 20, stdin);
            name[strlen(name) - 1] = '\0';
            deleteNode(name, &HEAD, &TAIL);
            break;
        }
        case 5: // 삽입
        {
            int tmp = 0;
            printf("삽입할 위치의 id를 입력하세요: ");
            scanf("%d", &tmp);
            insertNode(tmp, &HEAD, &TAIL);
            break;
        }
        case 9: // 종료
            printf("종료합니다\n");;
            save(&HEAD);
            {
                // 메모리 해제
                struct link* temp = HEAD;
                struct link* btemp;
                while (temp != NULL) {
                    btemp = temp->next;
                    free(temp);
                    temp = btemp;
                }
            }
            return 0;
        default:
            printf("잘못된 선택입니다. 다시 선택해주세요.\n");
            break;
        }
    }
}

 

'대외활동 > 시스템프로그래밍' 카테고리의 다른 글

임베디드 C  (4) 2024.07.22
리눅스 C 환경설정  (0) 2024.07.22
volatile 지시자  (0) 2024.07.19
1주차 C 전처리, 매크로, 조건부 컴파일  (1) 2024.07.19
1주차 C 공용체,열거형,파일 입출력  (0) 2024.07.19