【问题标题】:Strange Char* Truncation奇怪的字符 * 截断
【发布时间】:2023-04-05 00:29:01
【问题描述】:

我刚刚回到 C 编程领域,但我遇到了一个奇怪的问题,即结构中的动态 char* 字段。它一开始完全没问题,而且长度合适,但它被截断为 25 个字符,其中最后一个字符甚至不在原始数组中。

我定义了两个结构和几个全局变量:

struct files_list {
  struct files_list* next;
  char* fpath;
};

struct job_list {
  int len;
  off_t size;
  struct files_list* files;
  struct job_list* next;
};

struct job_list* job_head = NULL;
struct job_list* active = NULL;

(这个想法是会有一个“作业”的链接列表,多个线程将处理每个由该作业的单个文件链接列表组成。)

Main 只是调用ntfw 来遍历目录树:

int main(int argc, char** argv) {
  // ...
  nftw("/tmp/", populate, 100, 0);
  // ...
}

对于每个文件和目录,ntfw 都会调用我的populate 函数:

int populate(const char *fpath, const struct stat *sb,
             int tflag, struct FTW *ftwbuf) {



  if (tflag == FTW_F) {
    /* #1 CREATE NEW FILE ENTRY */
    printf("\n\n");
    printf("FPATH: %s\n", fpath);
    struct files_list* current_files = malloc(sizeof(struct files_list));
    current_files->fpath = malloc(sizeof(fpath) + 1);
    strcpy(current_files->fpath, fpath);
    current_files->next = NULL;
    printf("files_list %s (%i)\n", current_files->fpath, strlen(current_files->fpath)); 
    printf("&current_files: %p\n", current_files);



    /* #2 CREATE NEW ACTIVE JOB */
    if (active == NULL) {
      struct job_list* job = malloc(sizeof(struct job_list));
      job->len = 0;
      job->size = 0;
      job->files = NULL;
      job->next = NULL;
      active = job;
    }
    active->len++;
    active->size += sb->st_size;


    /* #3 INSERT FILE ENTRY AT THE END OF ACTIVE JOB */
    if (active->files == NULL) {
      active->files = current_files;
      printf("&active->files: %p\n", active->files);
      printf("current_files->fpath: %s (%i)\n", current_files->fpath, strlen(current_files->fpath)); // TRUNCATED STRING
      printf("active->files->fpath: %s (%i)\n", active->files->fpath, strlen(active->files->fpath));
    } else {                                                                                                                                                                                               
      struct files_list* x = active->files->next;                                                                                                                                                                  
      while (1) {                                                                                                                                                                                                  
        if (x == NULL) {                                                                                                                                                                                           
          x = current_files;                                                                                                                                                                                       
          printf("Added files_list: %s\n", x->fpath);                                                                                                                                                              
          break;                                                                                                                                                                                                   
        } else {                                                                                                                                                                                                   
          printf("next x->next\n");                                                                                                                                                                                
          x = x->next;                                                                                                                                                                                             
        }                                                                                                                                                                                                          
      }
    }

    /* #4 TIME FOR A NEW JOB */
    if (active->size > MAX_BYTES) {
      if (job_head == NULL) {
        job_head = active;
        job_tail = active;
      } else {
        job_tail->next = active;
      }
      struct job_list* new_active = NULL;
      active = new_active;
      job_len++;
    }
  }
  return 0;
}

产生这样的输出:

FPATH: /tmp/.com.google.Chrome.T8MuMk/SingletonSocket
files_list /tmp/.com.google.Chrome.T8MuMk/SingletonSocket (46)
&current_files: 0x125d1e0
&active->files: 0x125d1e0
current_files->fpath: /tmp/.com.google.Chrome.1 (25)
active->files->fpath: /tmp/.com.google.Chrome.1 (25)

从前两行我们可以看出,文件路径很长,包含 46 个字符,并且成功地将strcpy()ed 到我的files_list 结构中。然后在第 2 步和第 3 步的前几行之间发生了一些事情,将文件名截断为 24 个字符并添加了“1”。指针地址表明它仍然是同一个结构对象,并且我看不到任何可能与它混淆的操作。

我用过 GCC 4.9.2 和 Clang 3.5.0,他们都有这个问题,所以一定是我做错了。

有什么想法吗?

【问题讨论】:

  • current_files->fpath = malloc(sizeof(fpath) + 1); 你正在分配sizeof(char*) + 1 字节。

标签: c pointers struct


【解决方案1】:

这就是问题

malloc(sizeof(fpath) + 1);

sizeof(fpath) 将给出一个指针的大小,因为fpath 是一个char *,即一个char 指针,你需要strlen()

malloc(strlen(fpath) + 1);

不要忘记包含string.h

您需要了解sizeof 运算符,这是来自 1570 草案,§ 6.5.3.4 段落 ¶ 2

sizeof 运算符产生其操作数的大小(以字节为单位),可能是 表达式或类型的括号名称。大小由类型决定 操作数。结果是一个整数。如果操作数的类型是变长数组类型,则计算操作数;否则,不计算操作数,结果为整数常量。

注意:你必须检查malloc()函数族的返回值,当失败发生时它们返回NULL,你必须检查几乎每个函数的返回值,因为只有这样才能保证函数正常工作,没有意外发生,不然怎么会有返回值呢?

【讨论】:

  • 同意@iharob 关于检查的说法。看起来好像它使您必须做的工作加倍,但是当您的大型程序中有 1000 个函数调用并且它发生故障时,努力就会得到回报。但它更多不止于此。开发一种能够在事情没有按照您期望的方式进行时应对的编程风格会产生健壮的代码。如果你从一开始就投入时间,去测试每一个小的开发,给它施加压力,试图打破它,从长远来看,你会得到回报,特别是如果你的产品在一个已经即时调试和更新。
  • 感谢您的帮助。这确实有效,我理解这个问题。但是,malloc() 没有返回 NULL,并且初始分配包含完整的字符串。我无法理解为什么它最初可以工作,然后在以后中断。
  • 这被称为未定义行为,它是未定义的,所以它会工作一次,而不是另一次,我不是说malloc() 正在返回NULL,这只是建议,习惯检查malloc()的返回值,从长远来看对你有好处,请阅读WeatherVane的评论。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-12-12
  • 2012-12-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-29
  • 2020-05-12
相关资源
最近更新 更多