2014-09-09 2 views
1

C로 컴파일러를 작성하려고했지만 잠시 있었고 char ** 유형의 객체에 메모리를 할당하는 데 문제가 있습니다. 코드 :char **의 메모리를 c로 재 할당

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <ctype.h> 
#include <errno.h> 
#include <sys/types.h> 
#include <sys/stat.h> 
#include <unistd.h> 

#define FATAL 1 
#define NONFATAL 0 

#define GENERIC 0 
#define INVALID_ARG_COUNT 1 
#define BAD_FILE_HANDLE 2 
#define INVALID_FILE_TYPE 3 
#define ACCESS_DENIED 4 
#define SUCH_LOOPS_WOW 5 
#define NAME_TOO_LONG 6 
#define OOM 7 

typedef struct { 
    char *msg; 
    int fatal; 
} error_t; 

static error_t table[] = { 
/*000*/ {"something went wrong that does not have error handling", FATAL}, 
/*001*/ {"invalid number of arguments", FATAL}, 
/*002*/ {"file could not be opened", FATAL}, 
/*003*/ {"file is not a lightning (.lgt) source file", FATAL}, 
/*004*/ {"access to source file is denied", FATAL}, 
/*005*/ {"too many symbolic links between target and source", FATAL}, 
/*006*/ {"file to be passed has too long of a name", FATAL}, 
/*007*/ {"not enough memory to compile source file", FATAL} 
}; 

void lgt_error(int code) { 
    fprintf(stderr, "error: %s\n", table[code].msg); 

    if(table[code].fatal) { 
     exit(EXIT_FAILURE); 
    } 
} 

char *processedFiles[] = {0}; 
int size = 0; 

void add(char filename[]) { 
    processedFiles = realloc(processedFiles, ++size); 
    *processedFiles++ = malloc(strlen(filename)); 
    *processedFiles = filename; 
} 

int alreadyProcessed(char *filename) { 
    char **iterator = &processedFiles[0]; 

    for(int counter = 0; counter <= size; iterator++, counter++) { 
     if(filename == *iterator) { 
      return 1; 
     } 
    } 

    return 0; 
} 

int match(FILE *file, char *directive) { 
    char *sequence = malloc(strlen(directive) + 1); 

    for(int counter = 0; counter < strlen(directive); counter++) { 
     *sequence++ = fgetc(file); 
    } 

    return strcmp(sequence, directive); 
} 

char *grabFile(FILE *file) { 
    char current = 0; 
    char *filename = malloc(1); 

    while((current = fgetc(file)) != EOF && (!isspace(current) || current != ';')) { 
     sprintf(filename, "%s%c", filename, current); 
    } 
} 

void lgt_process(char *filename, char *translationUnit) { 
    add(filename); 

    struct stat buf; /* *sigh* have fun porting this to windows dumbass */ 

    if(stat(filename, &buf) != 0) { 
     switch(errno) { 
      case EACCES: { 
       lgt_error(ACCESS_DENIED); 
      } 

      case EBADF: 
      case ENOENT: 
      case ENOTDIR: 
      case EOVERFLOW: { 
       lgt_error(BAD_FILE_HANDLE); 
      } 

      case EFAULT: { 
       lgt_error(GENERIC); 
      } 

      case ELOOP: { 
       lgt_error(SUCH_LOOPS_WOW); 
      } 

      case ENAMETOOLONG: { 
       lgt_error(NAME_TOO_LONG); 
      } 

      case ENOMEM: { 
       lgt_error(OOM); 
      } 
     } 
    } 

    translationUnit = (char*) realloc(translationUnit, strlen(translationUnit) + (size_t) buf.st_size); 

    FILE *file = fopen(filename, "r"); 

    if(!file) { 
     lgt_error(BAD_FILE_HANDLE); 
    } 

    char next = 0; 

    while((next = fgetc(file)) != EOF) { 
     ungetc(next, file); 

     if(next == 'i') { 
      if(match(file, "import") == 0) { 
       char *nextFile = grabFile(file); 

       if(alreadyProcessed(nextFile) == 0) { 
        lgt_process(nextFile, translationUnit); 
       } 
      } 
     } 
    } 

    fclose(file); 
} 

int main(int argc, char **argv, char **env) { 
    if(argc == 1) { 
     lgt_error(INVALID_ARG_COUNT); 
    } 

    ++argv; 

    if(strcmp(".lgt", strrchr(*argv, '.')) != 0) { 
     lgt_error(INVALID_FILE_TYPE); 
    } 

    char *source = malloc(1); 

    lgt_process(*argv, source); 

    free(source); 
} 

문제는 대부분 프리 프로세서 인 lgt_process에서 유래한다. 다음은 그 생성하는 오류입니다 :

[email protected] ~/Desktop/lightning $ gcc -o lightning main.c -std=c99 
main.c: In function ‘add’: 
main.c:50:20: error: incompatible types when assigning to type ‘char *[1]’ from type ‘void *’ 
    processedFiles = realloc(processedFiles, ++size); 
        ^
main.c:51:20: error: lvalue required as increment operand 
    *processedFiles++ = malloc(strlen(filename)); 
        ^
+5

솔직히,'add()'는 완전한 오버홀을 필요로합니다. 이 함수에는 어떤 식 으로든 잘못되지 않은 행이 없습니다. 또한'processedFiles'는'char ** '가 아니라'char **'이어야합니다. – WhozCraig

+0

add()로 무엇을하려고합니까? 그렇다면 추천을 할 수 있습니까? – DTSCode

+1

그가 말한 것은 ^^^ 아마도 포인터와 배열을 이해하지 못하는 것 같습니까? –

답변

1

어쩌면이 단순한 문자열 벡터 도움이 될 아래처럼되어야한다 ....

#define STRINGVECTOR_CHUNK_ALLOCATION_SIZE 50 

typedef struct{ 
    char** vector; 
    unsigned int size; 
    unsigned int allocated_size; 
} stringvector; 

typedef int (*stringvector_comparer)(char* l, char* r); 

void stringvector_create(stringvector* v) 
{ 
    v->vector = malloc(sizeof(char*)*STRINGVECTOR_CHUNK_ALLOCATION_SIZE); 
    v->allocated_size = STRINGVECTOR_CHUNK_ALLOCATION_SIZE; 
    v->size=0; 
} 

char* stringvector_at(stringvector* v, int index) 
{ 
    return (v->vector[index]); 
} 

void stringvector_add(stringvector* v, char* s) 
{ 
    if(v->size+1 >= v->allocated_size) 
    { 
     v->allocated_size+=STRINGVECTOR_CHUNK_ALLOCATION_SIZE; 
     v->vector = realloc(v->vector, sizeof(char*)*(v->allocated_size)); 
    } 
    v->vector[v->size] = strdup(s); 
    v->size++; 
} 

void stringvector_destroy(stringvector* v) 
{ 
    int i; 
    for(i=0; i<v->size; i++) 
    { 
     free(v->vector[i]); 
    } 
    free(v->vector); 
} 

int stringvector_contains(stringvector* v, char* s, stringvector_comparer comparer) 
{ 
    int i; 
    for(i=0; i<v->size; i++) 
    { 
     if(comparer(v->vector[i], s) == 0) return 1; 
    } 
    return 0; 
} 

다음 그것을 같이 사용할 수 있습니다

int i; 
    stringvector v; 
    stringvector_create(&v); 
    stringvector_add(&v, "test"); 
    stringvector_add(&v, "this"); 
    stringvector_add(&v, "code"); 

    for(i=0; i< v.size; i++) 
    { 
     printf("%s\r\n", stringvector_at(&v, i)); 
    } 

    printf("contains 'this': %d\r\n", stringvector_contains(&v, "this", strcmp)); 
    printf("contains 'This': %d\r\n", stringvector_contains(&v, "This", strcmp)); 
    printf("contains 'This': %d\r\n", stringvector_contains(&v, "This", stricmp)); 
    stringvector_destroy(&v); 

또는 당신을 위해 16,....

stringvector processedFiles; 
stringvector_create(&processedFiles); 

는 그냥 stringvector_add를 사용하여 추가 기능이 필요하지 않습니다.

typedef struct 
{ 
    char const **data; // or non-const if you intend to modify in-place 
    size_t size; 
} StringList; 

void add(StringList *list, char const *filename) 
{ 
    void *new = realloc(list->data, (list->size + 1) * sizeof *list->data); 
    if (!new) 
     exit(EXIT_FAILURE); // and/or free list->data, other error handling 

    list->data = new; 
    list->data[list->size++] = strdup(filename); 
} 

샘플 사용 : 당신이 RAII처럼 말 때문에

1
char *processedFiles[] = {0};//You can not realloc for array. 
int size = 0; 

void add(char *filename) { 
    processedFiles = realloc(processedFiles, ++size);//need size * object size 
    *processedFiles++ = malloc(strlen(filename));//does not let you change the pointer as a base. and It is necessary to ensure the +1 extra for the NUL character. 
    *processedFiles = filename;//use the function such as strcpy to copy the string rather than a pointer. 
} 

char **processedFiles = NULL; 
int size = 0; 

void add(char *filename) { 
    processedFiles = realloc(processedFiles, (size+1)*sizeof(char*)); 
    processedFiles[size] = malloc(strlen(filename)+1); 
    strcpy(processedFiles[size++], filename); 
} 
0

것은 좀 OO 원칙을 빌려이 코드에 대한 더 나은 디자인을 제안 할 것이다 당신이 사용하려는 경우

StringList processed_files = { 0 }; 

add(&processed_files, "foobar.baz"); 

모든 심각한 코드에서 할당 전략을 개선하는 것을 고려할 것입니다 (즉 size_t capacity;StringList에 추가하고 더 큰 청크로 할당하므로 모든 단일 항목마다 realloc을 호출 할 필요가 없습니다)

+0

@KeithNicholas가 쓴 것과 같습니다. – DTSCode

+0

@DTSCode 예, 우리 모두가 동시에 대답 한 것처럼 보입니다 –

+0

ok. 감사! 나는 내가 그와 같이 갈 것이라고 생각한다. 난 그냥 정확하게 당신의 대답을 이해하고 있었는지 확인하고 싶었던 – DTSCode