2017-03-16 69 views
0

您好乡亲,
记忆被重新分配 - 为什么

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

#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后:
word:0x7ffcfffffdb0
个S:0x7ffcfffffdc0
读者:0x7ffcfffffde0
我:0x7ffcfffffdac

谢谢

+0

对不起,但我不明白您是如何确定地址发生变化的,我不相信您,重申他们在'RcppReadSumBin()'执行的范围内这样做。 –

+3

这些变量在堆栈中分配,并在退出该方法后立即回收。你为什么关心内存地址?你不应该首先使用指针 - 你已经使用了* some *参数的引用。 –

+1

请包括[mcve]。在提供的示例中 - 我没有看到您打印的地址在哪里。 –

回答

5

这是一个很成问题的事情:

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

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

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

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

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

+3

同样使用下一行的读取大小读取两个以上的整数是不好的。 sizeof最好是sizeof(int)* 2或者接下来的两行没有意义 –

+1

在这种情况下使用'sizeof(sizeOfhmdspecBody)'可能不太正确,如果8个字节是由协议指定的,而不是数据大小。 – Slava

+0

我正在阅读的文件有一个非常特定的格式,这个特定部分的变量,读入变量sizeOfhmdspecBody,在文件格式的文档中被指定为“8字节整数”。 – Myrkjartan

5

这是罪魁祸首:

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

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

4

使用reinterpret cast时应该小心。在此代码:

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

你假定,int为8个字节,但看起来是不是这样的,你重写变量(破栈)后的内存。您应该使用int64_t而不是int,并在您的代码中加入assert语句,即sizeof(sizeOfhmdspecBody) == 8

+3

好主意暗示断言;它甚至可以是'static_assert'。 – Angew