배열 선언할때 크기+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 |