C

[C] C언어 300제 - 중급(2)

JIN-JJS 2025. 6. 24. 02:27

096. 메모리 할당하기 (malloc)

더보기

• 소스

#include <stdio.h>
#include <string.h>
#include <stdlib.h> 
//#include <malloc.h> // stdlib.h에 malloc() 함수가 정의 되어 있고 macOS에선 malloc.h는 컴파일 에러가 남

#define MEMORY "MEMORY"

int main() 
{
    char *pmem;

    pmem = malloc(100);

    if(pmem == NULL)
    {
        puts("메모리를 할당할 수 없습니다.");
    }
    else
    {
        strcpy(pmem,MEMORY);
        puts(pmem);

        free(pmem);
    }
}

 

• 설명

malloc() 함수는 동적으로 할당하고자 하는 메모리의 크기를 지정 후 메모리를 할당한다.

만약 시스템 자원이 부족하여 메모리를 할당할 수 없는 경우라면 NULL이 반환되며, 할당된 경우 할당된 메모리 번지를 가리키는 번지의 값이 반환된다.

 

• 결과 화면

 

097. 메모리를 블록 단위로 할당하기 (calloc)

더보기

• 소스

#include <stdio.h>
#include <stdlib.h> 
//#include <malloc.h> // stdlib.h에 malloc() 함수가 정의 되어 있고 macOS에선 malloc.h는 컴파일 에러가 남

int main() 
{
    char *pmem;

    printf("sizeof(int)의 길이는 %d입니다.\n",sizeof(int));

    pmem = calloc(100,sizeof(int));

    if(pmem == NULL)
    {
        puts("메모리를 할당할 수 없습니다.");
    }
    else
    {
        puts("정수형 변수 100개를 저장할 버퍼가 할당되었습니다.");

        free(pmem);
    }
}

 

• 설명

sizeof 연산자는 해당 데이터형의 크기를 구해준다.

 

calloc() 함수는 동적으로 할당할 블록의 수와 블록의 크기를 지정하여 num*size 만큼의 메모리를 할당할 수 있다.

 

• 결과 화면

 

098. 메모리 해제하기 (free)

더보기

• 소스

#include <stdio.h>
#include <stdlib.h> 
//#include <malloc.h> // stdlib.h에 malloc() 함수가 정의 되어 있고 macOS에선 malloc.h는 컴파일 에러가 남

#define MEGA 1024*1024

int main() 
{
    int i;
    char *pmem;

    for(i=0; i<10; i++)
    {
        pmem = malloc(MEGA);

        if(pmem==NULL)
        {
            puts("메모리를 할당할 수 없습니다.");
        }
        else
        {
            puts("메모리를 1MB 할당하였습니다.");

            free(pmem);

            puts("메모리를 해제하였습니다.");
        }
    }
}

 

• 설명

free() 함수는 malloc() 함수 또는 calloc() 함수에서 반환된 포인터의 값을 넣어 메모리를 해제한다.

메모리를 동적으로 할당하여 사용을 한 후, 모든 할당된 메모리는 해제되어야 한다.

 

• 결과 화면

 

099. 메모리 재할당하기 (realloc)

더보기

• 소스

int main() 
{
    char *pmem;
    size_t size = 100;      // _msize() 함수는 macOS에서는 지원하지 않아 직접 크기를 기억하는 변수를 만들어 추적해야함

    pmem = malloc(size);     //pmem = malloc(100);


    if(pmem == NULL)
    {
        puts("메모리를 할당할 수 없습니다.");
    }
    else
    {
        printf("할당된 메모리 길이는 %zu바이트입니다.\n",size);  // printf("할당된 메모리 길이는 %d바이트입니다.\n",_msize(pmem));

        size = 200;     // X
        pmem = realloc(pmem,size);   // pmem = realloc(pmem,200);

            if(pmem == NULL)
            {
                puts("메모리를 재할당할 수 없습니다.");
            }
            else
            {
                printf("재할당된 메모리 길이는 %zu바이트입니다.\n",size);    // printf("재할당된 메모리 길이는 %d바이트입니다.\n",_msize(pmem));
            }
        free(pmem);
    }
}

 

• 설명

* 교재에 있는 _msize() 함수는 macOS에서는 지원하지 않아 직접 크기를 기억하는 변수(size)를 만들어 추적하는 소스로 변경함

 

realloc() 함수는 기존에 malloc() 함수에서 반환된 포인터, 재할당할 메모리의 크기를 받아 메모리를 재할당한다.

 

• 결과 화면

 

100. 메모리 복사하기 (memcpy)

더보기

• 소스

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

struct tagM1
{
    int x;
    int y;
    char buffer[30];
};

int main() 
{
    struct tagM1 x1, x2;

    x1.x = 5;
    x1.y = 10;
    strcpy(x1.buffer, "memory copy");

    memcpy(&x2,&x1,sizeof(x1));

    puts(x2.buffer);
}

 

• 설명

memcpy() 함수는 복사될 버퍼와 복사할 버퍼, 복사할 메모리의 크기를 받아 메모리를 복사한다. 복사하려는 버퍼에 널(0) 값이 있는 경우에도 지정된 길이만큼 모두 복사한다.

 

• 결과 화면

 

101.  메모리 비교하기 (memcmp)

더보기

• 소스

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

int main() 
{
    char s1[100] = "123";
    char s2[200] = "123";

    strcpy(&s1[4],"abc");
    strcpy(&s2[4],"efg");

    if(strcmp(s1,s2)==0)
    {
        puts("strcmp: 버퍼의 값이 일치합니다.");
    }

    if(memcmp(s1,s2,7)==0)
    {
        puts("memcmp: 버퍼의 값이 일치합니다.");
    }
    else
    {
        puts("memcmp: 버퍼의 값이 일치하지 않습니다.");
    }
}

 

• 설명

memcmp() 함수는 비교할 버퍼1, 버퍼2, 비교할 버퍼 크기를 받아 메모리를 비교하는 함수이다.

 

strcmp() 함수는 문자열을 비교하는 함수이고, memcmp() 함수는 메모리를 비교하는 함수이다. memcmp() 함수는 비교하려는 버퍼에 널(0) 값이 있는 경우에도 지정도니 길이만큼 모두 비교한다.

 

• 결과 화면

 

102. 메모리 이동하기 (memmove)

더보기

• 소스

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

char s1[20] = "1234567890";
char s2[20] = "1234567890";

int main() 
{
    puts(s1);
    memcpy(s1+4,s1+2,5);
    puts(s1);

    puts(s2);
    memmove(s2+4,s2+2,5);
    puts(s2);
}

 

• 설명

memmove() 함수는 옮겨질 버퍼, 옮겨질 데이터가 저장된 버퍼, 비교할 버퍼의 크기를 받아 사용하여 메모리 블록(버퍼)을 이동시킨다.

• 결과 화면

 

103. 메모리 채우기 (memset)

더보기

• 소스

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

int main() 
{
    char string[50] = "아름다운 우리나라 대한민국";

    puts(string);

    memset(string,(int)NULL,sizeof(string));

    memset(string,'*',sizeof(string)-1);

    puts(string);
}

 

• 설명

memset() 함수는 초기화될(또는, 특정 문자가 채워질) 버퍼, 초기화할 문자(또는, 특정문자), 몇바이트의 문자를 채우는지에 대한 크기를 받아 문자열 버퍼뿐만 아니라, 구조체, 공용체 등 다른 버퍼의 값을 0으로 초기화할 때 많이 사용된다.

 

• 결과 화면

 

104. 메모리를 복사하는 함수 만들기

더보기

• 소스

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

struct tagM1
{
    int x;
    int y;
    char buffer[30];
};

void* My_memory(void* dst, const void* src, unsigned int count);

int main() 
{
   struct tagM1 x1, x2;
   
   x1.x = 5;
   x1.y = 10;
   strcpy(x1.buffer,"memory copy");

   My_memory(&x2,&x1,sizeof(x1));

   puts(x2.buffer);
}

void* My_memory(void* dst, const void* src, unsigned int count)
{
    void* ret = dst;

    while (count--)
    {
        *(char*)dst = *(char*)src;
        dst = (char*)dst + 1;
        src = (char*)src + 1;
    }
    
    return ret;
}

 

• 설명

memcpy() 함수는 복사될 버퍼와 복사할 버퍼, 복사할 메모리 크기를 받아 메모리를 복사한다. 

내부적인 동작 원리를 이용해 count(복사할 메모리 크기)만큼 복사할 버퍼의 번지에 있는 값을 복사될 버퍼의 번지에 대입을 하면서 while문을 반복 실행하여 동일한 기능이 구현되게 만들 수 있다.

 

• 결과 화면

 

105. 메모리를 이동하는 함수 만들기

더보기

• 소스

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

char s[20] = "1234567890";

void* My_memmove(void* dst, const void* src, unsigned int count);

int main() 
{
    puts(s);
    My_memmove(s+4,s+2,6);
    puts(s);
}

void* My_memmove(void* dst, const void* src, unsigned int count)
{
    void* ret = dst;

    if(dst<=src||(char*)dst>=((char*)src+count))
    {
        while (count--)
        {
            *(char*)dst = *(char*)src;
            dst = (char*)dst + 1;
            src = (char*)src + 1;
        }
    }
    else
    {
        dst = (char*)dst + count - 1;
        src = (char*)src + count - 1;      
        
        while (count--)
        {
            *(char*)dst = *(char*)src;
            dst = (char*)dst - 1;
            src = (char*)src - 1;
        }
    }
    
    return ret;
}

 

• 설명

memmove() 함수는 옮겨질 버퍼, 옮겨질 데이터가 저장된 버퍼, 비교할 버퍼의 크기를 받아 사용하여 메모리 블록(버퍼)을 이동시킨다.

내부적인 동작 원리를 이용해 비교할 버퍼의 크기만큼 옮겨질 데이터가 저장된 버퍼에 옮겨질 버퍼를 이동하면서 while문을 반복 실행하여 동일한 기능이 구현되게 만들 수 있다.

 

• 결과 화면

 

106. 포인터 사용하기

더보기

• 소스

#include <stdio.h>

int main() 
{
    char    *p_char;
    short   *p_short;
    int     *p_int;
    long    *p_long;
    float   *p_float;
    double  *p_double;

    printf("문자형의 크기: %lu 바이트\n",sizeof(char));
    printf("정수형의 크기: %lu 바이트\n",sizeof(short));
    printf("정수형의 크기: %lu 바이트\n",sizeof(int));
    printf("정수형의 크기: %lu 바이트\n",sizeof(long));
    printf("실수형의 크기: %lu 바이트\n",sizeof(float));
    printf("실수형의 크기: %lu 바이트\n",sizeof(double));

    // 32비트 시스템 포인터 크기 4바이트, 64비트 시스템 포인터 크기 8바이트
    printf("문자형 포인터의 크기: %lu 바이트\n",sizeof(p_char));
    printf("정수형 포인터의 크기: %lu 바이트\n",sizeof(p_short));
    printf("정수형 포인터의 크기: %lu 바이트\n",sizeof(p_int));
    printf("정수형 포인터의 크기: %lu 바이트\n",sizeof(p_long));
    printf("실수형 포인터의 크기: %lu 바이트\n",sizeof(p_float));
    printf("실수형 포인터의 크기: %lu 바이트\n",sizeof(p_double));
}

 

• 설명

sizeof문은 각 변수형이 차지하는 메모리의 크기를 구한다.

포인터의 크기는 32비트는 4바이트, 64비트는 8바이트로 시스템 아키텍처에 따라 결정된다.

 

• 결과 화면

 

107. 포인터를 함수에서 사용하기

더보기

• 소스

#include <stdio.h>

void change_x1(int x1);
void change_x2(int *x2);

int main() 
{
    int x;

    x = 5;
    printf("함수를 호출하기 전 x 값: %d\n",x);

    change_x1(x);
    printf("change_x1() 함수를 호출한 후의 x 값: %d\n",x);

    change_x2(&x);
    printf("change_x2() 함수를 호출한 후의 x 값: %d\n",x);    
}

void change_x1(int x1)
{
    x1 = 50;
}

void change_x2(int *x2)
{
    *x2 = 100;
}

 

• 설명

Call-by-value : 함수 호출 시 값을 전달하는 방법 / 값을 받는 매개변수가 함수가 종료되면 사라져버림.

Call-by-reference : 함수 호출 시 주소를 넘기는 방법 / 주소 값을 인자로 넘겨주기 때문에 매개변수에 인자의 주소가 대입됨.

• 결과 화면

 

108. 포인터 배열 사용하기

더보기

• 소스

#include <stdio.h>

int main() 
{
    int x = 0, y = 0;
    int *pxy[2];

    pxy[0] = &x;
    pxy[1] = &y;

    *pxy[0] = 5;
    *pxy[1] = 10;

    printf("x = %d, pxy[0] = %d\n",x,*pxy[0]);
    printf("y = %d, pxy[1] = %d\n",y,*pxy[1]);

    printf("x + y = %d\n",x+y);
    printf("x + y = %d\n",*pxy[0]+*pxy[1]);     
}

 

• 설명

pxy[0] = &x; : x의 분신

pxy[1] = &y; : y의 분신

 

*pxy[0] = 5; : x의 분신인 pxy[0]을 사용해서 x의 값을 5로 설정한다.

*pxy[1] = 10; : x의 분신인 pxy[1]을 사용해서 y의 값을 5로 설정한다.

 

• 결과 화면

 

109. 포인터 배열을 함수에서 사용하기

더보기

• 소스

#include <stdio.h>

void print_pxy(int* pxy[2]);

int main() 
{
    int x = 0, y = 0;
    int *pxy[2];

    pxy[0] = &x;
    pxy[1] = &y;

    *pxy[0] = 5;
    *pxy[1] = 10;

    print_pxy(pxy);
}

void print_pxy(int* pxy[2])
{
    printf("pxy[0] = %d\n",*pxy[0]);
    printf("pxy[1] = %d\n",*pxy[1]);
}

 

• 설명

pxy는 int *pxy[2]라고 정의되어 있기 때문에, print_pxy() 함수의 인수도 int* pxy[2]라고 사용하면 된다.

 

• 결과 화면

 

110. 1차원 배열 사용하기

더보기

• 소스

#include <stdio.h>

int main() 
{
    char one[10] = "Korea";

    puts(one);
    one[2] = 'r';
    puts(one);

    printf("one[0] = %3d, %c \n",one[0],one[0]);
    printf("one[1] = %3d, %c \n",one[1],one[1]);
    printf("one[2] = %3d, %c \n",one[2],one[2]);
    printf("one[3] = %3d, %c \n",one[3],one[3]);
    printf("one[4] = %3d, %c \n",one[4],one[4]);
    printf("one[5] = %3d, %c \n",one[5],one[5]);
}

 

• 설명

one[2] = 'r'; : Korea에서 01234 중 2인 r에 r로 바뀌어서 동일한 Korea로 출력됨

 

printf("one[0] = %3d, %c \n",one[0],one[0]); : %3d에는 아스키 값이, %c에는 해당 문자가 출력된다.ㄴㅌ 

 

• 결과 화면

 

111.  1차원 배열의 포인터 사용하기

더보기

• 소스

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

int main() 
{
    char one[10] = "Korea";
    char *pone;

    pone = one;

    puts(one);          // "Korea"
    puts(pone);         // "Korea"

    strcpy(pone,"Japan");

    puts(one);          // "Japan"
    puts(pone);         // "Japan"  
}

 

• 설명

char *pone; : 문자형 변수의 포인터(분신)를 정의

pone = one; : one을 pone에 대입함으로써 one의 분신이 됨

 

• 결과 화면

 

112. 1차원 배열을 함수에서 사용하기

더보기

• 소스

#include <stdio.h>

void print_one(char *pone);
void print_one2(char one[]);

int main() 
{
    char one[] = "Korea";


    print_one(one);
    print_one2(one);
}

void print_one(char *pone)
{
    puts(pone);
}

void print_one2(char one[])
{
    puts(one);    
}

 

• 설명

1차원 배열을 함수에 전달하기 위해서는 두 가지 방법이 사용된다.

void func(int *x);, void func(int x[]);

 

• 결과 화면

113. 2차원 배열 사용하기

더보기

• 소스

#include <stdio.h>

int main() 
{
    int i;
    int jumsu[100][3];
    int total[3]={0,};

    for(i=0; i<100; i++)
    {
        jumsu[i][0] = 92;   // 국어 점수
        jumsu[i][1] = 90;   // 영어 점수
        jumsu[i][2] = 95;   // 수학 점수
    }

    for(i=0; i<100; i++)
    {
        total[0] += jumsu[i][0];   // 국어 점수
        total[1] += jumsu[i][1];   // 영어 점수
        total[2] += jumsu[i][2];   // 수학 점수
    }

    printf("국어 점수의 총점 : %d \n",total[0]);
    printf("영어 점수의 총점 : %d \n",total[1]);
    printf("수학 점수의 총점 : %d \n",total[2]);
}

 

• 설명

jumsu[i][0] : 100명에 대한 국어 점수

jumsu[i][1] : 100명에 대한 영어 점수

jumsu[i][2] : 100명에 대한 수학 점수

 

total[0] += jumsu[i][0] : 국어 점수의 총합

total[1] += jumsu[i][1] : 영어 점수의 총합

total[2] += jumsu[i][2] : 수학 점수의 총합

 

• 결과 화면

 

114. 2차원 배열의 포인터 사용하기

더보기

• 소스

#include <stdio.h>

int main() 
{
    int i;
    int jumsu[100][3];
    int total[3]={0,};
    int (*pjumsu)[3];

    pjumsu = jumsu;

    for(i=0; i<100; i++)
    {
        pjumsu[i][0] = 92;   // 국어 점수
        pjumsu[i][1] = 90;   // 영어 점수
        pjumsu[i][2] = 95;   // 수학 점수
    }

    for(i=0; i<100; i++)
    {
        total[0] += pjumsu[i][0];   // 국어 점수
        total[1] += pjumsu[i][1];   // 영어 점수
        total[2] += pjumsu[i][2];   // 수학 점수
    }

    printf("국어 점수의 총점 : %d \n",total[0]);
    printf("영어 점수의 총점 : %d \n",total[1]);
    printf("수학 점수의 총점 : %d \n",total[2]);
}

 

• 설명

int (*pjumsu)[3]; : 2차원 배열의 포인터 pjumsu를 정의

pjumsu = jumsu; : 2차원 배열 jumsu의 분신으로 pjumsu를 지정

 

pjumsu[i][0] : 100명에 대한 국어 점수

pjumsu[i][1] : 100명에 대한 영어 점수

pjumsu[i][2] : 100명에 대한 수학 점수

 

total[0] += pjumsu[i][0] : 국어 점수의 총합

total[1] += pjumsu[i][1] : 영어 점수의 총합

total[2] += pjumsu[i][2] : 수학 점수의 총합

• 결과 화면

 

115. 2차원 배열을 함수에서 사용하기

더보기

• 소스

#include <stdio.h>

void calc(int(*pjumsu)[3], int *ptoal);

int main() 
{
    int jumsu[100][3];
    int total[3]={0,};
    int (*pjumsu)[3];

    pjumsu = jumsu;

    calc(pjumsu, total);

    printf("국어 점수의 총점 : %d \n",total[0]);
    printf("영어 점수의 총점 : %d \n",total[1]);
    printf("수학 점수의 총점 : %d \n",total[2]);
}

void calc(int(*pjumsu)[3], int *ptoal)
{

    int i;

    for(i=0; i<100; i++)
    {
        pjumsu[i][0] = 92;   // 국어 점수
        pjumsu[i][1] = 90;   // 영어 점수
        pjumsu[i][2] = 95;   // 수학 점수
    }

    for(i=0; i<100; i++)
    {
        ptoal[0] += pjumsu[i][0];   // 국어 점수
        ptoal[1] += pjumsu[i][1];   // 영어 점수
        ptoal[2] += pjumsu[i][2];   // 수학 점수
    }
}

 

• 설명

calc() 함수를 정의 후 포인터 변수 pjumsu와 ptotal을 인자로 사용한다.

2차원 배열 변수 jumsu의 분신인 pjumsu를 사용해서 100명의 학생에 대한 국어, 영어, 수학 점수를 대입한다.

pjumsu를 사용하여 각 과목의 총점을 구한 후 ptotal에 대입한다.

 

• 결과 화면

 

116. 3차원 배열 사용하기

더보기

• 소스

#include <stdio.h>

int main() 
{
    int i, j;
    int jumsu[10][100][3];
    int total[3]={0,};

    for(i=0; i<10; i++)            // 10개 반
    {
        for(j=0; j<100; j++)       // 100명
        {
            jumsu[i][j][0] = 92;   // 국어 점수
            jumsu[i][j][1] = 90;   // 영어 점수
            jumsu[i][j][2] = 95;   // 수학 점수
        }
    }
    for(i=0; i<10; i++)
    {
        for(j=0; j<100; j++)
        {
        total[0] += jumsu[i][j][0];   // 국어 총합
        total[1] += jumsu[i][j][1];   // 영어 총합
        total[2] += jumsu[i][j][2];   // 수학 총합
        }
    }

    printf("모든 반의 국어 점수의 총점 : %d \n",total[0]);
    printf("모든 반의 영어 점수의 총점 : %d \n",total[1]);
    printf("모든 반의 수학 점수의 총점 : %d \n",total[2]);
}

 

• 설명

jumsu[i][j][0] : 각반의 100명에 대한 국어 점수

jumsu[i][j][1] : 각반의 100명에 대한 영어 점수

jumsu[i][j][2] : 각반의 100명에 대한 수학 점수

 

total[0] += jumsu[i][j][0] : 모든 반의 국어 점수의 총합

total[1] += jumsu[i][j][1] : 모든 반의 영어 점수의 총합

total[2] += jumsu[i][j][2] : 모든 반의 수학 점수의 총합

 

• 결과 화면

 

117. 3차원 배열의 포인터 사용하기

더보기

• 소스

#include <stdio.h>

int main() 
{
    int i, j;
    int jumsu[10][100][3];
    int total[3]={0,};
    int (*pjumsu)[100][3];

    pjumsu = jumsu;

    for(i=0; i<10; i++)            // 10개 반
    {
        for(j=0; j<100; j++)       // 100명
        {
            pjumsu[i][j][0] = 92;   // 국어 점수
            pjumsu[i][j][1] = 90;   // 영어 점수
            pjumsu[i][j][2] = 95;   // 수학 점수
        }
    }
    for(i=0; i<10; i++)
    {
        for(j=0; j<100; j++)
        {
        total[0] += pjumsu[i][j][0];   // 국어 총합
        total[1] += pjumsu[i][j][1];   // 영어 총합
        total[2] += pjumsu[i][j][2];   // 수학 총합
        }
    }

    printf("모든 반의 국어 점수의 총점 : %d \n",total[0]);
    printf("모든 반의 영어 점수의 총점 : %d \n",total[1]);
    printf("모든 반의 수학 점수의 총점 : %d \n",total[2]);
}

 

• 설명

int (*pjumsu)[100][3]; : 3차원 배열의 포인터 pjumsu를 정의

pjumsu = jumsu; : 3차원 배열 jumsu의 분신으로 pjumsu를 지정

 

pjumsu[i][j][0] : 각반의 100명에 대한 국어 점수

pjumsu[i][j][1] : 각반의 100명에 대한 영어 점수

pjumsu[i][j][2] : 각반의 100명에 대한 수학 점수

 

total[0] += pjumsu[i][j][0] : 모든 반의 국어 점수의 총합

total[1] += pjumsu[i][j][1] : 모든 반의 영어 점수의 총합

total[2] += pjumsu[i][j][2] : 모든 반의 수학 점수의 총합

 

• 결과 화면

 

118. 3차원 배열을 함수에서 사용하기

더보기

• 소스

#include <stdio.h>

void calc(int(*pjumsu)[100][3], int *ptotal);

int main() 
{
    int jumsu[10][100][3];
    int total[3]={0,};

    calc(jumsu, total);

    printf("모든 반의 국어 점수의 총점 : %d \n",total[0]);
    printf("모든 반의 영어 점수의 총점 : %d \n",total[1]);
    printf("모든 반의 수학 점수의 총점 : %d \n",total[2]);
}

void calc(int(*pjumsu)[100][3], int *ptotal)
{

    int i, j;

    for(i=0; i<10; i++)
    {
        for(j=0; j<100; j++)
        {
            pjumsu[i][j][0] = 92;   // 국어 점수
            pjumsu[i][j][1] = 90;   // 영어 점수
            pjumsu[i][j][2] = 95;   // 수학 점수
        }
    }

    for(i=0; i<10; i++)
    {
        for(j=0; j<100; j++)
        {
            ptotal[0] += pjumsu[i][j][0];   // 국어 점수
            ptotal[1] += pjumsu[i][j][1];   // 영어 점수
            ptotal[2] += pjumsu[i][j][2];   // 수학 점수
        }
    }
}

 

• 설명

calc() 함수를 정의 후 포인터 변수 pjumsu와 ptotal을 인자로 사용한다.

3차원 배열 변수 jumsu의 분신인 pjumsu를 사용해서 10개 반, 100명의 학생에 대한 국어, 영어, 수학 점수를 대입한다.

pjumsu를 사용하여 각 과목의 총점을 구한 후 ptotal에 대입한다.

 

• 결과 화면

 

119. 구조체 사용하기

더보기

• 소스

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

struct tagAddress
{
    char name[30];          // 이름
    char phone[20];         // 전화
    char address[100];      // 주소
}; // 중괄호(}) 뒤의 세미콜론을 절대로 빠뜨리지 마세요...

int main() 
{
    struct tagAddress ad;

    strcpy(ad.name,"홍길동");
    strcpy(ad.phone,"02-1234-5678");
    strcpy(ad.address,"서울시 성북구 월곡동 18단지");

    printf("이름 : %s \n",ad.name);
    printf("전화 : %s \n",ad.phone);
    printf("주소 : %s \n",ad.address);
}

 

• 설명

struct tagAddress {...}; : 구조체 struct tagAddress를 선언

struct tagAddress ad; : 구조체 struct tagAddress에 대한 변수 ad를 정의

ad.name : 구조체 ad의 name

ad.phone : 구조체 ad의 phone

ad.address : 구조체 ad의 address

• 결과 화면

 

120. 구조체 포인터 사용하기

더보기

• 소스

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

struct tagAddress
{
    char name[30];          // 이름
    char phone[20];         // 전화
    char address[100];      // 주소
};

int main() 
{
    struct tagAddress ad;
    struct tagAddress *pad;
    
    pad = &ad;

    strcpy((*pad).name,"홍길동");
    strcpy((*pad).phone,"02-1234-5678");
    strcpy((*pad).address,"서울시 성북구 월곡동 18단지");

    printf("이름 : %s \n",pad->name);     // (*pad).name) = pad->name
    printf("전화 : %s \n",pad->phone);    // (*pad).phone) = pad->phone
    printf("주소 : %s \n",pad->address);  // (*pad).address) = pad->address
}

 

• 설명

struct tagAddress {...}; : 구조체 struct tagAddress를 선언

struct tagAddress ad; : 구조체 struct tagAddress에 대한 변수 ad를 정의

struct tagAddress *pad; : 구조체 struct tagAddress에 대한 포인터 변수 pad를 정의

 

psd = &ad; : ad의 분신으로 pad를 지정함

 

(*pad).name : psd를 사용한 구조체 ad의 name

(*pad).phone : psd를 사용한 구조체 ad의 phone

(*pad).address : psd를 사용한 구조체 ad의 address

 

• 결과 화면

 

121.  구조체를 함수에서 사용하기

더보기

• 소스

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

struct tagAddress
{
    char name[30];          // 이름
    char phone[20];         // 전화
    char address[100];      // 주소
};

void print(struct tagAddress *pad);

int main() 
{
    struct tagAddress ad;

    strcpy(ad.name,"홍길동");
    strcpy(ad.phone,"02-1234-5678");
    strcpy(ad.address,"서울시 성북구 월곡동 18단지");

    print(&ad);
}

void print(struct tagAddress *pad)
{
    printf("이름 : %s \n",pad->name);   
    printf("전화 : %s \n",pad->phone); 
    printf("주소 : %s \n",pad->address); 
}

 

• 설명

배열은 배열명이 배열을 대표하는 상수이기 떄문에 번지 지정 연산자(&)를 사용하지 않지만, 구조체는 일반 변수처럼 사용되기 때문에 번지 지정 연산자(&)를 반드시 사용해야 한다.

 

• 결과 화면

 

122. 구조체 배열 사용하기

더보기

• 소스

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

struct tagAddress
{
    char name[30];          // 이름
    char phone[20];         // 전화
    char address[100];      // 주소
};

int main() 
{
    struct tagAddress ad[3];
    int i;

    for(i=0; i<3; i++)
    {
        sprintf(ad[i].name,"홍길동%d",i);
        strcpy(ad[i].phone,"02-1234-5678");
        strcpy(ad[i].address,"서울시 성북구 월곡동 18단지");
    }

    for(i=0; i<3; i++)
    {
        printf("이름 : %s \n",ad[i].name);   
        printf("전화 : %s \n",ad[i].phone); 
        printf("주소 : %s \n",ad[i].address);
    }
}

 

• 설명

구조체 배열은 일반 배열과 사용 방법이 같다.

구조체 배열을 정의하고 사용할 때는 일반 배열을 사용하듯이 하면 되고, 구조체 배열은 또한 1차원 배열뿐만 아니라 2차원, 3차원 구조체 배열을 정의하고 사용할 수 있다.

 

• 결과 화면

 

123. 구조체 배열 포인터 사용하기

더보기

• 소스

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

struct tagAddress
{
    char name[30];          // 이름
    char phone[20];         // 전화
    char address[100];      // 주소
};

int main() 
{
    struct tagAddress ad[3];
    struct tagAddress *pad;    
    int i;

    pad = ad; // 배열 변수이므로 번지 지정 연산자(&)를 사용하지 않는다.

    for(i=0; i<3; i++)
    {
        sprintf(pad[i].name,"홍길동%d",i);
        strcpy(pad[i].phone,"02-1234-5678");
        strcpy(pad[i].address,"서울시 성북구 월곡동 18단지");
    }

    for(i=0; i<3; i++)
    {
        printf("이름 : %s \n",pad[i].name);   
        printf("전화 : %s \n",pad[i].phone); 
        printf("주소 : %s \n",pad[i].address);
    }
}

 

• 설명

pad = ad; : 배열은 배열명이 배열을 대표하는 상수이기 때문에 번지 지정 연산자(&)를 사용하지 않는다.

 

• 결과 화면

 

124. 구조체 배열을 함수에서 사용하기

더보기

• 소스

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

struct tagAddress
{
    char name[30];          // 이름
    char phone[20];         // 전화
    char address[100];      // 주소
};

void print(struct tagAddress *pad);

int main() 
{
    struct tagAddress ad[3];
    int i;

    for(i=0; i<3; i++)
    {
        sprintf(ad[i].name,"홍길동%d",i);
        strcpy(ad[i].phone,"02-1234-5678");
        strcpy(ad[i].address,"서울시 성북구 월곡동 18단지");
    }

    print(ad);
}

void print(struct tagAddress *pad)
{
    int i;

    for(i=0; i<3; i++)
    {
        printf("이름 : %s \n",pad[i].name);   
        printf("전화 : %s \n",pad[i].phone); 
        printf("주소 : %s \n",pad[i].address);
    }
}

 

• 설명

구조체 배열 ad를 구조체 배열 포인터 pad에 전달 후 pad를 사용하여 구조체의 내용을 출력한다.

 

• 결과 화면

 

125. 구조체의 길이를 구하고 초기화 하기

더보기

• 소스

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

struct tagAddress
{
    char name[30];          // 이름
    char phone[20];         // 전화
    char address[100];      // 주소
};

typedef struct tagAddress addr;

int main() 
{
    addr ad;                        // struct tagAddress ad;
    int len;

    len = sizeof(addr);             // sizeof(struct tagAddress)

    printf("구조체 addr의 크기 : %d \n",len);
    
    memset(&ad,0,len);              // memset(&ad,0,sizeof(addr)); 
}

 

• 설명

len = sizeof(addr); : sizeof문을 사용하여 구조체 전체의 길이를 구함

memset(&ad,0,len); : 구조체를 널로 초기화한다. (공백으로 초기화 하려면 0 대신 32)

 

• 결과 화면

 

126. 공용체 사용하기

더보기

• 소스

#include <stdio.h>

typedef union tagVariable
{
    int i;
    double d;
} VA;

int main() 
{
    VA va;

    va.i = 5;

    printf("va.i 공용체의 값 : %d \n",va.i);

    va.d = 3.14;

    printf("va.d 공용체의 값 : %f \n",va.d);
    printf("va.i 공용체의 값 : %d \n",va.i);
}

 

• 설명

공용체 변수는 다른 공용체 멤버 변수의 값이 변할 때 자동으로 변화한다.

 

공용체는 특별한 경우에만 사용된다. 구조체와 선언 및 정의 방법이 같으며, 구조체와 다른 점은 공용체 멤버는 서로 같은 메모리 영역을 공유하고 있다는 것이다. 공용체는 네트워크 프로그램 등에서 자주 사용된다.

 

• 결과 화면

 

127. 공용체를 함수에서 사용하기

더보기

• 소스

#include <stdio.h>

typedef union tagVariable
{
    int i;
    double d;
} VA;

void print(VA *pva);

int main() 
{
    VA va;

    print(&va);
}

void print(VA *pva)
{
    pva->i = 5;

    printf("va.i 공용체의 값 : %d \n",pva->i);

    pva->d = 3.14;

    printf("va.d 공용체의 값 : %f \n",pva->d);
    printf("va.i 공용체의 값 : %d \n",pva->i);
}

 

• 설명

공용체 변수 또한 전달 인수는 포인터형으로 번지 지정 연산자(&)를 반드시 사용해야 한다.

 

• 결과 화면

 

128. void형 포인터 사용하기

더보기

• 소스

#include <stdio.h>

int main() 
{
    int i;
    double d = 3.14;

    int *pi;
    double *pd;
    void *pv;

    pi = &i;
    pd = &d;
    pi = &d;    // warning 에러 발생
    pv = &i;
    pv = &d;

    printf("실수 값 d : %f \n",*(double*)pv);
}

 

• 설명

void형 포인트에 값을 대입하는 경우, 경고 에러는 발생하지 않는다.

단, void형 포인터 값을 출력할 때는 어떤 변수의 분신인지를 명확하게 알려(캐스트)주어야 한다.

 

• 결과 화면

 

129. void형 포인터를 함수에서 사용하기

더보기

• 소스

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

typedef struct tagPoint
{
    int x;
    int y;
} point;

void My_memset(void* dest,int c,unsigned count);

int main() 
{
    point pt = {5,10};
    char array[10];

    printf("x, y : %d, %d \n",pt.x,pt.y);

    My_memset(&pt,0,sizeof(pt));

    printf("x, y : %d, %d \n",pt.x,pt.y);

    My_memset(array,48,sizeof(array));

    printf("array[0] ~ array[9] : %c ~ %c \n",array[0],array[9]);
}

void My_memset(void* dest,int c,unsigned count)
{
    while (count--)
    {
        *(char*)dest = c;
        dest = (char*)dest + 1;
    }
}

 

• 설명

void My_memset(void* dest, int c, unsigned count); : void형 포인터는 모든 종류의 포인터형을 전달받을 수 있다.

 

• 결과 화면

 

130. 포인터의 포인터 사용하기

더보기

• 소스

#include <stdio.h>

int main() 
{
    char *animal[3];
    char **ppanimal;

    animal[0] = "호랑이";
    animal[1] = "사자";
    animal[2] = "토끼";

    ppanimal = animal;

    puts(animal[0]);
    puts(ppanimal[1]);
    puts(ppanimal[2]);
}

 

• 설명

포인터 배열을 함수에 전달하기 위해 사용하는 것이 포인터의 포인터이다.

포인터의 포인터는 별이 두 개(**)이다.

 

• 결과 화면

131.  포인터의 포인터를 함수에서 사용하기

더보기

• 소스

#include <stdio.h>

void print(char **ppanimal);

int main() 
{
    char *animal[3];

    animal[0] = "호랑이";
    animal[1] = "사자";
    animal[2] = "토끼";

    print(animal);
}

void print(char **ppanimal)
{
    puts(ppanimal[0]);
    puts(ppanimal[1]);
    puts(ppanimal[2]);
}

 

• 설명

포인터 배열을 함수로 전달하기 위해서 포인터의 포인터가 사용된다.

 

• 결과 화면

 

132. 함수 포인터 사용하기

더보기

• 소스

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

int main() 
{
    int (*puts_func)(const char *);
    size_t (*strlen_func)(const char *);

    puts_func = puts;
    strlen_func = strlen;

    puts("올챙이의");
    puts_func("뒷다리는 맛있나요?");

    printf("문자열의 길이 : %zu \n", strlen("aa"));
    printf("문자열의 길이 : %zu \n", strlen_func("aa"));
}

 

• 설명

모든 함수 포인터는 함수 원형에서 함수명만 (*바꿀 함수명)처럼 바꾸면 된다.

 

• 결과 화면

 

133. 함수 포인터를 배열에서 사용하기

더보기

• 소스

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

int main() 
{
    int (*puts_func[3])(const char *);
    size_t (*strlen_func[3])(const char *);


    puts_func[0] = puts;
    puts_func[1] = puts;
    puts_func[2] = puts_func[1];

    strlen_func[0] = strlen;
    strlen_func[1] = strlen;
    strlen_func[2] = strlen_func[1];    

    puts("올챙이의");
    puts_func[2]("뒷다리는 맛있나요?");

    printf("문자열의 길이 : %zu \n", strlen("aa"));
    printf("문자열의 길이 : %zu \n", strlen_func[1]("aa"));
    printf("문자열의 길이 : %zu \n", strlen_func[2]("aa"));
}

 

• 설명

함수 포인터 배열은 함수 포인터의 옆에 배열 요소의 수만 표시하면 된다.

 

• 결과 화면



 

134. 함수 포인터를 함수에서 사용하기

더보기

• 소스

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

void print1(int(*X[2])(const char*));
void print2(size_t(*X)(const char*));

int main() 
{
    int (*puts_func[2])(const char *);
    size_t (*strlen_func[2])(const char *);


    puts_func[0] = puts;
    puts_func[1] = puts_func[0];

    strlen_func[0] = strlen;
    strlen_func[1] = strlen_func[0]; 

    print1(puts_func);
    print2(strlen_func[1]);

}

void print1(int(*X[2])(const char*))
{
    X[0]("올챙이의");
    X[1]("뒷다리는 맛있나요?");
}

void print2(size_t(*X)(const char*))
{
    printf("문자열의 길이 : %zu \n", X("aa"));
}

 

• 설명

함수의 인수로 함수 포인터나 포인터 배열을 선언하여 사용이 가능하다.

 

함수에 대한 포인터를 사용하려면 포인터를 선언해야 할 뿐만 아니라, 어떤 것을 가리키도록 초기화해야 한다. 물론, 여기서 "어떤 것"은 함수를 말한다. 포인터가 가리켜야 하는 함수에는 아무런 제한이 없다. 한 가지 주의해야 할 사항이 있다면, 함수의 복귀형과 인수 목록이 포인터를 선언할 때 지정된 반환형이나 인수 목록과 일치해야 한다.

 

• 결과 화면



 

135. main() 함수 원형 사용하기

더보기

• 소스

#include <stdio.h>

int main(int argc, char *argv[]) 
{
    int i;

    printf("인수의 수: %d \n", argc);

    for (i = 0; i < argc; i++)
    {
        printf("argv[%d] : %s \n", i, argv[i]);
    }
}

 

• 설명

argc는 총 전달된 이수의 수이며, argv는 포인터 배열이다.

argv는 특정한 크기가 없으며, 명령행에서 넘어온 값들을 공백으로 분리하여 argv[0], argv[1], argv[2],...argv[argc-1]까지 모든 인수의 값을 출력한다.

 

• 결과 화면

136. 파일 생성하기 (fopen)

더보기

• 소스

#include <stdio.h>

int main()
{
    FILE *file;

    file = fopen("/Users/jeonjoonsu/Desktop/무제 폴더/image.jpeg","w+");

    if(file == NULL)
    {
        puts("파일을 생성할 수 없습니다.");
    }
    else
    {
        puts("파일이 정상적으로 생성되었습니다.");
        fclose(file);
    }
}

 

• 설명

fopen() 함수는 파일의 생성 및 개방(open) 기능을 가지고 있으며, 개방 모드에 따라 생성은 "w+", 읽기 위해서 개방할 때는 "r"등이 사용된다.

 

• 결과 화면

 

137. 파일에 한 문자 쓰기 (fputc)

더보기

• 소스

#include <stdio.h>

int main()
{
    FILE *fp;

    fp = fopen("/Users/jeonjoonsu/Desktop/무제 폴더/file.txt","w+");

    if(fp == NULL)
    {
        puts("파일을 생성할 수 없습니다.");
    }
    else
    {
        fputc('A',fp);
        puts("문자 'A'를 파일에 저장하였습니다.");
        fclose(fp);
    }
}

 

• 설명

fputc() 함수는 쓰여질 문자와 개방된 파일의 포인터를 받아 한 문자를 쓴다.

문자열을 쓰기 위해서는 fputs() 함수를 사용해야한다.

 

• 결과 화면

 

138. 파일에서 한 문자 읽기 (fgetc)

더보기

• 소스

#include <stdio.h>

int main()
{
    FILE *fp;
    int ch;

    fp = fopen("/Users/jeonjoonsu/Desktop/무제 폴더/file.txt","r");

    if(fp == NULL)
    {
        puts("파일을 생성할 수 없습니다.");
    }
    else
    {
        ch = fgetc(fp);
        printf("읽은 문자 : %c \n",ch);
        fclose(fp);
    }
}

 

• 설명

fgetc() 함수는 개방된 파일의 포인터를 받아 개방된 파일에서 문자를 하나 읽는다.

 

• 결과 화면

 

139. 파일에 문자열 쓰기 (fputs)

더보기

• 소스

#include <stdio.h>

int main()
{
    FILE *fp;
    int ch;

    fp = fopen("/Users/jeonjoonsu/Desktop/무제 폴더/file.txt","w+");

    if(fp == NULL)
    {
        puts("파일을 생성할 수 없습니다.");
    }
    else
    {
        fputs("대한민국 \n",fp);
        fclose(fp);
    }
}

 

• 설명

fputs() 함수는 저장할 문자열과 개방된 파일의 포인터를 받아 개방된 파일에 문자열을 저장한다.

 

• 결과 화면

 

140. 파일에서 문자열 읽기 (fgets)

더보기

• 소스

#include <stdio.h>

int main()
{
    FILE *fp;
    char buffer[100];

    fp = fopen("/Users/jeonjoonsu/Desktop/무제 폴더/file.txt","r");

    if(fp == NULL)
    {
        puts("파일을 생성할 수 없습니다.");
    }
    else
    {
        fgets(buffer,100,fp);
        puts(buffer);
        fclose(fp);
    }
}

 

• 설명

fgets() 함수는 문자열이 읽혀질 버퍼와 문자열의 길이, 개방된 파일의 포인터를 받아 개방된 파일의 문자열을 읽는다.

 

• 결과 화면

 

 

141.  파일에 형식화된 문자열 쓰기 (fprintf)

더보기

• 소스

#include <stdio.h>

int main()
{
    FILE *fp;
    int i = 12345;

    fp = fopen("/Users/jeonjoonsu/Desktop/무제 폴더/file.txt","w+");

    if(fp == NULL)
    {
        puts("파일을 생성할 수 없습니다.");
    }
    else
    {
        fprintf(fp,"%d",i);
        fclose(fp);
    }
}

 

• 설명

fprintf() 함수는 printf() 함수와 같은 구조를 가진 형식 문자열이고, 함수의 사용법이 같기 때문에 printf() 함수처럼 사용하면 된다.

 

• 결과 화면

 

142. 파일에서 형식화된 문자열 읽기 (fscanf)

더보기

• 소스

#include <stdio.h>

int main()
{
    FILE *fp;
    int i;

    fp = fopen("/Users/jeonjoonsu/Desktop/무제 폴더/file.txt","r");

    if(fp == NULL)
    {
        puts("파일을 생성할 수 없습니다.");
    }
    else
    {
        fscanf(fp,"%d",&i);
        printf("i = %d \n",i);
        fclose(fp);
    }
}

 

• 설명

fscanf() 함수는 scanf() 함수의 사용법이 같기 때문에 scanf() 함수처럼 사용하면 된다.

 

• 결과 화면

143. 파일의 버퍼 비우기 (fflush)

더보기

• 소스

#include <stdio.h>

int main()
{
    FILE *fp;

    fp = fopen("/Users/jeonjoonsu/Desktop/무제 폴더/file.txt","w+");

    if(fp == NULL)
    {
        puts("파일을 생성할 수 없습니다.");
    }
    else
    {
        fputs("대한민국",fp);
        fflush(fp);
        fclose(fp);
    }
}

 

• 설명

fflush() 함수는 저장할 문자열과 개방된 파일의 포인터를 받아 개방된 파일에 문자열을 저장한다.

 

데이터는 파일에 저장되기 전에 임시 버퍼에 기록이 되는데, 만약 순간적으로 정전 등이 발생한다면 버퍼의 내용이 파일에 기록되지 않는다. 이런 문제점을 방지하기 위해 파일 버퍼를 일정 크기만큼 채우지 않고, 즉시 파일에 저장하기 위해 사용하는 것이 fflush() 함수이다.

 

• 결과 화면



144. 파일 포인터의 현재 위치 구하기1 (ftell)

더보기

• 소스

#include <stdio.h>

int main()
{
    FILE *fp;

    fp = fopen("/Users/jeonjoonsu/Desktop/무제 폴더/file.txt","w+");

    if(fp == NULL)
    {
        puts("파일을 생성할 수 없습니다.");
    }
    else
    {
        printf("파일 포인터의 위치 : %ld \n",ftell(fp));     // 0
        fputs("abcde",fp);
        printf("파일 포인터의 위치 : %ld \n",ftell(fp));     // 5
        fclose(fp);
    }
}

 

• 설명

ftell() 함수는 개방된 파일의 포인터를 받아 파일 포인터의 길이를 구한다.

 

• 결과 화면



 

145. 파일 포인터를 처음으로 이동하기1 (fseek)

더보기

• 소스

#include <stdio.h>

int main()
{
    FILE *fp;
    int i;

    fp = fopen("/Users/jeonjoonsu/Desktop/무제 폴더/file.txt","w+");

    if(fp == NULL)
    {
        puts("파일을 생성할 수 없습니다.");
    }
    else
    {
        printf("파일 포인터의 위치 : %ld \n",ftell(fp));     // 위치 : 0
        fputs("abcde",fp);
        printf("파일 포인터의 위치 : %ld \n",ftell(fp));     // 위치 : 5
        fseek(fp,0L,SEEK_SET);
        printf("파일 포인터의 위치 : %ld \n",ftell(fp));     // 위치 : 0             
        fclose(fp);
    }
}

 

• 설명

fseek() 함수는 개방된 파일의 포인터와 파일의 이동할 거리, 이동을 시작할 위치를 받아 이동합니다.

 

• 결과 화면

146. 파일 포인터를 처음으로 이동하기2 (rewind)

더보기

• 소스

#include <stdio.h>

int main()
{
    FILE *fp;
    int i;

    fp = fopen("/Users/jeonjoonsu/Desktop/무제 폴더/file.txt","w+");

    if(fp == NULL)
    {
        puts("파일을 생성할 수 없습니다.");
    }
    else
    {
        printf("파일 포인터의 위치 : %ld \n",ftell(fp));     // 위치 : 0
        fputs("abcde",fp);
        printf("파일 포인터의 위치 : %ld \n",ftell(fp));     // 위치 : 5
        rewind(fp);
        printf("파일 포인터의 위치 : %ld \n",ftell(fp));     // 위치 : 0             
        fclose(fp);
    }
}

 

• 설명

rewind() 함수는 개방된 파일의 포인터를 받아 파일 포인터의 위치를 처음을 이동한다.

 

• 결과 화면

 

147. 파일 포인터를 끝으로 이동하기 (fseek)

더보기

• 소스

#include <stdio.h>

int main()
{
    FILE *fp;
    int i;

    fp = fopen("/Users/jeonjoonsu/Desktop/무제 폴더/file.txt","w+");

    if(fp == NULL)
    {
        puts("파일을 생성할 수 없습니다.");
    }
    else
    {
        printf("파일 포인터의 위치 : %ld \n",ftell(fp));     // 위치 : 0
        fputs("abcde",fp);
        printf("파일 포인터의 위치 : %ld \n",ftell(fp));     // 위치 : 5
        rewind(fp);
        printf("파일 포인터의 위치 : %ld \n",ftell(fp));     // 위치 : 0        
        fseek(fp,0L,SEEK_END);
        printf("파일 포인터의 위치 : %ld \n",ftell(fp));     // 위치 : 5        
        fclose(fp);
    }
}

 

• 설명

fseek() 함수는 각각의 시작점에 대하여 양의 방향, 또는 음의 방향으로 움직일  수 있다.

SEEK_SET : 파일의 처음 (0번 위치)

SEEK_CUR : 현재 파일 포인터 위치 기준

SEEK_END : 파일의 끝(EOF) 위치 기준

 

• 결과 화면

 

148. 파일 포인터를 임의의 위치로 이동하기 (fseek)

더보기

• 소스

#include <stdio.h>

int main()
{
    FILE *fp;
    int i;

    fp = fopen("/Users/jeonjoonsu/Desktop/무제 폴더/file.txt","w+");

    if(fp == NULL)
    {
        puts("파일을 생성할 수 없습니다.");
    }
    else
    {
        printf("파일 포인터의 위치 : %ld \n",ftell(fp));     // 위치 : 0
        fputs("abcde",fp);
        printf("파일 포인터의 위치 : %ld \n",ftell(fp));     // 위치 : 5     
        fseek(fp,-2L,SEEK_CUR);
        printf("파일 포인터의 위치 : %ld \n",ftell(fp));     // 위치 : 3        
        fclose(fp);
    }
}

 

• 설명

파일 포인터의 위치를 현재 위치(SEEK_CUR)에서 -2만큼 뒤로 이동한다.

파일 포인터의 값은 뒤로(음의 값) 이동할 수 있으며, 앞으로(양의 값) 이동할 수도 있다.

 

• 결과 화면

 

149. 파일의 길이 구하기 (fseek)

더보기

• 소스

#include <stdio.h>

int main()
{
    FILE *fp;

    fp = fopen("/Users/jeonjoonsu/Desktop/무제 폴더/file.txt","r");

    if(fp == NULL)
    {
        puts("파일을 생성할 수 없습니다.");
    }
    else
    {   
        fseek(fp,0L,SEEK_END);
        printf("파일 길이 : %ld \n",ftell(fp));     // 길이 : 5        
        fclose(fp);
    }
}

 

• 설명

파일의 길이를 구하기 위해서는 fseek() 함수를 사용하여 파일 포인터를 파일의 맨 끝으로 이동 후,

ftell() 함수를 사용하여 현재 파일 포인터의 위치 값을 구하면 된다.

 

• 결과 화면

150. 파일 포인터의 현재 위치 구하기2 (fgetpos)

더보기

• 소스

#include <stdio.h>

int main()
{
    FILE *fp;
    fpos_t pos;

    fp = fopen("/Users/jeonjoonsu/Desktop/무제 폴더/file.txt","w+");

    if(fp == NULL)
    {
        puts("파일을 생성할 수 없습니다.");
    }
    else
    {   
        fputs("abcde",fp);
        fgetpos(fp,&pos);
        printf("파일 포인터의 위치 : %d \n",pos);     // 위치 : 5        
        fclose(fp);
    }
}

 

• 설명

fgetpos() 함수는 개방된 파일 포인터와 fpos_t 구조체 포인터를 받아서, 현재 파일 포인터의 위치를 구해 저장하는 함수입니다.

 

• 결과 화면

 

151.  파일 포인터의 현재 위치 설정하기 (fsetpos)

더보기

• 소스

#include <stdio.h>

int main()
{
    FILE *fp;
    fpos_t pos;

    fp = fopen("/Users/jeonjoonsu/Desktop/무제 폴더/file.txt","w+");

    fgetpos(fp,&pos);           // pos : 0
    fputs("abcde",fp);          // 파일 포인터의 위치 : 5
    fsetpos(fp,&pos);           // 파일 포인터의 위치 : 0   
    printf("파일 포인터의 위치 : %ld \n",ftell(fp));     // 위치 : 0        
    fclose(fp);
}

 

• 설명

fsetpos() 함수는 개방된 파일 포인터와 fgetpos() 함수에서 읽은 값을 받아서, 현재 파일 포인터의 위치를 구해 저장하는 함수입니다.

 

• 결과 화면

 

152. 파일 닫기 (fclose)

더보기

• 소스

#include <stdio.h>

int main()
{
    FILE *fp;

    fp = fopen("/Users/jeonjoonsu/Desktop/무제 폴더/file.txt","w+");

    fputs("fclose() 함수",fp);              
    fclose(fp);
}

 

• 설명

fclose() 함수는 개방된 파일 포인터를 받아 개방한 파일을 닫는다.

 

• 결과 화면

 

153. 파일의 끝에 도달했는지 검사하기 (feof)

더보기

• 소스

#include <stdio.h>

int main()
{
    FILE *fp;
    int ch;

    fp = fopen("/Users/jeonjoonsu/Desktop/무제 폴더/file.txt","r");

    if(fp == NULL)
    {
        puts("파일을 생성할 수 없습니다.");
    }
    else
    {   
        while (!feof(fp))
        {
            ch = fgetc(fp);
            printf("읽은 문자 : %c \n", ch);
        }
        fclose(fp);
    }
}

 

• 설명

feof() 함수는 개방된 파일 포인터를 받아 파일 stream의 마지막에 도달하지 않았다면 0을 돌려주고 파일의 마지막에 도달하면 0이 아닌 값을 돌려준다.

 

• 결과 화면

 

154. 파일 읽기/쓰기 시 에러 검사하기 (ferror)

더보기

• 소스

#include <stdio.h>

int main()
{
    FILE *fp;
    int ch;

    fp = fopen("/Users/jeonjoonsu/Desktop/무제 폴더/file.txt","r");

    if(fp == NULL)
    {
        puts("파일을 생성할 수 없습니다.");
    }
    else
    {   
        while (!feof(fp))
        {
            ch = fgetc(fp);
            if(ferror(fp))
            {
                puts("파일을 읽는 중에 에러가 발생하였습니다.");
            }
            printf("읽은 문자 : %c \n", ch);
        }
        fclose(fp);
    }
}

 

• 설명

ferror() 함수는 개방된 파일 포인터를 받아 파일을 읽거나 쓸 때 에러가 있는 경우 0이 아닌 값을 반환합니다.

 

• 결과 화면

 

155. 파일 처리 시 발생된 에러 표시하기 (perror)

더보기

• 소스

#include <stdio.h>

int main()
{
    FILE *fp;
    int ch;

    fp = fopen("/Users/jeonjoonsu/Desktop/무제 폴더/file.txt","r");

    if(fp == NULL)
    {
        perror("파일 개방 에러");
    }
    else
    {   
        ch = fgetc(fp);
        if(ferror(fp))
        {
            perror("파일 읽기 에러");
        }
        fclose(fp);
    }
}

 

• 설명

perror() 함수는 문자열을 받아 파일 개방이 실패된 주 원인에 대하여 출력 메시지를 보여준다.

 

• 결과 화면

 

156. 임시 파일 이름 만들기 (tmpnam)

더보기

• 소스

// Windows
// #include <stdio.h>

// int main()
// {
//     int i;
//     char buffer[500];
//     char *path;

//     for(i=0; i<10; i++)
//     {
//         tmpnam(buffer);
//         puts(buffer);
//     }

//     for(i=0; i<10; i++)
//     {
//         path = _tempnam("","test");
//         puts(path);
//     }
// }


// macOS
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main() {
    char template[] = "/tmp/testXXXXXX";
    int fd = mkstemp(template); // 실제 파일 생성됨

    if (fd == -1) {
        perror("mkstemp");
        return 1;
    }

    printf("임시 파일 경로: %s\n", template);
    close(fd); // 파일 닫기
    unlink(template); // 임시 파일 삭제
}

 

• 설명

tmpnam() 함수는 임시 파일 이름(파일 경로 문자열)을 생성하여 반환 (실제 파일은 생성되지 않음)

_tempnam() 함수는 임시 파일 이름을 생성해서 힙에 저장 후 포인터를 반환 (실제 파일은 생성되지 않음) Windows 환경 전용

mkstemp() 함수는 임시 파일을 실제로 생성하며, 고유한 파일 이름을 만들어주며 안전하고 다중 프로세서에서도 충돌을 방지한다.

 

• 결과 화면

 

157. 파일이 존재하는지 확인하기 (_access)

더보기

• 소스

#include <stdio.h>
// #include <io.h> window 전용 헤더 파일
#include <unistd.h>  // access() 함수 정의됨

int main()
{
    char *path = "/Users/jeonjoonsu/Desktop/무제 폴더/file.txt";

    if(access(path, F_OK) == 0)
    {
        puts("해당 경로에 파일이 존재합니다.");
    }
    else
    {
        puts("파일이 존재하지 않습니다.");
    }
}

 

• 설명

#include <io.h> : Windows 전용 헤더 파일로, _access() 등 저수준 입출력 함수가 정의되어 있음

_access() : Windows에서 파일 존재 여부나 권한 확인에 사용하는 함수 (io.h에 정의)

 

access() 함수는 POSIX 표준 함수로, 파일 경로와 권한 확인 매크로를 인자로 받아 파일의 존재 여부 및 접근 권한을 확인할 수 있음. 단, TOCTOU(검사-사용 시점 차이) 문제가 발생할 수 있어 보안적으로 완전하지는 않음

 

access()의 권한 확인 매크로

- F_OK : 존재 여부만 확인

- R_OK : 읽기 권한 확인

- W_OK : 쓰기 권한 확인

- X_OK : 실행 권한 확인

 

• 결과 화면

 

158. 파일 이름 변경하기 (rename)

더보기

• 소스

#include <stdio.h>

int main()
{
    char *oldname = "/Users/jeonjoonsu/Desktop/무제 폴더/file.txt";
    char *newname = "/Users/jeonjoonsu/Desktop/무제 폴더/file_1.txt";

    if(rename(oldname, newname) != 0)
    {
        perror("파일명 변경 에러");
    }
    else
    {
        puts("파일명을 성공적으로 변경하였습니다.");
    }
}

 

• 설명

rename() 함수는 원래 파일명과 새로 변경할 파일명을 받아 파일이나 디렉터리의 이름을 변경하거나, 다른 위치로 이동하는 데 사용되는 함수입니다.

 

• 결과 화면

 

159. 파일 속성 변경하기 (_chmod)

더보기

• 소스

// Windows
// #include <stdio.h>
// #include <io.h>
// #include <sys/stat.h>

// int main()
// {
//     char *filename = "/Users/jeonjoonsu/Desktop/무제 폴더/file.txt";

//     if(_chmod(filename, _S_IREAD) != 0)
//     {
//         perror("파일 속성 설정 에러");
//     }
//     else
//     {
//         puts("파일 속성을 성공적으로 설정하였습니다.");
//     }
// }

// macOS
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>

int main()
{
    const char *filename = "/Users/jeonjoonsu/Desktop/무제 폴더/file.txt";

    // 파일을 읽기 전용으로 설정 (owner만 읽기 가능)
    if (chmod(filename, S_IRUSR) != 0)
    {
        perror("파일 속성 설정 에러");
    }
    else
    {
        puts("파일 속성을 성공적으로 설정하였습니다.");
    }
}

 

• 설명

#include <io.h> : Windows 전용 헤더 파일로, _access() 등 저수준 입출력 함수가 정의되어 있음

_chmod() : Windows에서 파일 접근 권한을 설정하는 함수 (io.h에 정의)

 

chmod() 함수는 POSIX 표준 함수로, 파일 경로와 권한 확인 매크로를 인자로 받아 파일 또는 디렉터리의 퍼미션(접근 권한)을 설정

 

chmod() 매크로

- S_IRUSR : 사용자 읽기 권한

 

- S_IWUSR : 사용자 쓰기 권한

- S_IXUSR : 사용자 실행 권한

- S_IRGRP, S_IROTH 등으로 그룹 및 기타 사용자 권한 지정 가능

 

 

• 결과 화면

 

160. 파일 삭제하기 (remove)

더보기

• 소스

#include <stdio.h>

int main()
{
    char *filename = "/Users/jeonjoonsu/Desktop/무제 폴더/file.txt";

    if(remove(filename))
    {
        perror("파일 삭제 에러");
    }
    else
    {
        puts("파일을 성공적으로 삭제하였습니다.");
    }
}

 

• 설명

remove() 함수는 파일 경로를 받아 지정된 경로의 파일을 삭제한다.

파일이 없거나 사용중인 경우 또는 읽기 전용 파일은 삭제할 수 없다.

 

• 결과 화면


이 글은 초보자를 위한 C언어 300제 (김은철 지음, 정보문화사)을 참고하여 작성했습니다.