IT공부/IT서적

[윤성우 열혈 C프로그래밍] Part4. C언어의 깊은 이해

shine94 2024. 7. 28. 16:53

** 스트림(stream)

 : 프로그램상에서 모니터와 키보드를 대상으로 데이터를 입출력 하기 위해서는 이들을 연결시켜 주는 다리가 필요

   →  이러한, 다리의 역할을 하는 매개체

   [운영체제]에서 제공하는 소프트웨어적인 가상의 다리

   [운영체제]는 외부장치와 프로그램과의 데이터 송수신의 도구가 되는 스트림을 제공

         ㄴ 출력 스트림 : 실행중인 프로그램과 모니터를 연결 - (예) printf

         ㄴ 입력 스트림 : 실행중인 프로그램과 키보드를 연결 - (예) scanf

 

** 콘솔(일반적으로 키보드와 모니터를 의미) 입출력과 파일 입출력 사이의 차이점

 : 파일과의 연결을 위한 스트림 생성은 우리가 직접 요구해야하지만,

   콘솔과의 연결을 위한 스트림의 생성은 요구할 필요 없음

 

   정리하면, 콘솔 입출력을 위한 입력 스트림과 출력스트림은 프로그램이 실행되면 자동으로 생성되고,

                    프로그램이 종료되면 자동으로 종료됨

 

** 제공하는 표준 스트림 3가지

   1) stdin(표준 입력 스트림) : 키보드를 대상으로 입력

   2) stdout(표준 출력 스트림) : 모니터를 대상으로 입력

   3) stderr(표준 에러 스트림) : 모니터를 대상으로 출력

 

   → 추후, 입출력 리다이렉션(redirection) 기술을 배우면 stdout과 stderr를 구분하게 됨

   → 스트림이란 단어에는 단 한방향 으로만 데이터 전송이 이뤄진다는 뜻이 담겨져 있다

       실제로 입출력 스트림도 ① 입력 스트림과 ② 출력 스트림으로 구분되어

       한 방향으로만 데이터의 흐름을 유지하고 있다

 

** 문자 단위 입출력 함수

1) 문자 출력 함수 : putchar, fputc

   #include <stdio.h>

  ① int putchar(int c);

  ② int fputc(int c, FILE * stream);

       ㄴ 두번째 인자로 파일의 스트림 정보를 전달하면 해당 파일로 문자가 전달(해당 파일에 문자가 저장)됨

 

2) 문자 입력 함수 : getchar, fgetc

   #include <stdio.h>

   ① int getchar(void);

   ② int fgetc(FILE * stream);

        ㄴ 문자를 입력받을 스트림을 지정할 수 있음

 

#include <stdio.h>

int main(void)
{
    int ch1, ch2;

    ch1 = getchar();
    ch2 = fgetc(stdin);

    printf("=============================\n");
    putchar(ch1);
    printf("\n-----------------------------\n");
    fputc(ch2, stdout);
    printf("=============================\n");

    return 0;
}

 

** 문자 입출력에서의 EOF

 : End Of File의 약자로서, 파일의 끝을 표현하기 위해서 정해놓은 상수

   ① 함수 호출의 실패

   ② Windows에서 Ctrl + Z키, Linux에서 Ctrl + D키가 입력되는 경우

 

** 반환형이 int이고, int형 변수에 문자를 담는 이유?

   ① char를 unsigned char로 처리하는 컴파일러 존재

   ② EOF는 -1로 정의된 상수

 

** 문자열 단위 입출력 함수

1) 문자열 출력 함수 puts, fputs

   #include <stdio.h>

   ① int pusts(const char * s);

   ② int fputs(const char * s, FILE * stream);

 

   puts 함수가 호출되면 문자열 출력 후 자동으로 개행 됨,

   fputs 함수가 호출되면 문자열 출력 후 자동으로 개행이 안 됨.

 

   + printf()와 차이점

      : 위의 함수들은 문자열만 되지만, printf()는 문자열 및 다양한 정보를 서식화하여 출력하는 함수

         ㄴ https://codingadinga.tistory.com/2

 

[C언어 기초] 출력함수 puts( )와 printf( ) 공통점과 차이점

함수 puts( )와 printf( )의 공통점 두 함수를 모두 전처리 지시자 #include로 헤더 파일 를 입력해야 한다. 헤더 파일 에는 표준 입출력 함수를 위한 함수 원형이 들어있으며 puts( )와 printf( )는 모두 출

codingadinga.tistory.com

 

2) 문자열 입력 함수 : gets, fgets

   #include <stdio.h>

   ① char * gets(char * s);

   ② char * fgets(char * s, int n, FILE * stream);

 

   (예) gets(str);

          fgets(str, sizeof(str), stdin);

          ㄴ stdin으로부터 문자열을 입력받는데 배열 str에 저장하되, sizeof(str)의 길이만큼 저장하란 뜻

 

   미리 마련해놓은 배열을 넘는 문자열을 입력하면,

   할당 받지 않은 메모리 공간을 침범하여 실행 중 오류가 발생한다는 단점이 있기 때문에

   fgets 함수를 사용하기를 권장

 

   + scanf()와 차이점

      : scanf 함수는 \n이나 공백 전까지 문자열을 가져오고 마지막에 널문자를 붙이나,

        fgets 함수는 \n을 만날 때까지 문자열을 가져오나 \n도 포함하여 가져와서 널 문자를 붙인다

                            따라서 중간에 삽입된 공백 문자도 문자열의 일부로 읽음

      ㄴ https://velog.io/@fkstndnjs/scanf-gets-fgets-%EC%B0%A8%EC%9D%B4

 

scanf(), gets(), fgets() 차이

C Programming

velog.io

      ㄴ https://halfmoonbearlog.tistory.com/38

 

[실험] #20 C언어 fgets gets scanf의 차이를 확실하게 알아보자 \0\n의 차이점도 같이 알아보자

우선 \0은 아스키 코드로 0 즉 (int)0이고 \n은 아스키 코드로 10 즉 (int)10입니다. 의례 말하는 널, NULL은 \0을 뜻하고 \0은 문자열의 끝을 알려주는 문자입니다. 대부분의 함수가 문자열을 처리할때 \0

halfmoonbearlog.tistory.com

 

** 표준 입출력 기반의 버퍼(buffer) - 출력 버퍼, 입력 버퍼

 : 표준 입출력 함수를 통해서 데이터를 입출력 하는 경우,

   해당 데이터들은 운영체제가 제공하는 메모리 버퍼를 중간에 통과

   ㄴ 메모리 버퍼 : 데이터를 임시로 저장하는 메모리 공간

 

** 버퍼링(Buffering)을 하는 이유?

   데이터 전송의 효율성

   (예) 창고 물건 나를때, 손 vs 손수레

 

** 버퍼 비우기, 함수 호출 성공시 0, 실패시 EOF 반환

   #include <stdio.h>

   int fflush(FILE * stream);

 

   1) fflush(stdout); - 표준 출력 버퍼 비우기

        : 버퍼에 저장된 내용이 비워지면서 데이터가 목적지로 이동

 

   2) ClearLineFromReadBuffer(); - 입력 버퍼 지우기

        : \n이 읽혀질 때까지 입력버퍼에 저장된 문자들을 지우는 함수

#include <stdio.h>

void ClearLineFromReadBuffer()
{
    while(getchar() != '\n');
}

int main(void)
{
    char perId[7];
    char name[10];

    fputs("Enter the first 6 digits of your social security number : ",  stdout);
    fgets(perId, sizeof(perId), stdin);

    ClearLineFromReadBuffer();      // 입력 버퍼 지우기

    fputs("Enter Name : ",  stdout);
    fgets(name, sizeof(name), stdin);

    printf("\nsocial security number : %s\n", perId);
    printf("name : %s\n", name);
    return 0;
}

 

** 문자열 관련 함수

1) 전달된 문자열의 길이를 반환하되, 널 문자는 길이에 포함하지 않음

   #include <string.h>

   size_t strlen(const char * s);

 

2) 복사된 문자열의 주소 값 반환

   #include <string.h>

   char * strcpy(char * dest, const char * src);

   char * strncpy(char * dest, const char * src, size_t n);

 

3) 덧붙여진 문자열의 주소 값 반환

   #include <string.h>

   char * strcat(char * dest, const char * src);

   char * strncat(char * dest, const char * src, size_t n);

 

4) 문자열 비교, 두 문자열의 내용이 같으면 0, 같지 않으면 0이 아닌 값 반환

   #include <string.h>

   int strcmp(const char * s1, const char * s2);

   int strncmp(const char * s1, const char * s2, size_t n);

 

5) 그 외

   문자열의 내용을 int형으로 변환 : int atoi(const  char * str);

   문자열의 내용을 long형으로 변환 : long atol(const char * str);

   문자열의 내용을 double형으로 변환 : double atof(const char * str);

 

** 구조체(structure), 사용자 정의 자료형(user defined data type)

 : 하나 이상의 변수(포인터 변수와 배열 포함)를 묶어서 새로운 자료형을 정의하는 도구

// 1. 구조체 정의
struct Person
{
    char name[20];
    char phoneNum[20];
    int age;
};

// 2. 구조체 변수 선언
struct Person man;

// 3. 구조체 변수 안에 존재하는 멤버에 접근하여 데이터 저장
*(man.name) = 's';
*(man.name + 1) = 'h';
*(man.name + 2) = 'i';
*(man.name + 3) = 'n';
*(man.name + 4) = 'e';
strcpy(man.phoneNum, "010-1111-1111")
man.age = 21;

// 4. 구조체 변수의 초기화
struct Person man = {"shine", "010-1111-1111", 21};

 

** 구조체 배열의 선언과 접근, 구조체 배열의 초기화

// 1. 구조체 배열의 선언과 접근
struct Person person[2];

strcpy(person[0].name, "zero");
strcpy(person[0].phoneNum, "010-0000-0000");
person[0].age = 20;

strcpy(person[1].name, "one");
strcpy(person[1].phoneNum, "010-1111-1111");
person[1].age = 21;

printf("1. name : %s, phone : %s, age : %d\n", person[0].name, person[0].phoneNum, person[0].age);
printf("2. name : %s, phone : %s, age : %d\n", person[1].name, person[1].phoneNum, person[1].age);


// 2. 구조체 배열의 초기화
struct Person person[2] = {
    {"zero", "010-0000-0000", 20},
    {"one", "010-1111-1111", 21}
};

printf("1. name : %s, phone : %s, age : %d\n", person[0].name, person[0].phoneNum, person[0].age);
printf("2. name : %s, phone : %s, age : %d\n", person[1].name, person[1].phoneNum, person[1].age);

 

** 구조체 변수와 포인터

struct Person man = {"shine", "010-1111-1111", 21};
struct Person * pptr = &man;

printf("1. name : %s, phone : %s, age : %d\n", man.name, man.phoneNum, man.age);

strcpy((*pptr).name, "change");
strcpy((*pptr).phoneNum, "010-1111-1111");
(*pptr).age = 100;

printf("2. name : %s, phone : %s, age : %d\n", man.name, man.phoneNum, man.age);

strcpy(pptr->name, "happy");
strcpy(pptr->phoneNum, "010-2222-2222");
pptr->age = 200;

printf("3. name : %s, phone : %s, age : %d\n", man.name, man.phoneNum, man.age);

 

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

 

** 배열이 구조체 멤버로 선언될 수 있듯이, 포인터 변수도 구조체의 멤버가 될 수 있음

 

** 구조체 변수의 주소 값 == 첫 번째 멤버의 주소 값

 

** typedef 선언 : 새 이름을 부여, 대문자로 시작하는 것이 관례

typedef int ElementType;

typedef struct TagSLLNode
{
    ElementType data;
    struct TagSLLNode* nextNode;
}Node;

Node* List1 = NULL;
struct TagSLLNode* List2 = NULL;

 

** 인자의 전달 과정에서, 그리고 값의 반환 과정에서 구조체의 멤버로 선언된 배열도 통째로 복사됨

    ㄴ 그럼 Call-by-reference 형태는? 구조체의 포인터 변수도 매개변수로 선언

#include <stdio.h>

typedef struct Coordinate
{
    int x;
    int y;
}Co;

void ChangeZeroCo(Co* co)
{
    co->x = 0;
    co->y = 0;
}

int main(void)
{
    Co co = {5, 5};
    printf("(%d, %d)\n", co.x, co.y);

    ChangeZeroCo(&co);
    printf("(%d, %d)\n", co.x, co.y);
}

 

** 구조체를 통해서 연관있는 데이터를 하나로 묶을 수 있는 자료형을 정의하면,

   데이터의 표현 및 관리가 용이해지고,

   그만큼 합리적인 코드를 작성할 수 있음

 

** 공용체(Union Type) : 하나의 메모리 공간을 둘 이상의 방식으로 접근 가능

 

** 열거형(Enumerated Type) : 변수에 저장이 가능한 값들을 열거하여 정의

   ㄴ 상수의 값을 명시하지 않으면 0부터 시작

   ㄴ 둘 이상의 연관이 있는 이름을 상수로 선언함으로써 프로그램의 가독성을 높임

 

** 파일 입출력

1) 프로그램상에서 파일과의 스트림 형성

   #include <stdio.h>

   FILE * fopen(const char * filename, const char * mode);

    ㄴ 성공시 해당 파일의 FILE 구조체 변수의 주소값, 실패시 NULL 포인터 반환

 

2) 파일에 데이터 쓰기

   #include <stdio.h>

   int fputc(int c, FILE * stream);                // 문자 출력

   int fputs(const char * s, FILE * stream); // 문자열 출력

 

3) fclose 함수 : 스트림의 소멸을 요청

① 운영체제가 할당한 자원의 반환

② 버퍼링 되었던 데이터의 출력

   #include <stdio.h>

   int fclose(FILE * stream);

    ㄴ 성공시 0, 실패시 EOF 반환

 

4) fflush 함수 : 스트림을 종료하지 않고 버퍼만 비우기(출력버퍼만 가능)

   #include <stdio.h>

   int fflush(FILE * stream);

    ㄴ 함수 호출 성공시 0, 실패시 EOF 반환

 

5) 파일로부터 데이터 읽기

   #include <stdio.h>

   int fgetc(FILE * stream);

   char * fgetc(char * s, int n,  FILE * stream);

 

6) 파일의 개방 모드(Mode)

모드(mode) 스트림의 성격 파일이 없으면?
r 읽기 가능 에러
w 쓰기 가능 생성
a 파일의 끝에 덧붙여 쓰기 가능 생성
r+ 읽기/쓰기가능 에러
w+ 읽기/쓰기 가능 생성
a+ 읽기/덧붙여 쓰기 가능 생성
t 텍스트 모드  

 

** 텍스트 파일(text file) : 사람이 인식할 수 있는 문자를 담고 있는 파일

 

** 바이너리 파일(binary file) : 컴퓨터가 인식할 수 있는 데이터를 담고 있는 파일

 

** 개행은 환경이 다르면 표시가 다를 수 있는데 파일을 텍스트 모드로 개방하면 변환이 자동으로 이뤄져 \n로 표시하면 됨

 

** 메모리 영역별로 저장되는 데이터 유형

1) 코드 영역(Code Area)

 : 실행할 프로그램의 코드가 저장되는 메모리 공간

 

2) 데이터 영역(Data Area)

 : 전역변수와 static으로 선언되는 static 변수가 할당, 프로그램 종료시까지 남아있음

 

3) 스택 영역(Stack Area)

 : 지역변수와 매개변수가 할당, 함수를 빠져나가면 소멸

 

4) 힙 영역(Heap Area)

 : 프로그래머가 원하는 시점에 변수를 할당하고 소멸시킬 수 있는 곳(= 동적할당)

 

** 메모리의 동적 할당

1) 힙 영역의 메모리 공간 할당과 해제

#include <stdlib.h>

void * malloc(size_t size); // 힙 영역으로의 메모리 공간 할당

 ㄴ 할당된 메모리 주소값, 실패시 NULL 반환

 ㄴ 리턴이 void*인 이유? 어떠한 포인터형이 반환될지는 입력 값에 따라 달라지기 때문

void free(void * ptr);          // 힙 영역에 할당된 메모리 공간 해제

 

2) 힙 영역의 메모리 공간 할당(위와 인자값 다름)

#include <stdlib.h>

void * calloc(size_t elt_count, size_t elt_size);

 ㄴ 성공시 할당된 메모리의 주소값, 실패시 NULL 반환

 ㄴ 4바이트 크기의 블록(elt_size) 30개(elt_count)를 힙 영역에 할당

 

3) 힙에 할당된 메모리 공간 확장

#include <stdlib.h>

void * realloc(void * ptr, size_t size);

 ㄴ 성공시 새로 할당된 메모리의 주소값, 실패시 NULL 반환

 

** 선행처리는 컴파일 이전의 처리를 의미

   ㄴ 소스 파일.c --[선행처리기]--> 선행처리 거친 소스파일 --[컴파일러]--> 오브젝트 파일 --[링커]--> 실행파일.exe

 

** 매크로 함수

1) 장점

- 일반 함수에 비해 실행속도가 빠름

   ㄴ 왜?

        ① 호출된 함수를 위한 스택 메모리 할당

        ② 실행위치의 이동과 매개변수로의 인자 전달

        ③ return 문에 의한 값의 반환

- 자료형에 따라서 별도의 함수를 정의하지 않아도 됨

 

2) 단점

- 정의하기가 까다로움

- 디버깅 어려움

 

3) 사용하기에 적합한 곳

- 작은 크기의 함수

- 호출의 빈도수가 높은 함수

 

   https://jjunsu.tistory.com/40

 

C언어 - 매크로와 선행처리기(preprocessor)

선행처리 선행처리는 컴파일 이전의 처리를 의미한다. 선행처리는 선행처리기에 의해, 컴파일은 컴파일러에 의해, 링크는 링커에 의해 진행이 된다. 컴파일 과정을 거치면 바이너리 데이터로

jjunsu.tistory.com

 

** 전역변수 static, 함수에 static : 다른 파일에서 접근을 못하게 막음

 

** 헤더 파일을 include 하는 두 가지 방법

#include <헤더파일 이름>

    : 표준 헤더파일이 저장되어 있는 디렉터리에서 파일을 찾음

#include "헤더파일 이름"

    : 소스파일이 저장된 디렉터리에서 헤더파일을 찾음(절대경로, 상대경로)

 

** 헤더파일에 넣으면 좋은 것을

①  외부에 선언된 변수에 접근하거나, 외부에 정의된 함수를 호출하기 위한 선언

   (예) extern int num;                    // extern 생략 가능

          extern int GetNum(void);

구조체 정의

 

** 헤더파일을 중복해서 문제가 되지 않지만, 구조체의 정의는 다르다.

   구조체는 컴파일에 도움을 주는 정보가 아닌,

   실행파일의 내용에 직접적인 연관이 있는 정보이기 때문이고,

   이러한 정보는 두 번 이상 중복 불가

   [해결] 조건부 컴파일을 위한 매크로를 사용하면 됨

#ifndef __STDIV2_H__
#define __STDIV2_H__

typedef struct div
{
    int quotient;
    int remainder;
}Div;

#endif

 

** 도전 프로그래밍4

1.

#include <stdio.h>

typedef struct BookInfo
{
    char title[50];
    char author[50];
    int pageCount;
}Book;

void ClearLineFromReadBuffer()
{
    while(getchar() != '\n');
}

int main(void)
{
    Book info[3] = {};

    printf("Enter book information\n");
    for (int i = 0; i < 3; i++)
    {
        // printf("author : ");
        // scanf("%s", info[i].author);
        //
        // printf("book title : ");
        // scanf("%s", info[i].title);
        //
        // printf("book page : ");
        // scanf("%d", &info[i].pageCount);

        printf("author : ");
        gets(info[i].author);

        printf("book title : ");
        gets(info[i].title);

        // printf("book page : ");
        // scanf("%d%*c", &info[i].pageCount);

        printf("book page : ");
        scanf("%d", &info[i].pageCount);
        
        ClearLineFromReadBuffer();
    }

    printf("\nBook information output\n");
    for (int i = 0; i < 3; i++) 
    {
        printf("author : %s\n", info[i].author);
        printf("book title : %s\n", info[i].title);
        printf("book page : %d\n", info[i].pageCount);
    }
    return 0;
}

 

   https://cokk.tistory.com/42

 

C프로그래밍_gets와 scanf 사용시 주의점

공백문자를 포함한 문자열을 받기 위해 주로 사용하는 gets함수gets 함수를 사용할때 scanf를 함께 사용하는 경우 주의할 점이 있다. gets함수는 (1) 입력버퍼가 차있는 경우 첫번째 글자를 출력(2) 입

cokk.tistory.com

 

 

2.

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

typedef struct BookInfo
{
    char title[50];
    char author[50];
    int pageCount;
}Book;

int main(void)
{
    int repetNum;
    printf("How many book information would you like to enter? ");
    scanf("%d%*c", &repetNum);

    Book* data[repetNum] = {};

    printf("\n\nEnter book information\n");
    for (int i = 0; i < repetNum; i++) 
    {
        data[i] = (Book*)malloc(sizeof(Book)) ;
        if (data[i] == NULL) 
        {
            printf("Out of memory");
            return -1;
        }

        printf("author : ");
        gets(data[i]->author);

        printf("book title : ");
        gets(data[i]->title);

        printf("book page : ");
        scanf("%d%*c", &data[i]->pageCount);
    }

    printf("\n\nBook information output\n");
    for (int i = 0; i < repetNum; i++)
    {
        printf("author : %s\n", data[i]->author);
        printf("book title : %s\n", data[i]->title);
        printf("book page : %d\n", data[i]->pageCount);
        free(data[i]);
    }

    return 0;
}

 

 

3.

** 복소수의 곱셈공식(i는 허수)

   (a+bi) + (c+di)

   = ac + adi + bci + bd => [i²은 -1]

   = ac + adi + bci - bd

   = ac - bd + adi + bci

#include <stdio.h>

typedef struct ComplexNum
{
    float realNum;
    float imaginaryNum;
}ComplexNum;

ComplexNum Sum(const ComplexNum* targetNum)
{
    ComplexNum result = {};
    result.realNum = targetNum[0].realNum + targetNum[1].realNum;
    result.imaginaryNum = targetNum->imaginaryNum + (targetNum + 1)->imaginaryNum;
    return result;
}

ComplexNum Multiple(const ComplexNum* targetNum) 
{
    ComplexNum result = {};
    result.realNum =
        (targetNum[0].realNum * targetNum[1].realNum) -
            (targetNum->imaginaryNum * (targetNum + 1)->imaginaryNum);
    result.imaginaryNum =
        (targetNum[0].realNum *  (targetNum + 1)->imaginaryNum) +
            (targetNum->imaginaryNum * targetNum[1].realNum);
    return result;
}

int main(void)
{
    ComplexNum num[2];
    ComplexNum result[2];

    for (int i = 0; i < 2; i++) 
    {
        printf("Input of complex numbers%d[RealNum, ImaginaryNum] : ", i + 1);
        scanf("%f %f", &num[i].realNum, &num[i].imaginaryNum);
    }

    result[0] = Sum(num);
    result[1] = Multiple(num);

    printf("\n\n[The result of the sum] real : %f, imaginary : %f\n", result[0].realNum, result[0].imaginaryNum);
    printf("[The result of the multiple] real : %f, imaginary : %f\n", result[1].realNum, result[1].imaginaryNum);

    return 0;
}

 

 

4.

1) 처음 내 생각대로 풀어봄

#include <stdio.h>

int main(void)
{
    FILE* file = fopen("text.txt", "rt");

    if (file == NULL)
    {
        printf("File not found");
        return -1;
    }

    char c;
    int flag = 1;
    int aCnt = 0;
    int pCnt = 0;

    while((c = fgetc(file)) != EOF)
    {
        if (flag) {
            flag = 0;

            if (c == 'A' || c == 'a')
                aCnt += 1;
            else if (c == 'P' || c == 'p')
                pCnt += 1;

            continue;
        }

        if (c == '\n' || c == '\t' || c == ' ')
            flag = 1;
    }

    printf("The number of words beginning with A : %d\n"
           "The number of words beginning with P : %d\n", aCnt, pCnt);
    fclose(file);
    return 0;
}

 

2) 가이드 및 다른 사람 풀이 참고, fscanf 사용

   #include <stdio.h>

   int scanf(const char * format, ... );

   int fscanf(FILE * fp, const char * format, ... );

#include <stdio.h>

int main(void)
{
    FILE* file = fopen("text.txt", "rt");

    if (file == NULL)
    {
        printf("File not found");
        return -1;
    }

    char word[100];
    int aCnt = 0;
    int pCnt = 0;

    while(fscanf(file, "%s", word) != EOF)
    {
        const char c = word[0];
        if (c == 'A' || c == 'a')
            aCnt += 1;
        else if (c == 'P' || c == 'p')
            pCnt += 1;
    }

    printf("The number of words beginning with A : %d\n"
           "The number of words beginning with P : %d\n", aCnt, pCnt);
    fclose(file);
    return 0;
}

 

 

#include <stdio.h>

int main(int argc, char * argv[])
{
    FILE* file = fopen(argv[1], "rt");

    if (file == NULL)
    {
        printf("File not found");
        return -1;
    }

    char word[100];
    int aCnt = 0;
    int pCnt = 0;

    while(fscanf(file, "%s", word) != EOF)
    {
        const char c = word[0];
        if (c == 'A' || c == 'a')
            aCnt += 1;
        else if (c == 'P' || c == 'p')
            pCnt += 1;
    }

    printf("The number of words beginning with A : %d\n"
           "The number of words beginning with P : %d\n", aCnt, pCnt);
    fclose(file);
    return 0;
}

 

 

   https://blog.naver.com/regular4950/221453013326

 

[C 언어] main()과 return 사용이유, 설명

안녕하세요 최개향입니다. 오늘 배울 내용은 main, return PART 1 입니다. 안녕하세요. 오늘 배울 내용...

blog.naver.com

 

    https://eastc.tistory.com/entry/C-LINUX-scanf3-fscanf3-sscanf3

 

C / LINUX scanf(3) fscanf(3) sscanf(3)

함수 기능 데이터를 foramt에서 지시하는 대로 서식화 변환하여 입력 받는 라이브러리 함수 fscanf fp가 가리키는 파일에 입력 sscanf 파일이 아닌 인자 buf가 가리키는 문자 배열에서 읽음 함수 원형 #

eastc.tistory.com

 

 

5.

#include <stdio.h>

int main(int argc, char * argv[])
{
    FILE* targetFile1 = fopen(argv[1], "rt");
    FILE* targetFile2 = fopen(argv[2], "rt");

    if (targetFile1 == NULL || targetFile2 == NULL)
    {
        printf("File not found");
        return -1;
    }

    while(1)
    {
        const char c1 = fgetc(targetFile1);
        const char c2 = fgetc(targetFile2);

        if (c1 != c2)
            break;

        if (c1 == EOF && c2 == EOF)
        {
            printf("O : The two files are completely identical");
            fclose(targetFile1);
            fclose(targetFile2);
            return 0;
        }

        if (c1 == EOF || c2 == EOF)
            break;
    }

    printf("X : The two files are different");
    fclose(targetFile1);
    fclose(targetFile2);
    return 0;
}

 

 

 

6.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// typedef enum Menu 
// {
//     Insert = 1,
//     Delete = 2,
//     Search = 3,
//     PruintAll = 4,
//     Exit = 5
// }Menu;

typedef enum Menu 
{
    Insert = 1,
    Delete,
    Search,
    PruintAll,
    Exit
}Menu;

typedef struct PhoneNumInfo 
{
    char name[100];
    char phoneNum[15];
    struct PhoneNumInfo* next;
}PhoneNumInfo;

int main(void)
{
    PhoneNumInfo* phoneList = NULL;

    int flag = 1;
    while (flag) 
    {
        const Menu chooseNum;
        printf("***** MENU *****\n"
               "1. Insert\n2. Delete\n3. Search\n4. Print All\n5. Exit\n"
               "Choose thie item : ");
        scanf("%d", &chooseNum);

        switch (chooseNum) 
        {
            case Insert:
            {
                printf("\n\n[ INSERT ]\n");
                PhoneNumInfo* info = (PhoneNumInfo*)malloc(sizeof(PhoneNumInfo));
                if (info == NULL) 
                {
                    break;
                }

                printf("Input Name : ");
                scanf("%s", info->name);

                printf("Input PhoneNum : ");
                scanf("%s", info->phoneNum);

                info->next = NULL;

                PhoneNumInfo** head = &phoneList;

                if (*head == NULL)
                {
                    *head = info;
                    printf("\n\n");
                    break;
                }

                PhoneNumInfo* tailNode = *head;
                while (tailNode->next != NULL)
                {
                    tailNode = tailNode->next;
                }
                tailNode->next = info;
                printf("\n\n");
                break;
            }
            case Delete:
            {
                PhoneNumInfo** head = &phoneList;

                if (*head == NULL)
                {
                    printf("No Data\n");
                    break;
                }

                char name[100];

                printf("\n\n[ DELETE ]\n"
                       "Please enter your name : ");
                scanf("%s", name);

                PhoneNumInfo* prevNode = phoneList;
                PhoneNumInfo* targetNode = phoneList;
                while (targetNode != NULL)
                {
                    if (strcmp(name, targetNode->name) == 0) 
                    {
                        if (prevNode == targetNode) 
                        {
                            if (targetNode->next == NULL)
                            {
                                *head = NULL;
                                free(targetNode);
                                printf("\n\n");
                                break;
                            }
                            *head = targetNode->next;
                            free(targetNode);
                            printf("\n\n");
                            break;
                        }
                        prevNode->next = targetNode->next;
                        free(targetNode);
                        printf("\n\n");
                        break;
                    }
                    prevNode = targetNode;
                    targetNode = targetNode->next;
                }
                printf("\n\n");
                break;
            }
            case Search: {
                char name[100];

                printf("\n\n[ SEARCH ]\n"
                       "Please enter your name : ");
                scanf("%s", name);

                int isNotSearch = 1;
                PhoneNumInfo* targetNode = phoneList;
                while (targetNode != NULL)
                {
                    if (strcmp(name, targetNode->name) == 0) 
                    {
                        isNotSearch = 0;
                        printf("Name : %s\tTel : %s\n", targetNode->name, targetNode->phoneNum);
                        break;
                    }
                    targetNode = targetNode->next;
                }

                if (isNotSearch) 
                {
                    printf("No Data");
                }

                printf("\n\n");
                break;
            }
            case PruintAll:
            {
                printf("\n\n[ PRINT ALL ]\n");
                if (phoneList == NULL) 
                {
                    printf("No Data\n\n");
                    break;
                }

                PhoneNumInfo* targetNode = phoneList;
                while (targetNode != NULL)
                {
                    printf("Name : %s\tTel : %s\n", targetNode->name, targetNode->phoneNum);
                    targetNode = targetNode->next;
                }
                printf("\n\n");
                break;
            }
            case Exit:
                printf("[ EXIT ]\n");
                flag = 0;
                break;
           default:
               printf("You entered it incorrectly\n");
               break;
        }
    }

    free(phoneList);
    return 0;
}

 

 

7.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef enum Menu {
    Insert = 1,
    Delete,
    Search,
    PruintAll,
    Exit
}Menu;

typedef struct PhoneNumInfo
{
    char name[100];
    char phoneNum[15];
    struct PhoneNumInfo* next;
}PhoneNumInfo;

int main(void)
{
    PhoneNumInfo* phoneList = NULL;

    // 시작 전 데이터 불러오기
    FILE * readFile = fopen("Phone_Number.txt", "rt");

    char word[115];
    while (fscanf(readFile, "%s", word) != EOF)
    {
        PhoneNumInfo* info = (PhoneNumInfo*)malloc(sizeof(PhoneNumInfo));
        if (info == NULL)
        {
            printf("Out of memory");
            break;
        }

        strcpy(info->name, strtok(word, ","));
        strcpy(info->phoneNum, strtok(NULL, ","));

        PhoneNumInfo** head = &phoneList;

        if (*head == NULL)
            *head = info;
        else 
        {
            PhoneNumInfo* tailNode = *head;
            while (tailNode->next != NULL)
            {
                tailNode = tailNode->next;
            }
            tailNode->next = info;
        }
    }

    fclose(readFile);

    // 프로그램
    int flag = 1;
    while (flag) 
    {
        const Menu chooseNum;
        printf("***** MENU *****\n"
               "1. Insert\n2. Delete\n3. Search\n4. Print All\n5. Exit\n"
               "Choose thie item : ");
        scanf("%d", &chooseNum);

        switch (chooseNum) 
        {
            case Insert:
            {
                printf("\n\n[ INSERT ]\n");
                PhoneNumInfo* info = (PhoneNumInfo*)malloc(sizeof(PhoneNumInfo));
                if (info == NULL) {
                    printf("Out of memory");
                    break;
                }

                printf("Input Name : ");
                scanf("%s", info->name);

                printf("Input PhoneNum : ");
                scanf("%s", info->phoneNum);

                info->next = NULL;

                PhoneNumInfo** head = &phoneList;

                if (*head == NULL)
                {
                    *head = info;
                    printf("\n\n");
                    break;
                }

                PhoneNumInfo* tailNode = *head;
                while (tailNode->next != NULL)
                {
                    tailNode = tailNode->next;
                }
                tailNode->next = info;
                printf("\n\n");
                break;
            }
            case Delete:
            {
                PhoneNumInfo** head = &phoneList;

                if (*head == NULL)
                {
                    printf("No Data\n");
                    break;
                }

                char name[100];

                printf("\n\n[ DELETE ]\n"
                       "Please enter your name : ");
                scanf("%s", name);

                PhoneNumInfo* prevNode = phoneList;
                PhoneNumInfo* targetNode = phoneList;
                while (targetNode != NULL)
                {
                    if (strcmp(name, targetNode->name) == 0) 
                    {
                        if (prevNode == targetNode) 
                        {
                            if (targetNode->next == NULL)
                            {
                                *head = NULL;
                                free(targetNode);
                                printf("\n\n");
                                break;
                            }
                            *head = targetNode->next;
                            free(targetNode);
                            printf("\n\n");
                            break;
                        }
                        prevNode->next = targetNode->next;
                        free(targetNode);
                        printf("\n\n");
                        break;
                    }
                    prevNode = targetNode;
                    targetNode = targetNode->next;
                }
                printf("\n\n");
                break;
            }
            case Search: 
            {
                char name[100];

                printf("\n\n[ SEARCH ]\n"
                       "Please enter your name : ");
                scanf("%s", name);

                int isNotSearch = 1;
                PhoneNumInfo* targetNode = phoneList;
                while (targetNode != NULL)
                {
                    if (strcmp(name, targetNode->name) == 0)
                    {
                        isNotSearch = 0;
                        printf("Name : %s\tTel : %s\n", targetNode->name, targetNode->phoneNum);
                        break;
                    }
                    targetNode = targetNode->next;
                }

                if (isNotSearch) 
                {
                    printf("No Data");
                }

                printf("\n\n");
                break;
            }
            case PruintAll:
            {
                printf("\n\n[ PRINT ALL ]\n");
                if (phoneList == NULL)
                {
                    printf("No Data\n\n");
                    break;
                }

                PhoneNumInfo* targetNode = phoneList;
                while (targetNode != NULL)
                {
                    printf("Name : %s\tTel : %s\n", targetNode->name, targetNode->phoneNum);
                    targetNode = targetNode->next;
                }
                printf("\n\n");
                break;
            }
            case Exit:
                printf("[ EXIT ]\n");
                flag = 0;
                break;
           default:
               printf("You entered it incorrectly\n");
               break;
        }
    }

    // 종료 전 파일 남기기
    FILE * writeFile = fopen("Phone_Number.txt", "wt");

    if (phoneList != NULL)
    {
        PhoneNumInfo* targetNode = phoneList;
        while (targetNode != NULL)
        {
            char line[115];

            strcpy(line, targetNode->name);
            strcat(line, ",");
            strcat(line, targetNode->phoneNum);
            strcat(line, "\n");

            fputs(line, writeFile);
            targetNode = targetNode->next;
        }
    }

    fclose(writeFile);

    free(phoneList);
    return 0;
}

 

 

** 해당 글은 윤성우의 열혈 C프로그래밍 도서를 읽고 정리한 글입니다.

  https://product.kyobobook.co.kr/detail/S000001589148

 

윤성우의 열혈 C 프로그래밍 | 윤성우 - 교보문고

윤성우의 열혈 C 프로그래밍 | 윤성우 열형강의『C 프로그래밍』은 C언어에 대한 기본을 배울 수 있는 개론서이다. 이 책은 총 4개의 파트로 구성이 되어 있다. C언어의 기본이 되는 내용들을 다

product.kyobobook.co.kr