【问题标题】:C programming strings, pointers, and allocationC 编程字符串、指针和分配
【发布时间】:2012-02-26 06:01:37
【问题描述】:

我认为这个问题完全是内存分配不足的问题。

(可能跳到底部,阅读最后一个问题以获得一些简单的建议)

我正在编写这个程序来读取用户输入的文件。如果文件“包含”其他文件,那么它们也将被读取。为了检查另一个文件是否包含一个文件,我解析了字符串的第一个单词。为此,我编写了一个返回已解析单词的函数,并传入一个指针,该指针被设置为下一个单词的第一个字母。例如考虑字符串:

"include foo" 注意文件只能包含 1 个其他文件

firstWord == 包括,chPtr == f

我的算法解析 firstWord 以使用“include”测试字符串是否相等,然后解析第二个单词以测试文件有效性并查看文件是否已被读取。

现在,我的问题是正在读取许多文件并且 chPtr 被覆盖。因此,当我将指针返回到下一个单词时。下一个单词有时会包含前一个文件的最后几个字符。考虑名为 testfile-1 和 bogus 的示例文件:

让 chPtr 原来等于 testfile-1,现在考虑解析 'include bogus':

提取 firstWord 将 == 包含,并且 chPtr 将被覆盖以指向 b in bogus。因此,chPtr 将等于 b o g u s '\0' l e - 1。 l e - 1 是 testfile-1 的最后几个字符,因为每次调用我的函数时 chPtr 都指向相同的内存地址。这对我来说是个问题,因为当我解析 bogus 时,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 的深拷贝?

非常感谢!

【问题讨论】:

  • 你为什么Strdup(temp)然后返回复制的副本?如果不出意外,你永远不会 free(temp) 所以你会泄漏内存,而实际上 return temp; 会一样好(并为你节省新分配的开销)。
  • “这对我来说是个问题,因为当我解析伪造的,chPtr 将指向 l”你是什么意思当找到 '\0' 时你会停止解析吗?

标签: c string parsing malloc deep-copy


【解决方案1】:

如果我理解正确,您想扫描一个文件,当遇到“包含”指令时,您想扫描“包含”指令中指定的文件,以此类推,以获取任何级别的包含,即读取一个可能包含其他文件的文件,而这些文件又可能包含其他文件.....

如果是这样(如果我错了,请纠正)那么这是一个经典的递归问题。递归的优点是所有变量都在堆栈上创建,并在堆栈展开时自然释放。

以下代码将执行此操作,无需任何 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);

 }

【讨论】:

    【解决方案2】:
    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';
    

    【讨论】:

    • 感谢您找到此内容。但这并不能解决我的问题,因为我的 chPtr 仍在被覆盖。
    • 我在文件中看不到 char* chPtr,您提供的代码中将覆盖该值。
    • 此外,如果字符串遇到空终止符,您将传回指向缓冲区范围之外的 nextWord,这将引入未定义的行为。
    【解决方案3】:

    不清楚您的问题出在哪里。但是您可以使用工具来帮助定位它。

    Valgrind 就是这样一种(免费)工具。它将检测各种内存访问错误。 (它可能不会发现您的 temp[i+1]='\0' 错误,因为这不是“非常错误”)。

    我们的CheckPointer 工具是另一个工具。它发现 Valgrind 不能发现的错误(例如,它应该找到你的错误临时分配)。虽然它是商业版,但评估版可以处理小型程序,这可能对您有用。 (我在家,不记得限制了)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-03-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-21
      • 2021-04-15
      相关资源
      最近更新 更多