重新分配局部变量的记忆 - 为什么

时间:2017-03-16 13:22:46

标签: c++

大家好,

我试图实现一个应该读取二进制文件的函数 在代码中的某一点,我总是会遇到内存访问错误 我已经知道,这是因为我调用某个函数后,我的局部变量的内存地址发生了变化,即使该函数与我的局部变量无关。 愿任何人都能告诉我我做错了什么吗? 这是我的代码:

#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>
#include <cstdint>


//all Blocks from .sum in form of struct
struct HMDSPEC{
  int value1;
  int value2;
};

struct TIME{
  double value;
  std::string dimension;
};

struct DATE{
  int day;
  std::string month;
  int year;
};

//global variables

HMDSPEC hmdspec;
TIME scheduledTime;
DATE date;


void EraseSpaces(char* arr,std::string &s) {
  for(int i = 0; i < 8 ;i++){
    if(std::isspace(arr[i])){
      arr[i]='\0';
    }
  }
  s=std::string(arr);
}

void readHMDSPEC(std::ifstream &reader){
  std::cout<<"in HMDSPEC -> Adresse von reader : " << &reader << std::endl;
  std::cout << &hmdspec<<std::endl;
  std::cout << &hmdspec.value1 << std::endl;
  std::cout << &hmdspec.value2 << std::endl;
  int sizeOfhmdspecBody;
  reader.read(reinterpret_cast<char *>(&sizeOfhmdspecBody), 8);
  std::cout<<"in HMDSPEC nach 1st lesen-> Adresse von reader : " << &reader << std::endl;
  std::cout << &sizeOfhmdspecBody << std::endl;
  reader.read(reinterpret_cast<char *>(&hmdspec.value1), sizeOfhmdspecBody/2);
  std::cout<<"in HMDSPEC nach 2nd lesen-> Adresse von reader : " << &reader << std::endl;
  std::cout << &hmdspec<<std::endl;
  std::cout << &hmdspec.value1 << std::endl;
  reader.read(reinterpret_cast<char *>(&hmdspec.value2), sizeOfhmdspecBody/2);
  std::cout<<"in HMDSPEC nach 3rd lesen-> Adresse von reader : " << &reader << std::endl;
  std::cout << &hmdspec.value2 << std::endl;
}

void readTIME(char *word, std::ifstream &reader){
  reader.read(word,8);
  reader.read(reinterpret_cast<char *>(&scheduledTime.value),8);
  reader.read(word, 8);
  EraseSpaces(word,scheduledTime.dimension);
}



void RcppReadSumBin(std::string fname)
{
  std::ifstream reader(fname,std::ios::binary|std::ios::in);
  std::string s;
  s.reserve(512);
  char word[8];
  std::cout<<"Nach deklaration -> Adresse von word : " << &word << std::endl;
  std::cout<<"Nach deklaration -> Adresse von s : " << &s << std::endl;
  std::cout<<"Nach deklaration -> Adresse von reader : " << &reader << std::endl;
  s.reserve(256);
  reader.read(word, 8);
  std::cout<<"Nach erstem einlesen -> Adresse von word : " << &word << std::endl;
  std::cout<<"Nach erstem einlesen -> Adresse von s : " << &s << std::endl;
  std::cout<<"Nach erstem einlesen -> Adresse von reader : " << &reader << std::endl;
  EraseSpaces(word,s);
  std::cout<<"Nach eraseSpaces -> Adresse von word : " << &word << std::endl;
  std::cout<<"Nach eraseSpaces -> Adresse von s : " << &s << std::endl;
  std::cout<<"Nach eraseSpaces -> Adresse von reader : " << &reader << std::endl;
  int i =0;
  std::cout<<"Vor while -> Adresse von word : " << &word << std::endl;
  std::cout<<"Vor while -> Adresse von s : " << &s << std::endl;
  std::cout<<"Vor while -> Adresse von reader : " << &reader << std::endl;
  std::cout<<"Vor while -> Adresse von i : " << &i << std::endl;
  while(s!="ENDFILE"){
    reader.read(word,8);
    std::cout<<"Nach nächstem read -> Adresse von word : " << &word << std::endl;
    std::cout<<"Nach nächstem read -> Adresse von s : " << &s << std::endl;
    std::cout<<"Nach nächstem read -> Adresse von reader : " << &reader << std::endl;
    std::cout<<"Nach nächstem read -> Adresse von i : " << &i << std::endl;
    EraseSpaces(word,s);
    std::cout<<"Nach eraseSpaces -> Adresse von word : " << &word << std::endl;
    std::cout<<"Nach eraseSpaces -> Adresse von s : " << &s << std::endl;
    std::cout<<"Nach eraseSpaces -> Adresse von reader : " << &reader << std::endl;
    std::cout<<"Nach eraseSpaces -> Adresse von i : " << &i << std::endl;
    if(s=="HMDSPEC"){
      std::cout<<"In HMDSPEC -> Adresse von word : " << &word << std::endl;
      std::cout<<"In HMDSPEC -> Adresse von s : " << &s << std::endl;
      std::cout<<"In HMDSPEC -> Adresse von reader : " << &reader << std::endl;
      std::cout<<"In HMDSPEC -> Adresse von i : " << &i << std::endl;
      readHMDSPEC(reader);
      std::cout<<"Nach readHMDSPEC -> Adresse von word : " << &word << std::endl;
      std::cout<<"Nach readHMDSPEC -> Adresse von s : " << &s << std::endl;
      std::cout<<"Nach readHMDSPEC -> Adresse von reader : " << &reader << std::endl;
      std::cout<<"Nach readHMDSPEC -> Adresse von i : " << &i << std::endl;
    }else if (s=="TIME"){
      readTIME(word,reader);
      std::cout << scheduledTime.value << std::endl;
      std::cout << scheduledTime.dimension << std::endl;
    }/*else if (s=="DATE"){
      readDATE();
    }else if (s=="CELLDATA"){
      readCELLDATA();
    }else if (s=="CONNDATA"){
      readCONNDATA();
    }else if (s=="SRCDATA"){
      readSRCDATA();
    }else if (s=="FPCEDATA"){
      readFPCEDATA();
    }else if (s=="FPCODATA"){
      readFPCODATA();
    }*/
    std::cout<<"Nach if -> Adresse von word : " << &word << std::endl;
    std::cout<<"Nach if -> Adresse von s : " << &s << std::endl;
    std::cout<<"Nach if -> Adresse von reader : " << &reader << std::endl;
    std::cout<<"Nach if -> Adresse von i : " << &i << std::endl;
    i++;
    std::cout<<"Nach i++ -> Adresse von word : " << &word << std::endl;
    std::cout<<"Nach i++ -> Adresse von s : " << &s << std::endl;
    std::cout<<"Nach i++ -> Adresse von reader : " << &reader << std::endl;
    std::cout<<"Nach i++ -> Adresse von i : " << &i << std::endl;
  }
  reader.close();
}

int main ()
{
    std::string filename="SPE1.0000.SUM";

    RcppReadSumBin(filename);

    exit(0);
}

当我打印地址时,它看起来像这样(例如)
在readHDMSPEC之前:
字:0x7ffded9a42b0
s:0x7ffded9a42c0
读者:0x7ffded9a42e0
我:0x7ffded9a42ac

readHDMSPEC之后:
字:0x7ffcfffffdb0
s:0x7ffcfffffdc0
读者:0x7ffcfffffde0
i:0x7ffcfffffdac

谢谢

3 个答案:

答案 0 :(得分:5)

这是罪魁祸首:

int sizeOfhmdspecBody;
reader.read(reinterpret_cast<char *>(&sizeOfhmdspecBody), 8);

您正在将{8}字节读入int,但在大多数(如果不是全部)公共平台上,sizeof(int)为4.如果您知道数据流中将有8个字节,请使用一个合适的类型,例如std::int64_t,而不是int

答案 1 :(得分:5)

这是一个非常有问题的事情:

int sizeOfhmdspecBody;
reader.read(reinterpret_cast<char *>(&sizeOfhmdspecBody), 8);

我不知道sizeof(int) == 8的任何平台。即使在64位系统上,int的大小也是4个字节。这将导致程序写出sizeOfhmdspecBody变量的界限,导致未定义的行为,使整个程序格式错误

解决方案?不要使用硬编码的magic numbers。而是使用例如sizeof sizeOfhmdspecBody为大小。

如果文件中的数据是8字节(64位),则使用int64_t作为类型,或使用uint8_t的数组作为正确的大小。

正如Lou Franco在评论中指出的那样,如果sizeOfhmdspecBody的值不等于sizeof(int),那么接下来的两行也会做坏事。

答案 2 :(得分:4)

使用重新解释演员时应该小心。在这段代码中:

int sizeOfhmdspecBody;
reader.read(reinterpret_cast<char *>(&sizeOfhmdspecBody), 8);

你假设,int是8个字节,但看起来并非如此,你在该变量之后覆盖内存(打破堆栈)。您应该使用int64_t而不是int并在您的代码中添加断言语句sizeof(sizeOfhmdspecBody) == 8