1) fgets
2) feof
3) _strdup
4) strtok
5) strcmp
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE 15790
typedef struct Data {
char* ip;
char* time;
char* url;
int status;
}Data;
Data* my_data;
void read_data(char* data_name){
my_data = (Data*)malloc(sizeof(Data) * SIZE);
char str_tmp[1024];
FILE* pFile = NULL;
pFile = fopen("webLog.csv", "r");
if (pFile != NULL)
{
int idx = 0;
fgets(str_tmp, 1024, pFile);
while (!feof(pFile) && idx < SIZE - 1) { // since idx 0 == line 2
fgets(str_tmp, 1024, pFile);
my_data[idx].ip = _strdup(strtok(str_tmp, ","));
my_data[idx].time = _strdup(strtok(NULL, ","));
my_data[idx].url = _strdup(strtok(NULL, ","));
my_data[idx].status = atoi(strtok(NULL, ","));
idx++;
}
}
fclose(pFile);
}
- SIZE 크기의 구조체 배열을 생성한다.
- File을 열고 fgets로 첫 줄을 읽는다.
- while문 안에서 idx가 SIZE - 1 보다 작을 때 까지 구조체의 각 멤버에 토큰화된 데이터를 저장한다.
int compare_ip(const void* m, const void* n) {
return strcmp(((Data*)m)->ip, ((Data*)n)->ip);
}
void sort_ip() {
qsort(my_data, SIZE - 1, sizeof(my_data[0]), compare_ip);
for (int i = 0; i < SIZE - 1; i++) {
printf("%s\n", my_data[i].ip);
printf("\tTime: %s\n", my_data[i].time);
printf("\tURL: %s\n", my_data[i].url);
printf("\tStatus: %d\n", my_data[i].status);
}
}
- 구조체 배열 정렬을 위해 qsort를 이용한다.
- compare_ip는 strcmp를 이용하여 m의 값이 n보다 작은 경우 음수, 같은 경우 0, 큰 경우에 양수를 리턴한다.
typedef enum {
Jan = 1,
Feb,
Mar,
Apr,
May,
Jun,
Jul,
Aug,
Sep,
Oct,
Nov,
Dec
}Month;
Month string_to_enum(char* string) {
if (strcmp(string, "Jan") == 0) {
return Jan;
}
else if (strcmp(string, "Feb") == 0) {
return Feb;
}
else if (strcmp(string, "Mar") == 0) {
return Mar;
}
else if (strcmp(string, "Apr") == 0) {
return Apr;
}
else if (strcmp(string, "May") == 0) {
return May;
}
else if (strcmp(string, "Jun") == 0) {
return Jun;
}
else if (strcmp(string, "Jul") == 0) {
return Jul;
}
else if (strcmp(string, "Aug") == 0) {
return Aug;
}
else if (strcmp(string, "Sep") == 0) {
return Sep;
}
else if (strcmp(string, "Oct") == 0) {
return Oct;
}
else if (strcmp(string, "Nov") == 0) {
return Nov;
}
else if (strcmp(string, "Dec") == 0) {
return Dec;
}
else {
printf("Wrong month input");
exit(-1);
}
}
int help_compare_time(char* m, char* n) {
char temp_m[100];
char temp_n[100];
strcpy(temp_m, m);
strcpy(temp_n, n);
char* m_day;
char* m_month;
int m_year;
char* m_time;
m_day = _strdup(strtok(temp_m, "/"));
m_month = _strdup((strtok(NULL, "/")));
m_year = atoi(strtok(NULL, ":"));
m_time = _strdup(strtok(NULL, ""));
char* n_day;
char* n_month;
int n_year;
char* n_time;
n_day = _strdup(strtok(temp_n, "/"));
n_month = _strdup(strtok(NULL, "/"));
n_year = atoi(strtok(NULL, ":"));
n_time = _strdup(strtok(NULL, ""));
int result;
// do compare
if (m_year == n_year) {
if (string_to_enum(m_month) == string_to_enum(n_month)) {
if (strcmp(m_day, n_day) == 0) {
result = strcmp(m_time, n_time);
}
else {
result = strcmp(m_day, n_day);
}
}
else {
if (string_to_enum(m_month) < string_to_enum(n_month)) {
result = -1;
}
else if (string_to_enum(m_month) > string_to_enum(n_month)) {
result = 1;
}
else {
result = 0;
}
}
}
else {
if (m_year < n_year) {
result = -1;
}
else if (m_year > n_year) {
result = 1;
}
else {
result = 0;
}
}
return result;
}
int compare_time(const void* m, const void* n) {
return help_compare_time(((Data*)m)->time, ((Data*)n)->time);;
}
void sort_time() {
qsort(my_data, SIZE - 1, sizeof(my_data[0]), compare_time);
for (int i = 0; i < SIZE - 1; i++) {
printf("%s\n", my_data[i].time);
printf("\tIP: %s\n", my_data[i].ip);
printf("\tURL: %s\n", my_data[i].url);
printf("\tStatus: %d\n", my_data[i].status);
}
}
C는 Time을 비교하는 함수를 지원하지 않으므로 비교 함수를 직접 만들어야 했다.
- sort_time()은 qsort를 이용해 구조체 배열을 compare_time을 이용하여 정렬한다.
- compare_time은 help_compare_time을 이용하여 m이 n보다 작은 경우 -1, 같은 경우 0, 큰 경우 +1을 리턴한다.
- strtok함수는 데이터 버퍼를 이용하기때문에 compare_time의 m과 n에 사용하면 데이터가 손상되어 qsort가 정상적으로 작동하지 않는다.
- 따라서 help_compare_time에서 temp 스트링에 strcpy를 이용하여 데이터를 복사를하고 토큰화 하여 각 스트링 변수에 저장하였다.
- Month를 비교하기 위해 enum을 이용해 Month 자료형을 만들고, 입력된 스트링을 enum 정수값으로 바꿔주는 string_to_enum 함수를 사용하였다.