Строки программирования C, указатели и распределение - PullRequest
0 голосов
/ 26 февраля 2012

эта проблема, я думаю, связана исключительно с проблемой выделения памяти.

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

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

"include foo" NOTE файлы могут включать только 1 другой файл

firstWord == включить, chPtr == f

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

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

Пусть chPtr изначально равен testfile-1 и теперь рассмотрим синтаксический анализ 'include bogus':

извлечение firstWord будет == включать, и chPtr будет перезаписан, чтобы указывать на b в фиктивном. Таким образом, chPtr будет равен b \ g 's' \ 0 'l e - 1. l e - 1 - это последние несколько символов testfile-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?

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

Ответы [ 3 ]

1 голос
/ 26 февраля 2012

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

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

Следующий код сделает это без необходимости использования malloc или free или создания копий чего-либо:

 #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);

 }
0 голосов
/ 26 февраля 2012

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

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

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

0 голосов
/ 26 февраля 2012
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';
...