반응형
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>
#define MAX 50
#define TRUE 1

typedef struct StudentInfo
{
    int Number;
    char Name[10];
    int Age;
    char Gender[10];
    int Grade;
}StudentInfo;

int SetStudent(StudentInfo* student, int count)
{
    student->Number = ++count;
    printf("====%d번 학생====", student->Number);
    printf("\n이름 입력 : ");
    scanf("%s", student->Name);
    printf("\n나이 입력 : ");
    scanf("%d", &student->Age);
    printf("\n성별 입력 : ");
    scanf("%s", student->Gender);
    printf("\n학년 입력<1~3> : ");
    scanf("%d", &student->Grade);

    return count;
}

void ShowStudent(StudentInfo* student)
{
    printf("====%s학생<%d번>====\n", student->Name, student->Number);
    printf("나이 : %d, 성별 : %s, 학년 : %d\n", student->Age, student->Gender, student->Grade);
    printf("==========\n");
}

void ShowStudentByGrade(StudentInfo* studentArr[], int grade)
{
    printf("========%d 학년 \n", grade);
    for (int i = 0; studentArr[i] != NULL; i++)
    	if (studentArr[i]->Grade == grade)
        	ShowStudent(studentArr[i]);

    printf("==========\n");
}

void SearchStudentByGrade(StudentInfo* studentArr[])
{
    int grade = 0;
    printf("학년 입력 : ");
    scanf("%d", &grade);

    system("cls");
    if (grade > 0 && grade <= 3)
    	ShowStudentByGrade(studentArr, grade);
}

void SearchStudentByName(StudentInfo* studentArr[])
{
    char name[10] = { 0 };
    printf("이름 입력 : ");
    scanf("%s", name);

    system("cls");
    for (int i = 0; studentArr[i] != NULL; i++)
    	if (strcmp(studentArr[i]->Name, name) == 0)
    		ShowStudent(studentArr[i]);
}

void Save(StudentInfo* studentArr[])
{
    FILE* file = fopen("Students.txt", "w");

    for (int i = 0; studentArr[i] != NULL && i < MAX; i++)
    	fprintf(file, "%s %d %s %d\n", studentArr[i]->Name, studentArr[i]->Age,
    	studentArr[i]->Gender, studentArr[i]->Grade);

    fclose(file);
}

//포인터로 반환해도 좋지만, return으로 반환을 우선으로 생각한다.
int Load(StudentInfo* studentArr[], int count)
{
    if (count + 1 >= MAX)
    {
    	printf("학생목록을 더이상 불러올 수 없습니다.");
    	system("pause");
    	return;
    }

    FILE* file = fopen("Students.txt", "r");
    if (file == NULL)
    {
    	printf("해당 파일이 존재하지 않습니다.");
    }
    else
    {
    	for (; count < MAX; count++)
        {
            studentArr[count] = (StudentInfo*)malloc(sizeof(StudentInfo));
            studentArr[count]->Number = count + 1;
            int eof = fscanf(file, "%s%d%s%d", studentArr[count]->Name, &studentArr[count]->Age,
            studentArr[count]->Gender, &studentArr[count]->Grade);
            if (eof == EOF)
            {
                free(studentArr[count]);
                studentArr[count] = NULL;
                break;
            }
        }

        fclose(file);

        return count;
    }
}

void main()
{
    StudentInfo* studentArr[MAX] = { 0 };
    int count = 0;
    while (TRUE)
    {
    	system("cls");
        int label = 0;

        printf("====학생관리프로그램====(total : %d)\n", count);
        printf("  1. 학생 등록\n");
        printf("  2. 학생 목록<번호순>\n");
        printf("  3. 학생 목록<학년순>\n");
        printf("  4. 학년 검색\n");
        printf("  5. 학생 검색\n");
        printf("  6. 마지막 학생 삭제\n");
        printf("  7. 학생 전체 삭제\n");
        printf("  8. 학색 목록 저장하기\n");
        printf("  9. 학색 목록 불러오기\n");
        printf("  10. 종료\n");
        printf("입력 : ");
        scanf("%d", &label);

        system("cls");
        switch (label)
        {
        case 1:
            if (count + 1 >= MAX)
            {
            	printf("정원(50명) 초과");
                system("pause");
                break;
            }

            studentArr[count] = (StudentInfo*)malloc(sizeof(StudentInfo));
            count = SetStudent(studentArr[count], count);
            break;
        case 2:
            for (int i = 0; i < count; i++)
                ShowStudent(studentArr[i]);

            system("pause");
            break;
        case 3:
            for (int i = 0; i < 3; i++)
                ShowStudentByGrade(studentArr, i + 1);

            system("pause");
            break;
        case 4:
            SearchStudentByGrade(studentArr);
            system("pause");
            break;
        case 5:
            SearchStudentByName(studentArr);
            system("pause");
            break;
        case 6:
            if (count > 0)
            {
            	count--;
                free(studentArr[count]);
                studentArr[count] = NULL;
            }
            break;
        case 7:
            count = 0;
            for (int i = 0; studentArr[i] != NULL; i++)
            {
            	free(studentArr[i]);
                studentArr[i] = NULL;
            }
            break;
        case 8:
            if (count > 0)
                Save(studentArr);
            break;
        case 9:
            count = Load(studentArr, count);
            break;
        case 10:
            return;
        }
    }
}

  ※ SetSudent함수 : Grade 값이 범위 안(1학년~3학년) 사이에 들지 않는 오입력이 일어날 수 있으므로 필요하면 while문으로 범위 안에 들어올 때까지 계속 값을 요구하는 코드를 넣을수도 있다.

  ※ SetStudent함수, Load 함수 : count 인수를 포인터로 받을수도 있지만 이런 경우엔 포인터로 인수를 받기보단 return 값을 먼저 생각해서 작성한다.

  ※case 10 (종료 Label) : 프로그램이 종료되면 동적 할당이 자동으로 반환되지만, 해제 후 return해도 무방하다.

반응형

'Stack > C' 카테고리의 다른 글

C 파일 입출력  (0) 2021.08.24
C 구조체, 구조체 포인터  (0) 2021.08.22
C 동적할당  (0) 2021.08.22
C 포인터, 배열  (0) 2021.08.22
반응형

파일 입출력

- 프로그램 내의 정보를 외부 파일에 저장하거나 외부 파일의 정보를 프로그램으로 불러오는 방식.

  ※ 스트림 : 구현한 프로그램과 참조할 데이터가 저장되어 있는 파일 사이에 놓는 다리.

- 필요 헤더 : <stdio.h>

 

fopen 함수

- FILE* fopen(char* filename, char* mode)

- mode 값에 따라 파일 입출력 옵션이 정해진다

  ※ w(덮어쓰기) : 파일이 없을 경우 새로 만듦, 내용이 있을 경우 전부 지우고 다시 작성됨.

  ※ a(추가) : 파일이 없을 경우 새로 만듦, 내용이 있을 경우 마지막 내용 뒤 추가.

  ※ r(읽기) : 파일이 없을 경우 NULL을 반환한다.

- 성공 시 해당 FILE 구조체 변수의 주소 값, 실패시 NULL 반환

  ※ 구조체의 주소 값을 반환하기 때문에 FILE 포인터로 변수를 선언함.

  ※ 해당 함수를 호출하면 FILE 구조체 생성 후, 구조체 변수에 파일에 대한 정보가 담긴다.

 

fclose 함수

- int fclose(FILE* stream)

- fopen으로 인해 형성된 스트림을 해제하는 함수

  ※ 운영 체제가 할당한 자원(주로 메모리)을 반환한다.

  ※ 스트림 중간에 존재하는, 버퍼링 되어있던 데이터의 출력.

- 성공 시 0, 실패 시 EOF를 반환

  ※ EOF : end of file, -1의 값을 가지고 있는 상수이다.

 

fprintf 함수

- int fprintf(FILE* stream, char* format)

- 파일의 내용 출력

  ※ 출력의 대상이 콘솔이 아닌 파일이다.

 

구구단 예시

#include<stdio.h>

void main()
{
    FILE* file = fopen("GoGoDan.txt", "w");
    for(int i = 1; i <= 9; i++)
        for(int j = 1; j <= 9; j++)
            fprintf(file, "%d x %d = %d\n", i, j, i * j);
    
    fclose(file);
    
    //결과 : 1단 ~ 9단까지 구구단
}

 

fscanf 함수

- int fscanf(FILE* stream, char* format)

  ※ 파일의 끝에 도달하면 EOF를 반환한다.

- 띄어쓰기 또는 엔터 단위로 정보를 가져온다.

- 파일의 내용 입력

  ※ 입력의 대상이 콘솔이 아닌 파일이다.

 

fgets 함수

- char* fgets(char* buffer, int count, FILE* stream)

- 엔터 단위로 정보를 가져온다.

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>

typedef struct temp
{
    char arr[10];
    int a;
}Temp;

void main()
{
    Temp tmp = { "A", 10 };
    FILE* file = fopen("Tmp.txt", "w");
    char buf[256];
    fprintf(file, "%s\n", tmp.arr);
    fprintf(file, "%d", tmp.a);
    fclose(file);
    
    file = fopen("Tmp.txt", "r");
    if (file == NULL)
    {
        printf("해당 파일이 존재하지 않습니다.\n");
    }
    else
    {
        while (!feof(file))
        {
            fgets(buf, sizeof(buf), file);
            printf("%s", buf);
        }
        
        fclose(file);
    }
    
    // 결과 : A
    //        10
}

 

fread 함수

- char* fread(char* buffer, size_t size, size_t count, FILE* stream)

  ※ count는 바이트 수이다. 보통 1로 둔다.

- 성공지 전달인자 count, 실패 또는 파일의 끝 도달 시 count보다 작은 값 반환

- fgets 함수와는 달리 비어있는 부분은 NULL로 채워주지 않는다.

  ※ 그렇기 때문에 buffer 배열을 선언시에 초기화 후 사용한다.

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>

typedef struct temp
{
    char arr[10];
    int a;
}Temp;

void main()
{
    Temp tmp = { "A", 10 };
    FILE* file = fopen("Tmp.txt", "w");
    char buf[256] = {0};
    fprintf(file, "%s %d\n", tmp.arr, tmp.a);
    fclose(file);
    
    file = fopen("Tmp.txt", "r");
    if (file == NULL)
    {
        printf("해당 파일이 존재하지 않습니다.\n");
    }
    else
    {
        fread(buf, sizeof(buf), 1, file);
        printf("%s", buf);
        
        fclose(file);
    }
    
    // 결과 : A 10
}

  ※ buffer 선언부를 보면 초기화 한것을 확인할 수 있다.

반응형

'Stack > C' 카테고리의 다른 글

C 중간 활용 : 학생 관리 시스템 만들기  (0) 2021.08.24
C 구조체, 구조체 포인터  (0) 2021.08.22
C 동적할당  (0) 2021.08.22
C 포인터, 배열  (0) 2021.08.22
반응형

구조체

- 하나 이상의 변수(포인터와 배열 포함)를 묶어서 새로운 사용자정의 자료형

- 실존하는 정보를 데이터화 하는 추상화 작업

  ※ class와의 차이점은 접근지시자를 사용하지 않을시 struct는 public, class는 private으로 설정된다.

//type 1
struct example
{
    int a;
    char arr[10];
};

void main()
{
    struct example exam = { 10, "test" };
    printf("%d, %s", exam.a, exam.arr);
    
    //결과 10, test
}

 

typedef 선언

- typedef는 기존의 자료형의 이름에 새 이름(별명)을 부여하는 것을 목적으로 선언된다.

  ※ typedef int INT : int의 또 다른 이름 INT를 부여.

//type 2
struct example
{
    int a;
    char arr[10];
};

typedef struct example Example;

//type 3
typedef struct example
{
    int a;
    char arr[10];
}Example;

void main()
{
    Example exam = { 10, "test" };
    printf("%d, %s", exam.a, exam.arr);
    
    //결과 10, test
}

  ※ type 2와 같이 구조체 선언 후 typedef로 지정하는 법과 type 3과 같이 선언과 동시에 지정하는 방법이 있다.

 

구조체 변수와 포인터

- 기존 포인터와 선언 형식 및 접근의 방법이 다르지 않다.

typedef struct example
{
    int a;
    char arr[10];
}Example;

void main()
{
    Example exam = { 10, "test" };
    Example* exptr = &exam;
	
    printf("%d, %s", (*exptr).a, (*exptr).arr);
    
    //결과 10, test
}

  ※ 접근을 위해 포인터 변수를 대상으로 *연산을 하는것은 동일하다. 다만 구조체 포인터이기 때문에 변수에 접근하기위해 .연산을 추가해야한다.

  ※ *연산과 .연산을 하나의 ->연산으로 대체가 가능하다.

typedef struct example
{
    int a;
    char arr[10];
}Example;

void main()
{
    Example exam = { 10, "test" };
    Example* exptr = &exam;
	
    printf("%d, %s", exptr->a, exptr->arr);
    
    //결과 10, test
}

 

반응형

'Stack > C' 카테고리의 다른 글

C 중간 활용 : 학생 관리 시스템 만들기  (0) 2021.08.24
C 파일 입출력  (0) 2021.08.24
C 동적할당  (0) 2021.08.22
C 포인터, 배열  (0) 2021.08.22
반응형

메모리 공간

Code 영역 실행할 프로그램의 명령코드 저장 공간
Data 영역 전역변수 저장 공간
Heap 영역 동적할당 저장 공간
Stack 영역 지역, 매개 변수 저장 공간

 

메모리 할당

- 정적 할당

  - 컴파일 시 할당될 메모리 크기가 결정

  - Stack, Data 영역에 변수로 할당되는 메모리

- 동적 할당

  - 실행 중 메모리 할당

  - 동적할당 메모리는 Heap영역에 할당

 

Heap 영역의 특징

- Heap 영역은 자료형의 개념이 없음. byte단위로 정보를 처리한다.

- Heap 영역은 일반적인 Stack과 Data영역보다 넓은 메모리 영역을 가진다.

- 할당된 메모리의 시작주소를 malloc함수를 호출한 지역으로 반환한다.

- 시작주소만 반환 되기 때문에 Stack영역에서 사용하려면 해당 자료형 주소로 형변환 해야한다.

- Heap영역에 할당된 메모리는 자동으로 해제되지 않는다.

 

malloc 함수

- Heap 영역에 동적으로 공간을 할당 해주는 함수

- 필요 헤더 : <stdlib.h>

- (void*)malloc(size)

  ※ 할당 하고싶은 자료형을 byte 단위로 인자값을 보낸 후 할당된 메모리의 시작주소를 해당 자료형으로 형변환 후 사용.

  ※ 할당에 성공하면 해당 주소값을 반환하고, 실패하면 NULL을 반환한다.

  ※ int* a = (int*)malloc(sizeof(int));

 

free 함수

- Heap영역에 할당된 공간을 해제하는 함수

- 필요 헤더 : <stdlib.h>

- free(void*)

  ※ Heap 영역에 할당된 메모리는 자동으로 해제되지 않는다.

  ※ 해제를 한다고 해당 포인터 변수의 값이 없어지는것이 아니다. (메모리 사용 권한만 취득, 반납하는 개념)

  ※ 해제를 한 후 해당 포인터 변수는 NULL로 밀어준다.

  ※ free(ptr);

     ptr = NULL;

반응형

'Stack > C' 카테고리의 다른 글

C 중간 활용 : 학생 관리 시스템 만들기  (0) 2021.08.24
C 파일 입출력  (0) 2021.08.24
C 구조체, 구조체 포인터  (0) 2021.08.22
C 포인터, 배열  (0) 2021.08.22
반응형

포인터

- 포인터 : 주소값을 저장하기 위한 변수

- 포인터 size : 4byte(32bit), 8byte(64bit)

- 포인터형 : (자료형)* 변수명

   ※ 포인터형도 자료형 범주에 포함시키기도 한다.

   ※ *연산자의 위치는 상관없다.

   ※ 포인터에 형이 없으면 *연산을 통한 메모리 접근은 불가능하다.

- 포인터 변수의 자료형은 해당 주소의 자료형과 동일해야 한다.

- 포인터의 형이 존재하는 이유는 메모리 공간을 참조하는 기준이 된다.

  ※ int* ptr : 해당 변수에 저장되어있는 주소값으로 가서 sizeof(int)(4byte)를 읽어들여 정수로 해석한다.

- NULL 포인터 : 아무데도 가리키지 않는다.

   ※ int* ptr = 0 or NULL

 

#include<stdio.h>

void main()
{
    int a = 10;
    int* ptr = &a;
    
    //ptr은 주소값을 가지므로 ptr == &a
    printf("var a address : %p, pointer ptr value : %d", ptr, *ptr);
}

 


배열

- 배열의 이름은 포인터이다.

  ※ 단, 값을 바꿀 수 없는 '상수 형태의 포인터'이다.

  ※ 배열의 이름도 포인터이기 때문에 배열의 이름을 피연산자로 하는 *연산이 가능하다.

  포인터 변수 배열 이름
이름 유무
저장하는 값 주소 값 주소 값
주소 값 변경 가능한가? 가능(변수) 불가능(상수)

 

- 포인터 변수를 배열로 사용하기

#include<stdio.h>
#define MAX 3

void main()
{
    //포인터에 배열의 이름을 넣어 배열처럼 사용 가능
    int arr[3] = {0, 1, 2};
    int* ptr = arr or &arr[0];

    for(int i = 0; i < MAX; i++)
    {
        ptr[i] += 1;
        printf("%d", ptr[i]);
    }
    
    //결과 1 2 3
}

 

 

- 배열의 다른 표현방법

#include<stdio.h>
#define MAX 3

void main()
{
    int arr[3] = {0, 1, 2};
    int* ptr = arr or &arr[0];

    for(int i = 0; i < MAX; i++)
    {
        *(ptr + i) += 1;
        printf("%d", *(ptr + i));
    }
    
    //결과 1 2 3
}

  ※ int형 포인터를 대상으로 1을 증가시키면 4가 증가한다.

  ※ int 형 포인터를 대상으로 +-n => +-n * sizeof(int)

  ※ 결론 arr[i] == *(arr + i)

 

- 활용

#include<stdio.h>

//배열도 포인터이기 때문에 인수를 char str[]로 사용해도 무방하다.
void ConvertLowercase(char* str)
{
    for (int i = 0; str[i] != NULL; i++)
        if (str[i] >= 'A' && str[i] <= 'Z')
            str[i] += 32;
}

void main()
{
    char arr[3] = "AB";
    ConvertLowercase(arr);
    printf("%s", arr);
    
    //결과 ab
}

  ※ char 배열의 마지막은 NULL(\0)로 채워지므로 for문 조건문에 NULL을 사용할 수 있다.

 


포인터 배열

- 포인터 변수로 이뤄진, 주소 값의 저장이 가능한 배열을 가리킨다.

#include<stdio.h>
#define MAX 3

void main()
{
    int a = 10, b = 20, c = 30;
    int* arr[3] = {&a, &b, &c};

    for(int i = 0; i < MAX; i++)
        printf("%d", *arr[i]);
    
    //결과 10 20 30
}
반응형

'Stack > C' 카테고리의 다른 글

C 중간 활용 : 학생 관리 시스템 만들기  (0) 2021.08.24
C 파일 입출력  (0) 2021.08.24
C 구조체, 구조체 포인터  (0) 2021.08.22
C 동적할당  (0) 2021.08.22

+ Recent posts