【问题标题】:fclose, fopen and fwrite issues with writing multiple filesfclose、fopen 和 fwrite 写入多个文件时出现问题
【发布时间】:2013-08-20 22:16:59
【问题描述】:

我有一个从串口记录数据的程序。每隔一段时间,我想拆分文件以使数据日志不会变得非常大。问题是,在我重新创建 FILE* 并尝试写入它之后,程序崩溃了。事先也没有编译器错误/警告...

该程序确实在第一个时间间隔创建了一个日志,但是一旦需要创建一个新的数据日志,它就会在 fwrite 时崩溃。

首先,初始化/声明。

char * DATA_DIR = "C:\DATA";
sprintf(path,"%s%s%s",DATA_DIR,curtime,".log"); //curtime is just the current time in a string
FILE * DATA_LOG = fopen(path, "wb+");   

然后在一个while循环中

if(((CURRENT_TIME-PREVIOUS_TIME) > (SEC_IN_MINUTE * MINUTE_CHUNKS) ) && (MINUTE_CHUNKS != 0) && FIRST_TIME == 0) //all this does is just checks if its time to make a new file
{
    fclose(DATA_LOG); //end the current fileread

    char * path; 
    char curtime[16];

    //gets the current time and saves it to a file name
    sprintf(curtime , "%s" , currentDateTime());
    sprintf(path,"%s%s%s",DATA_DIR,curtime,".log");

    DATA_LOG = fopen(path, "wb+"); //open the new file

    //just some logic (not relevant to problem)
    PREVIOUS_TIME = CURRENT_TIME; 
    newDirFlag = 1;
}
fwrite(cdata , sizeof(char) , numChars , DATA_LOG); //crashes here. cdata, sizeof, and numChars don't change values

任何想法为什么会发生这种情况?我被难住了。

【问题讨论】:

  • 你在检查fopen和fwrite等的返回值吗?
  • 这是 C++ 还是简单的 C?
  • 另外,声明 char * path 没有任何大小或动态分配可能会产生不必要的副作用。
  • 这是用 C++ 编写的。不,我没有检查返回值。我现在就去做。

标签: c++ file-io fopen fwrite fclose


【解决方案1】:

几个问题,路径没有分配内存(您正在将内容写入某个不好的随机内存地址)。您还应该检查 fwrite fopen 的返回值是否有错误。如果有一个使用perror,那么您就知道问题所在了。很可能 fopen 失败了,或者你写信给path 破坏了你的堆栈。

也可以使用snprintf,它比sprintf 更安全,sprintf 容易受到缓冲区溢出的影响。

编辑:刚刚看到您的评论,它是 c++。为什么不改用std::stringfstream?它们比您当前所做的要安全得多(而且可能更容易)。

【讨论】:

  • 道歉。我没有任何正式的 C++ 经验(只有 Java)。我正在更改以前的实习生编写的代码,所以我不知道 fstream,因为他没有在这段代码中使用它。你是说不是 char * path;我可以做类似 std:string 路径的事情吗?我不需要担心随机内存地址问题?
  • 是的,std::string 将处理为字符串分配内存等,因此您不必担心制作char path[512]; 或其他东西来保存路径。如果您仍想使用fopen 等,您始终可以通过调用my_string.c_str() 来传递底层字符串。
【解决方案2】:

您的主要问题是char * path; 没有分配内存。这意味着您正在写入内存中的某个 RANDOM [1] 位置。

我建议您使用char path[PATH_MAX]; - 这样您就不必担心为您的路径分配和稍后释放存储空间。

或者,您可以使用:

stringstream ss;

ss << DATA_DIR << currentDateTime() << ".log";
string path = ss.str();
fopen(path.c_str(), "wb+")

这是一个更 C++ 风格的解决方案。

[1] 我所说的随机并不是真正的随机数,而是恰好位于堆栈上该位置的某个未知值。它几乎总是不是存储字符串的好地方。

【讨论】:

  • 我最终这样做了。最终我发现我的问题是我的路径字符串以某种方式确实发生了变化,这弄乱了我的 fopen。我从这篇文章/谷歌搜索中学到了很多东西。
猜你喜欢
  • 2015-12-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-30
  • 1970-01-01
  • 2013-01-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多