C언어 파일 입출력 너무 어렵네요ㅠ.ㅠ
글쓴이: newbboy / 작성시간: 토, 2010/06/19 - 2:02오전
아직 개념이 덜 잡혀서 최대한 짜깁기 하면서 이해하려고 노력하고 있는데
잘 안되네요..
7M이 넘는 txt파일을 불러와서 처리해야 하기 때문에 동적할당으로 배열을 최대한 크게
잡았습니다. 처리해야할 것이 10만개를 훨씬 넘습니다;;
파일에서 빈칸,탭,개행문자로 구분해서 한 단어라고 하는 것을 추출합니다.
그리고 그 단어에 알파벳 이외의 문자가 있으면 그냥 버리고 전부 알파벳으로만 이루어진
단어라면 그 단어를 배열에 차곡 차곡 저장하는것 입니다.
한번 아래와 같이 구현해보았는데 words[numwords++] = strdup(word); 이부분에서
포인터 값이 잘 안맞는지 char * 에서 char 로 변환할 수 없다는 에러메세지가 뜹니다.
도움 부탁드립니다!
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <malloc.h> #include <ctype.h> #define ARRAY_SIZE 10000 int main() { char* word = (char*)malloc(sizeof(char)*ARRAY_SIZE); char* words = (char*)malloc(sizeof(char)*ARRAY_SIZE); //char *words[ARRAY_SIZE]; //char word[ARRAY_SIZE]; int numwords = 0; FILE *fp; int i=0,damn=0,len=0; fp = fopen("document.txt","r"); while( fscanf(fp, "%s", word) != EOF ) { len=strlen(word); for(i=0;i<len;i++) { if(!isalpha(word[i])) damn++; } if(damn==0) { words[numwords++] = strdup(word); damn=0; } } for(i=0;i<numwords;i++) printf("%s\n", words[i]); free(word); free(words); }
Forums:
....
(글삭제 ^^;;) 본인의 무지함이 적나라하게 드러났군요.;;
words 선언이
words 선언이 잘못되었네요
의도대로 하실려면 아래와 같이 char*을 원소로 하는 배열로 선언을 하셔야되요
char* words[ARRAY_SIZE] = {}; // 포인터들을 null 로 초기화
words에 배열 크기를
C++로 구현해보세요.
우선 저기서 오버플로우가 나는 이유는
그리고 words를 소스코드에서 사용하는 방식을 보아하니, 문자열의 목록을 담기위해서 선언하신것 같은데...
한마디로 char포인터형을 담아내기 위한 배열로 사용하고 계시니 아래처럼 바꿔주셔야합니다.
마지막으로... C언어 대신
C++ 표준라이브러리로 아래처럼 편리하고 간결하게 구현할 수 있습니다.
7메가짜리 파일도 문제없이 열리네요.
소스코드를 보니 읽어들인 텍스트 파일내 각 라인의 문자열상에
알파벳이 없는 문자열들만 리스트화해서 마지막에 출력하시려고 하시는것 같은데, 맞나요?
그렇다면, 문자열의 갯수는 정해진 갯수보다 충분히 커질 수 있기 때문에,
이런 가변적인 요소를 쉽게 해결하기 위해서는 고정 배열이나 위와 같은 방법을쓰는 것 보다는
STL 컨테이너를 쓰는게 훨씬 효율적입니다.
라인의 문자열 자체도 가변적이기 때문에, char 배열을 쓰거나, char 동적배열을 쓸바에는
string 객체를 쓰는게 낫구요.
구현을 꼭 C로 해야되서요ㅠ.ㅠ
이렇게 해보았는데 buff = (char*)word.c_str(); 요 부분에서
" error C2228: '.c_str' 왼쪽에는 클래스/구조체/공용 구조체가 있어야 합니다.
'char *' 형식입니다." 라는 오류가 떠버리네요ㅠ.ㅠ
아 그리고 논리적 오류가 있었는데, 공백/탭/개행 문자로 구분된 한 string을 단어라고 하고
그 단어가 알파뱃 의외의 문자 - , . ' 등이 들어가 있으면 그냥 버리고 그게 아니면 배열에
삽입하는겁니다^^
그런 후에 이제 사전순으로 따로 배열을 해야되서요ㅎㅎ
클 모 사이트에서도
클 모 사이트에서도 봤던 것 같은데 여기서 뵙는군요 :-)
5시에 작성하신 리플의 코드는 C와 C++가 엄하게 섞였네요. word 는 char * 타입일 뿐이니 뒤에 .c_str 이런 필드를 적을 수 없죠. 위에 richjaff님 코드에서는 line 이 string 클래스라서 가능한 거고...
새로 올리신 코드는 그 외의 부분은 제가 안 봐서 모르겠고, 처음 코드에서 보면요..
처음에 words 를 고정된 배열로 했던 코드도 7MB 정도를 다루는 데는 괜찮은 것 같은데요?
여기서 word 는 매번 scanf 로 읽는 한 단어들을 임시로 넣을 공간이니 굳이 ARRAY_SIZE 만큼의 공간은 필요가 없고, 텍스트 파일 내에서 가장 긴 단어의 길이보다 길기만 하면 되겠죠. 수십~백 정도만 잡아도 될 것 같고,
words 의 크기가 문제인데, 영어텍스트 한 문단을 계속 복사해서 7.4MB 짜리 텍스트를 만들었더니 단어 갯수가 132만개 정도 되더군요. 제가 리눅스 시스템에서 gcc 로 컴파일해보면 ARRAY_SIZE 를 2,000,000 정도로 잡으니 너끈하더군요.
그리고 damn 값을 0으로 다시 세팅하는 문장은 if 문 바깥쪽으로 빼셔야겠죠. 안 그러면 한 번 1이 되면 다시는 0이 되지 않으니 이후의 단어들은 죄다 저장되지 않습니다.
배열 말고 malloc 으로 words 를 잡는다면, richjaff님 말씀처럼, 문자열의 목록 = char 의 포인터의 목록이니까 char * 가 아니라 char ** 여야 하고
역시 ARRAY_SIZE는 2백만 정도로 잡으니 무리없이 읽어서 출력하는 걸 확인했습니다.
도움이 되면 좋겠네요.
P.S. 별개의 얘기지만, 문장 마지막 단어들이 뒤에 마침표 붙는 것 때문에 저장되지 못하고 스킵되더군요. 아마 그 처리도 해주셔야 할 듯?
좋은 하루 되세요!
아... 소스를 보고
아... 소스를 보고 짜깁기를 하다보니 또 제대로 되지가 않는군요.. C++ 언어를 섞어 쓴걸
이제야 알았네요;;;
대충 핵심은 이정도 인데, isalpha(word[i]) 이 부분에서 살짝 말썽을 피우네요..
저렇게 직접 접근해서 배열의 값을 가져오면 안되는건지 모르겠습니다..
그리고 ARRAY_SIZE를 2000000으로 두고 돌려버리니 스택 오버플로가 생기고
200000으로 하니 그냥 프로그램이 아무것도 안뜨네요.. 실행은 되긴 되는데;;
제가 VMWare상에서 램을 약 1GB로 잡아두었는데 이 이유일까요?;;
isalpha()쪽은 제가 할
isalpha()쪽은 제가 할 때는 전혀 문제의 소지가 없었는데... word 는 윗 글에서도 말했듯이 굳이 클 필요가 없으니 char word[100] 정도만 잡고 해 보시지요. 아니면 그렇게 했는데도 isalpha 쪽에서 문제가 되던가요?
좋은 하루 되세요!
char word[100]으로
char word[100]으로 잡아주고,
words는 200000으로 잡아주면 실행은 되고 결과는 없고
words는 2000000으로 잡아주면 오버플로가 나네요.. 디버깅 포인트도 없구요;
다시 디버깅 포인트 잡아서 차례 차례 내려가니
단어를 배열에 넣는 부분에서
words[numwords++] = strdup(word);
words[numwords++]이 이 잘못 되었다고 뜨네요;;
음 그럼 시스템마다
음 그럼 시스템마다 배열의 원소 갯수의 한계가 다른가보네요.. 아니면 컴파일러 옵션으로 지정이 가능할런지...
그럼 처음 적으신 코드에서 malloc 을 사용한 경우도 2백만이면 문제가 되던가요? 텍스트 문서의 단어 갯수를 대강 어림잡아서 최소한도로 사용하게 해보던가...
그도 안 되면 아예 접근 방법을 좀 바꿔야 할지도... 저는 더는 모르겠네요 ^^;
좋은 하루 되세요!
작성자분 코드의 문제점
흠... 기본기가 많이 부족하신것 같네요.
코드내에서 하나하나 잘못된 부분을 찝어드리겠습니다.
상당히 지적사항이 많네요.
그리고 굳이 여기서 동적배열을 쓸 필요가 없을 것 같은데,
라인 문자열 하나당 길이가 5000개가 안되는 조건에 맞는다면,
차라리 아래처럼...
-정리하자면,
1.동적할당을 할때에 원소가 무엇이냐에 따라 그에 맞는 할당을 실시해준다.
타입* = (타입*)malloc(sizeof(타입)*원하는크기);
위에서 words는 포인터형을 원소로 가지는 동적배열입니다. 그럼 아래처럼
char** (char**)malloc(sizeof(char*)*MAXIMUMSIZE);
이때, char원소와 char*원소를 가지는 배열의 차이점:
-->char* : 생성되는 크기는 4바이트(주소값의 자료크기는 32비트(win32)) X 배열의크기(100일때) = 400바이트 (배열의 크기는 100)
-->char : 생성되는 크기는 1바이트 X 배열의크기(100일때) = 100바이트, (배열의 크기는 100)
2.버퍼에 인덱스(첨자)를 사용함에 있어서 참조에러가 일어나는지 검사하는 것은 필수입니다.
또한, 버퍼의 인덱스에는 음수값이 들어가서는 안되므로 부호있는 자료형보다는 unsigned형을 쓰는게 안전합니다.
따라서, 적당히 unsigned int형을 쓰면 되겠죠.
또한, words[인덱스]를 사용함에 있어서 인덱스는 0에서 시작하여 (MAXIMUMSIZE-1)만큼의 값에 대해서만 유효합니다.
그러므로 인덱스값을 항상 검사해주세요.
더불어서 words가 가지는 원소인 포인터형 값에 대한 유효성을 반드시 검사하는게 필요합니다.
3.strdup으로 새로 동적할당을 실시하고 있는데, 이에 대해 동적할당을 해제하는 구문이 없습니다.
따라서, 해제하는 과정을 작업이 완료된 이후에 실시해줘야합니다.
또한 파일 포인터도 작업이 끝나면 꼭 닫도록 하시구요.
-마지막으로
C언어를 공부하시면서 문법이나 사용법만 알려고 하실게 아니라,
"예외"사항의 추측, 메모리 차원에서 어떻게 접근이 이루어지는지,
코드의 전체적인 흐름(코드 하나가 실행되고나서, 어떤 결과가 나오고 이어서 어떤 처리로 이루어질지)을
하나하나 추상적으로 생각하면서 코딩하는 습관이 필요합니다.
더 궁금한게 있으면 질문해주세요.
긴 답글 정말
긴 답글 정말 감사합니다. 앞으로 C에 대해선 더 많이 배워야 겠다는 생각이 듭니다.
말씀해 주신 소스를 이용해 보면 아무 것도 표시 되지 않고 그냥 프로그램이 종료가 되네요..
링크드 리스트로 구현된 이 소스는 잘 작동을 합니다. 그런데 배열로 작성을 해야하니
이걸 다시 옮기던지 아니면 처음부터 다시 소스를 작성해야할텐데 배열은 안되고
링크드 리스트는 되는게 조금 난감하네요ㅠ.ㅠ;
가상 머신이라 그런건지.. 아니면 배열 크기가 문제인건지 계속 되는 오버 플로우 때문에
배열로 하는 것을 건드리기가 어렵군요.. 직접 머리 싸매며 해결해 보아야 겠습니다.
질문과는 맞지 않지만 문득 루비로...
Life rushes on, we are distracted
Life rushes on, we are distracted
댓글 달기