이 프로젝트의 목적은 파일 디스크립터로부터 읽혀진, newline으로 끝나는 라인을 반환하는 함수를 코드화
테스트 통과 후 이 프로젝트의 목적은 malloc을 원하는 만큼 크기를 사용하고 나서 free 를 잘 해주었는지 확인하는 작업을 하게 된다. static 함수 사용하면서 read 읽은 것을 저장해야 하고, 개행을 만나게 되면 line 에 넣어줘야 하기 때문에 크기의 변화도 있을 것이며, 그 관리를 잘해줘야 하는 프로젝트이다. 어떤 느낌인지 감이 안온다면 목차의 8번째를 읽어보고 서브젝트를 잘 읽어보면 어떻게 read 해야할 지 감이 조금씩 올 것이다. 그래도 안온다면 옆 사람에게 어떻게 코드가 짜여지는지 대략적인 것을 듣고 만들어 보자.
fd(file descriptor) 이 지칭하는 파일에 내용을 BUFFER_SIZE 만큼 읽으면서 static 배열에 저장하다가 line에 반환하는 함수 작정
- fd란 무엇인가
- read 함수
- EOF는 무엇인가
- malloc과 free
- BUFFER_SIZE
- To succeed get_next_line with a single static varivable
- Double Pointer
- main.c / 어떻게 구동이 되는가
1. fd란 무엇인가
fd (file descriptor) : 정한 파일에 접근하기 위한 추상적인 키
표준 입력(Standard Input), 표준 출력(Standard Output), 표준 에러(Standard Error)이다. 이 들에게 각각 0, 1, 2 라는 정수가 할당
프로세스가 실행 중에 파일을 Open 하면 커널은 해당 프로세스의 파일 디스크립터 숫자 중에 사용하지 않는 가장 작은 값을 할당해 준다. 그 다음 프로세스가 열려있는 파일에 시스템 콜을 이용해서 접근 할 때, FD 값을 이용해 파일을 지칭 할 수 있다.
0 ~ OPEN_MAX(fd의 최대값) 까지의 값을 가질 수 있다. OPEN_MAX는 단일 프로그램에 허용되는 최대 열린 파일 수를 정의하는 상수이다. 값은 getconf OPEN_MAX를 통해서 구할 수 있다. 클러스터는 256으로 확인
# 쉽게 말하자면 맛집, 은행등에서 사용하는 번호표라 생각하면 된다.
2. read 함수
man 2 read 통한 read 함수 읽어보면, ssize_t read(int fildes, void *buf, size_t nbyte);
: read ()는 디스크립터가 참조하는 객체에서 nbyte 바이트의 데이터를 읽으려고 시도
성공하면 실제로 읽은 바이트 수가 반환. 파일 끝을 읽으면 0이 리턴하고 그렇지 않으면, -1이 반환되며 전역 변수 errno가 오류를 나타내도록 설정
디스크립터가 참조하는 객체에서 nbyte 바이트의 데이터를 buf가 가리키는 버퍼로 가져옵니다.
▼ read 함수 및 GNL 구조에 대한 감찾기
#출처 : 42Seoul @sna
#include <unistd.h> //open, read
#include <stdio.h> //printf
#include <fcntl.h> //read 옵션인 O_RDONLY 등을 위해서
#define BUF_SIZE 1024
int main(void)
{
static char txt_str[1024]; //정적 변수 txt_str 선언
int fd1 = open("./text1.txt", O_RDONLY); //open 함수 사용, 정상적이면 fd반환, 실패하면 음수 반환
int fd2 = open("./text2.txt", O_RDONLY); //둘다 읽기 전용으로 open
printf("text1.txt's fd value is : %d\n", fd1); //할당된 파일 디스크럽터 출력
printf("text2.txt's fd value is : %d\n", fd2);
char buff1[BUF_SIZE]; //문자열을 저장할 버퍼 선언
char buff2[BUF_SIZE];
int n1 = read(fd1, buff1, BUF_SIZE); //'파일 디스크럽터' 로부터 '버퍼 크기만큼' '버퍼에 파일을 읽어들인다'
puts(buff1);
int n2 = read(fd2, buff2, BUF_SIZE); //read의 반환값은 '읽어들인 바이트 수'
puts(buff2); //읽어온 문자열이 저장된 버퍼 출력
printf("text1.txt1's n1 value is : %d\n", n1); //read의 반환값인 '읽어들인 바이트 수' 출력
printf("text1.txt2's n2 value is : %d\n", n2);
int i = 0;
while (buff1[i] != '\n')
{
txt_str[i] = buff1[i]; //buff1의 문자열 중 개행문자 전 까지 정적변수에 저장
i++;
}
printf("buff1's text is : %s\n", txt_str); //정적변수 출력
close(fd1); //파일 디스크럽더 사용 종료
close(fd2);
}
3. EOF는 무엇인가
eof(End of File) : 파일의 끝, 데이터 소스로부터 더 이상 읽을 수 있는 데이터가 없음을 나타낸다
4. malloc과 free
#include <stdlib.h>
void *malloc(size_t size);
: malloc () 함수는 메모리의 크기 바이트를 할당하고 할당 된 메모리에 대한 포인터를 반환합니다.
int *ip;
ip = (int *)malloc(sizeof(int) * 5);
void free(void *ptr);
: free () 함수는 ptr이 가리키는 메모리 할당을 해제합니다. ptr이 NULL 포인터이면 작업이 수행되지 않습니다.
포인터가 여전히 해제된 메모리 영역을 가리키고 있는 것 (댕글링 포인터)으로 인해 다양한 문제를 야기하기에, 메모리 해제 후 포인터를 NULL로 설정해야 한다.
5. BUFFER_SIZE
: 프로그램은 -D BUFFER_SIZE=xx 플래그를 붙여서 컴파일
외부에서 #define 을 정의, 아래와 같이 실행될 예정
gcc -Wall -Wextra -Werror -D BUFFER_SIZE=32 get_next_line.c get_next_line_utils.c
6. To succeed get_next_line with a single static varivable
Dynamic Memory Allocation & Static Memorry Allocation
입력되는 데이터에 맞게 기억공간을 확보 하는 것이 동적 메모리 할당, 프로그램을 작성하는 단계에서 필요한 기억공간의 크기를 결정하는 것이 정적 메모리 할당이다. 동적 메모리 할당의 경우는 필요한 메모리만 사용하기 위해 데이터 만큼을 할당, char myName[10] 와 같은 방법은 정적 메모리 할당이다.
동적 메모리가 할당되는 공간은 힙(Heap)으로 프로그램이 종료될 때까지 특정 함수에 구속 받지 않고 어디서나 참조하여 사용 가능하지만, 메모리 회수(free 함수)를 하지 않으면 무한정으로 쌓이게 되고 메모리 낭비를 일으킬 수 있다. 메모리 부족 혹은 어떠한 이유에서 할당이 되지 않았을 때를 대비하여, Null Pointer에 대한 에러 메세지 출력을 하도록 하는 게 좋다.
7. Double Pointer
포인터 변수 : 자료값을 저장하는 목적이 아닌 자료값이 저장된 곳의 주소를 저장하는 변수
8. main.c / 어떻게 구동이 되는가
테스터기를 돌리기 전 가볍게 확인차원에서 쓰는 역할
GNL 해당 파일에서 아래에 있는 파일들을 넣고
"gcc -Wall -Wextra -Werror -D BUFFER_SIZE=32 get_next_line.c get_next_line_utils.c main.c"
그리고 "./a.out" 실행을 하게 되면 제대로 출력이 되는 지 확인
폭발 1.
#include "get_next_line.h"
#include <stdio.h>
int find_new(char **s, char **line, int reader)
{
char *ptr;
char *tmp;
int i;
ptr = *s;
i = -1;
while (*(*s + ++i) != '\0')
{
if (*(*s + i) == '\n')
{
*(*s + i) = '\0';
*line = cut_save(*s, i);
if (ft_strlen(ptr + i + 1) == 0 && reader == 0)
{
free(*s);
*s = NULL;
return (0);
}
tmp = cut_save(ptr + i + 1, ft_strlen(ptr + i + 1));
free(*s);
*s = tmp;
return (1);
}
}
return (0);
}
int get_next_line(int fd, char **line)
{
static char *save[256];
char buf[BUFFER_SIZE + 1];
int flag;
int reader;
if (fd < 0 || fd > 256 || !line || BUFFER_SIZE <= 0)
return (-1);
while ((reader = read(fd, buf, BUFFER_SIZE)) > 0)
{
buf[reader] = '\0';
save[fd] = ft_strjoin(save[fd], buf);
if ((flag = find_new(&save[fd], line, reader)) == 1)
return (1);
}
if (reader == -1 || flag == -1)
return (-1);
if ((flag = find_new(&save[fd], line, reader)) == 1)
return (1);
return (0);
}
폭발 2.
#include "get_next_line.h"
#include <stdio.h>
int find_new(char **s, char **line, int reader)
{
char *ptr;
char *tmp;
int i;
int len;
ptr = *s;
i = 0;
while (*(*s + i) != '\0')
{
if (*(*s + i) == '\n')
{
// len = ft_strlen(ptr + i + 1);
// if (len == 0)
// return (0);
*(*s + i) = '\0';
*line = cut_save(*s, i);
len = ft_strlen(ptr + i + 1);
if (len == 0 && reader == 0)
{
free(*s);
*s = NULL;
return (0);
}
tmp = cut_save(ptr + i + 1, len);
free(*s);
*s = tmp;
return (1);
}
i++;
}
return (0);
}
int get_next_line(int fd, char **line)
{
static char *save[256];
char buf[BUFFER_SIZE + 1];
int flag;
int reader;
if (fd < 0 || fd > 256 || !line || BUFFER_SIZE <= 0)
return (-1);
// if (save[fd])
// if ((flag = find_new(&save[fd], line)) == 1)
// return (1);
while ((reader = read(fd, buf, BUFFER_SIZE)) > 0)
{
buf[reader] = '\0';
save[fd] = ft_strjoin(save[fd], buf);
// write(1, save[fd], ft_strlen(save[fd]));
if ((flag = find_new(&save[fd], line, reader)) == 1)
return (1);
}
if (reader == -1 || flag == -1)
return (-1);
if ((flag = find_new(&save[fd], line, reader)) == 1)
return (1);
// if (flag == 0)
// {
// *line = save[fd];
// free(save[fd]);
// }
return (0);
}
폭발3
#include "get_next_line.h"
#include <stdio.h>
int check_enter(char *s)
{
size_t i;
i = 0;
while (*(s + i))
{
if (*(s + i) == '\n')
return (i);
i++;
}
return (-1);
}
int find_new(char **s, char **line, int enter, int reader)
{
char *tmp;
// *(*s + enter) = '\0';
// *line = cut_save(*s, enter);
if (*s && enter >= 0 && reader > 0)
{
*(*s + enter) = '\0';
*line = cut_save(*s, enter);
if (ft_strlen(*s + enter + 1) == 0)
{
free(*s);
*s = 0;
return (1);
}
tmp = cut_save(*s + enter + 1, ft_strlen(*s + enter + 1));
free(*s);
*s = tmp;
return (1);
}
else if (*s)
{
write(1, "\n[ok]", 5);
*line = *s;
*s = 0;
return (0);
}
*line = ft_strjoin(0, "\0");
/* if (ft_strlen(*s + i + 1) == 0 && reader == 0)
{
printf("\nfinal");
free(*s);
*s = NULL;
return (0);
}*/
return (0);
}
int get_next_line(int fd, char **line)
{
static char *save[256];
char buf[BUFFER_SIZE + 1];
int flag;
int reader;
if (fd < 0 || fd > 256 || !line || BUFFER_SIZE <= 0)
return (-1);
while ((reader = read(fd, buf, BUFFER_SIZE)) > 0)
{
buf[reader] = '\0';
save[fd] = ft_strjoin(save[fd], buf);
if ((flag = check_enter(save[fd])) >= 0)
return (find_new(&save[fd], line, flag, reader));
}
if (reader == -1)
return (-1);
/* if ((flag = check_enter(save[fd])) >= 0)
return (find_new(&save[fd], line, reader, flag));
if (flag == 0 && reader == 0 && *save[fd])
{
write(1, "final", 5);
// *line = ;
free(save[fd]);
*save[fd] = 0;
}*/
flag = check_enter(save[fd]);
return (find_new(&save[fd], line, flag, reader);
}
폭파 4
int free_func(char *s, int flag)
{
free(s);
if (!flag)
return (0);
return (-1);
}
int checking_new(char **ret, char **line)
{
char *tmp;
tmp = ft_strchr(*ret, '\n');
if (!tmp)
{
line = ret;
return (free_func(*ret, 0));
}
else
{
*line = ft_strjoin(0, *ret, (tmp - *ret));
*ret = tmp;
free(tmp);
}
return (1);
}
int get_next_line(int fd, char **line)
{
static char *save[256];
char buf[BUFFER_SIZE + 1];
int reader;
if (fd < 0 || fd > 256 || !line || BUFFER_SIZE <= 0)
return (-1);
while ((reader = read(fd, buf, BUFFER_SIZE)) > 0)
save[fd] = ft_strjoin(save[fd], buf, reader);
if (reader == -1)
return (free_func(save[fd], -1));
return (checking_new(&save[fd], line));
}
폭파의 여러번 .. 직접 짠 함수 그리고 malloc을 쓰면서 할당 되었던 *save 파일 초기화가 제일 문제가 되었던 거 같고, 함수를 최대한 줄이려고 했던 것도 결국 함수 4개를 쓰면서 이후 테스터기에서는 성공
'42 Seoul' 카테고리의 다른 글
[42Seoul] Network netwhat (0) | 2021.06.28 |
---|---|
born2beroot (0) | 2021.06.22 |
[ft_printf] printf 함수 구현 (0) | 2021.05.13 |
[42Seoul] libft (part . bonus) (0) | 2021.05.11 |
[42Seoul] libft (part. 2) (0) | 2021.05.09 |
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!