2012-02-26 3 views
0

Эта проблема, по-моему, является исключительно проблемой нехватки памяти.C программируемые строки, указатели и их назначение

(возможно перейти к нижнему и прочитать последний вопрос для некоторых простых предложений)

Я пишу эту программу, которая считывает файл (ы), введенный пользователем. Если файл «включает» другие файлы, они также будут прочитаны. Чтобы проверить, содержит ли другой файл файл, я разбираю первое слово строки. Для этого я написал функцию, которая возвращает синтаксическое слово, и передается указатель, который устанавливается в первую букву следующего слова. Для примера рассмотрим строку:

«включают Foo» Примечание файлы могут содержать только 1 файл

firstWord == включают, chPtr == е

Мой алгоритм разбирает firstWord для проверки строки равенства с 'include', он затем анализирует второе слово, чтобы проверить достоверность файла и посмотреть, был ли файл уже прочитан.

Теперь моя проблема в том, что многие файлы читаются, а chPtr перезаписывается. Поэтому, когда я возвращаю указатель на следующее слово. В следующем слове будут содержаться последние несколько символов предыдущего файла. Рассмотрим пример файлы с именем TestFile-1 и поддельным:

Пусть chPtr первоначально равна TestFile-1 и рассмотрим теперь парсинг «включают поддельным»:

извлекая firstWord будет включать в себя == и chPtr будут переписаны на укажите на b в фиктивном. Таким образом, chPtr будет равен b o g u s '\ 0' l e - 1. l e - 1 - это последние несколько символов тестового файла-1, так как chPtr указывает на тот же адрес памяти каждый раз, когда вызывается моя функция. Это проблема для меня, потому что, когда я разбираю фикцию, chPtr укажет на l. Вот код для моей функции:

char* extract_word(char** chPtr, char* line, char parseChar)  
//POST: word is returned as the first n characters read until parseChar occurs in line 
//  FCTVAL == a ptr to the next word in line 
{ 
    int i = 0; 
    while(line[i] != parseChar && line[i] != '\0')       
    { 
    i++; 
    } 

    char* temp = Malloc(i + 1);   //I have a malloc wrapper to check validity 

    for(int j = 0; j < i; j++) 
    { 
    temp[j] = line[j]; 
    } 
    temp[i+1] = '\0'; 

    *chPtr = (line + i + 1); 
    char* word = Strdup(temp);    //I have a wrapper for strdup too 
    return word; 

Итак, это моя проблема диагностики правильной? Если да, сделаю ли я глубокие копии chPtr? Также, как сделать глубокие копии chPtr?

Большое спасибо!

+2

Почему вы 'Strdup (темп)', а затем вернуть дублированную копию? Если ничего больше, вы никогда не будете «свободными (temp)», поэтому вы будете пропускать память, и на самом деле «return temp;» будет так же хорош (и сэкономить накладные расходы на новое распределение). –

+0

Что вы подразумеваете под «Это проблема для меня, потому что, когда я разбираю фикцию, chPtr укажет на l» Не остановите анализ, когда будет найден «\ 0»? –

ответ

0
char* temp = Malloc(i + 1);   //I have a malloc wrapper to check validity 

for(int j = 0; j < i; j++) 
{ 
    temp[j] = line[j]; 
} 
temp[i+1] = '\0'; <------- subscript out of range replace with temp[i] = '\0'; 
+0

Спасибо, что нашли это. Но это не исправляет мою проблему, так как мои chPtr все еще перезаписываются. – CodeKingPlusPlus

+0

Я не вижу char * chPtr в файле, значение которого перезаписывается в коде, который вы указали. – Nico

+1

Также в том случае, если строка попадает в нуль-терминатор, вы будете передавать следующийWord, который указывает на внешнюю часть диапазона буфера, что приведет к неопределенному поведению. – Nico

0

Непонятно, где ваша проблема. Но вы можете использовать инструмент, который поможет найти его.

Valgrind является одним из таких (бесплатных) инструментов. Он обнаружит множество ошибок доступа к памяти. (Вероятно, он не нашел бы вашу ошибку temp [i + 1] = '\ 0 ", потому что это не так" очень неправильно ").

Наш инструмент CheckPointer - это еще один инструмент. Он находит ошибки, которые Valgrind не может (например, он должен был найти ваше ошибочное назначение temp). Хотя это коммерческая версия, оценочная версия обрабатывает программы небольшого размера, которые могут работать на вас. (Я дома и не помню пределов).

1

Если я правильно понял, что вы хотите отсканировать файл и когда встречается директива 'include', вы хотите отсканировать файл, указанный в директиве 'include', и так далее ad infinitum для любых уровней include, т.е. read один файл, который может включать в себя другие файлы, которые могут в свою очередь включать в себя другие файлы .....

Если это так (и, пожалуйста, исправьте, если я ошибаюсь), то это классическая проблема рекурсии.Преимущество рекурсии состоит в том, что все переменные создаются в стеке и, естественно, освобождаются при распаковке стека.

Следующий код будет делать это без необходимости таНос или свободный или необходимости делать копии того, что:

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

#define INCLUDE "include" 
#define INCOFFSET 7 

static void 
process_record (char *name, char *buf) 
{ 
    // process record here 
    printf ("%s:%s\n", name, buf); 
} 

// change this to detect your particular include 
static int 
isinclude (char *buf) 
{ 
    //printf ("%s:Record %s INCLUDE=%s INCOFFSET=%d\n", __func__, buf, INCLUDE, 
//  INCOFFSET); 
    if (!strncmp (buf, INCLUDE, INCOFFSET)) 
    { 
     //printf ("%s:Record == include", __func__); 
     return 1; 
    } 
    return 0; 
} 

static int 
read_file (char *name) 
{ 

    //printf ("%s:File %s\n", __func__, name); 
    FILE *fd = fopen (name, "r"); 
    if (!fd) 
    { 
     printf ("%s:Cannot open %s\n", __func__, name); 
     return -1; 
    } 

    char buf[1024]; 
    ssize_t n; 
    while (fgets (buf, sizeof (buf), fd)) 
    { 
     size_t n = strcspn (buf, "\n"); 
     buf[n] = '\0'; 
     //printf ("%s:Buf %s\n", __func__, buf); 
     if (isinclude (buf)) 
     { 
      read_file (buf + (INCOFFSET + 1)); 
     } 
     else 
     { 
      process_record (name, buf); 
     } 
    } 
    fclose (fd); 

    return 0; 
} 

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

    int ret = read_file (argv[1]); 
    if (ret < 0) 
    { 
     exit (EXIT_FAILURE); 
    } 
    exit (EXIT_SUCCESS); 

}