I am using the cstdio (stdio.h) to read and write data from binary files. I have to use this library due to legacy code and it must be cross-platform compatible with Windows and Linux. I have a FILE* basefile_ which I use to read in the variables configLabelLength and configLabel, where configLabelLength tells me how much memory to allocate for configLabel.
unsigned int configLabelLength; // 4 bytes
char* configLabel = 0; // Variable length
fread((char *) &configLabelLength, 1, sizeof configLabelLength, baseFile_);
configLabel = new char[configLabelLength];
fread(configLabel,1, configLabelLength,baseFile_);
delete [] configLabel; // Free memory allocated for char array
configLabel = 0; // Be sure the deallocated memory isn't used
Is there a way to read in configLabel without using a pointer? For example is there a solution where I can use the c++ vector library or something where I do not have to worry about pointer memory management.
Just do:
unsigned int configLabelLength; // 4 bytes*
fread((char *) &configLabelLength, 1, sizeof configLabelLength, baseFile_);
std::vector<char> configLabel(configLabelLength);
fread(&configLabel[0], 1, configLabel.size(), baseFile_);
The elements in a vector are contiguous.
* I assume you know that unsigned int isn't necessary always 4 bytes. If you pay attention to your implementation details that's fine, but it'll be a bit easier if you adopt Boost's cstdint.hpp and just use uint32_t.
Related
So I have this function that has a string with a pre-defined buffer (the buffer is defined when calling a function).
My question is, why doesn't the compiler throws me an error whenever I do the following (without the new operator?):
int crc32test(unsigned char *write_string, int buffer_size){
// Append CRC32 to string
int CRC_NBYTES = 4;
int new_buffer_size = buffer_size + CRC_NBYTES; // Current buffer size + CRC
// HERE (DECLARATION OF THE STRING)
unsigned char appendedcrc_string[new_buffer_size];
return 0;
}
isn't THIS the correct way to do it..?
int crc32test(unsigned char *write_string, int buffer_size){
// Append CRC32 to string
int CRC_NBYTES = 4;
int new_buffer_size = buffer_size + CRC_NBYTES; // Current buffer size + CRC
// HERE (DECLARATION OF THE STRING USING NEW)
unsigned char * appendedcrc_string = new unsigned char[new_buffer_size+1];
delete[] appendedcrc_string ;
return 0;
}
And I actually compiled both, and both worked. Why isn't the compiler throwing me any error?
And is there a reason to use the new operator if apparently the former function works too?
There's a few answers here already, and I'm going to repeat several things said already. The first form you use is not valid C++, but will work in certain versions of GCC and CLang... It is decidedly non-portable.
There are a few options that you have as alternatives:
Use std::string<unsigned char> for your input and s.append(reinterpret_cast<unsigned char*>(crc), 4);
Similarly, you can use std::vector<unsigned char>
If your need is just for a simple resizable buffer, you can use std::unique_ptr<unsigned char[]> and use memcpy & std::swap, etc to move the data into a resized buffer and then free the old buffer.
As a non-portable alternative for temporary buffer creation, the alloca() function carves out a buffer by twiddling the stack pointer. It doesn't play very well with C++ features but it can be used if extremely careful about ensuring that the function will never have an exception thrown from it.
Store the CRC with the buffer in a structure like
struct input {
std::unique_ptr<unsigned char[]> buffer;
uint32_t crc;
}
And deal with the concatenation of the CRC and buffer someplace else in your code (i.e. on output). This, I believe is the best method.
The first code is ill-formed, however some compilers default to a mode where non-standard extensions are accepted.
You should be able to specify compiler switches for standard conformance. For example, in gcc, -std=c++17 -pedantic.
The second code is "correct" although not the preferred way either, you should use a container which frees the memory when execution leaves the scope, instead of a manual delete. For example, std::vector<unsigned char> buf(new_buffer_size + 1);.
The first example uses a C99 feature called Variable Length Arrays (VLA), that e.g. g++ by default supports as a C++ language extension. It's non-standard code.
Instead of the second example and similar, you should preferably use std::vector.
I'm trying to read data from a file but I'm getting a STATUS_STACK_BUFFER_OVERRUN error and the app crashes.
I have a struct:
struct BSPEntities
{
char* ents;
};
And I'm reading the file:
BSPEntities entities
ifstream mapfile;
int size = 54506;
int offset = 5182600;
entities.ents = new char[size];
mapfile.seekg(offset, ios::beg);
mapfile.read((char *)(&entities.ents), size);
"size" and "offset" are values loaded from the file and known to be valid. I have preprocessor directives #pragma pack(1) and #pragma push around the BSPEntities struct.
Thanks.
&entities.ents is a pointer to a pointer to char. The object pointed to (a pointer to char) is probably only 4 or 8 bytes depending on the architecture you're targeting, but you're trying to write 54,506 bytes to it. Obviously 54,506 is larger than 8, so you're writing past the end of the pointer, and the behavior is undefined.
That read should just be mapfile.read(entities.ents, size);
Also you don't need to mess around with #pragma pack here, unless there's something more complicated going on that you're not showing.
mapfile.read((char *)(&entities.ents), size);
Should be
mapfile.read(entities.ents, size);
Instead of passing the address of the heap memory block that ents points to, you are passing the address of ents itself. And since ents is being allocated on the stack, you are reading bytes onto the stack until it overruns.
I am fairly new at C++ and am trying to understand how memory manipulation works. I am used to Java and Python and haven't really been exposed to this.
I am working on a project that has the following structure that doesn't quite make sense to me.
typedef struct
{
size_t size;
char *data;
} data_buffer;
This structure basically acts as a buffer, with a pointer to the data stored within the buffer and the size of the buffer to allow the program to know how large the buffer is when reading from it.
An example of how the program uses the buffer:
data_buffer buffer = {0};
//Manipulate data here so it contains pertinent information
CFile oFile;
oFile.Write(buffer.data, buffer.size);
The program mostly uses 3rd party code to read the data found within the buffer, so I am having trouble finding an example of how this is done. My main question is how do I read the contents of the buffer, given only a pointer to a character and a size? However, I would also like to understand how this actually works. From what I understand, memory is written to, with a pointer to where it starts and the size of the memory, so I should be able to just iterate through the memory locations, grabbing each character from memory and tagging it onto whatever structure I choose to use, like a CString or a string. Yet, I don't understand how to iterate through memory. Can someone help me understand this better? Thanks.
There is no reason you cannot use a std::string or CString to manipulate that data. (Use higher level constructs when they are available to you.)
To get the data into a std::string, use the constructor or assignment operator:
std::string s( buffer.data, buffer.size );
You can even stick it in a std::stringstream so you can treat the data buffer like a file:
std::istringstream ss( s );
int n;
ss >> n;
Things work similarly for the MFC string class.
To get the data from a string, you'll need to copy it over. Ideally, you'll be able to allocate the data's memory. Assuming you have data written into a stringstream
std::ostringstream ss;
ss << name << "," << employee_number;
You can then allocate the space you need using the function that creates the data_buffer object:
function_that_creates_a_data_buffer( buffer, ss.str().size() );
If there is no such function (there ought to be!) you must malloc() or new it yourself, as appropriate:
buffer.size = ss.str().size();
buffer.data = (char*)malloc( buffer.size );
Now just copy it:
ss.str().copy( buffer.data, buffer.size );
If your buffer needs a null-terminator (I have so far assumed it doesn't), make sure to add one to the size you allocate and set the last character to zero.
buffer.size = ss.str().size + 1;
buffer.data = new char[ buffer.size ];
ss.str().copy( buffer.data, buffer.size );
buffer.data[ buffer.size-1 ] = 0;
Make sure to look at the documentation for the various classes you will use.
Hope this helps.
A variable of type char* is actually a pointer to memory. Your struct contains data which is of type char* so it is a pointer to memory. (I suggest writing char* data instead of char *data, to help keep this clear.)
So you can use it as a starting point to look at your data. You can use another pointer to walk over the buffer.
char* bufferInspectorPointer;
bufferInspectorPointer = buffer.data;
bufferInspectorPointer will now point to the first byte of the buffer's data and
*bufferInsepectorPointer
will return the contents of the byte.
bufferInspectorPointer++
will advance the pointer to the next byte in the buffer.
You can do arithmetic with pointers in C++, so
bufferInspectorPointer - buffer.data
will tell you how many bytes you have covered. You can compare it to buffer.size to see how far you have left to go.
Since you tagged this as C++ I'd recommend using algorithms. You can get your iterators by using buffer.data as start and buffer.data + buffer.size as end. So to copy the memory into a std::string you'd do something like so:
std::string str(buffer.data, buffer.data + buffer.size);
Or perhaps to append onto a string:
str.reserve(str.size() + buffer.size);
std::copy(buffer.data, buffer.data + buffer.size, std::back_inserter(str));
Of course you can always chose a different end so long as it's not past buffer.data + buffer.size.
They are using a char array so that you can access each byte of the data buffer since size of char is usually 1 byte.
Reading the contents of the data buffer depends on the application. If you know how the internal data is encoded, you can write an unpacking function which selects chunks of the char array and convert/typecast it to the target variables.
eg: Lets say the data buffer is actually a list of integers of size 4 bytes.
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char const* argv[])
{
//how the data buffer was probably filled
int *a = (int *)malloc(10*sizeof(int));
int i;
for(i=0;i<10;i++) {
a[i] = i;
}
char *data = (char *)a;
//how we could read from the data buffer
int *b = (int *)malloc(10*sizeof(int));
char *p = data;
for(i=0;i<10;i++) {
b[i]=(int )*p;
printf("got value %d\n",b[i]);
p += sizeof(int);
}
free(a);
free(b);
return 0;
}
Note: That being said, since this is C++, it would be much safer if we could avoid using char pointers and work with strings or vectors. Other answers have explored other options of how to handle such buffers properly in C++.
I am pretty inexperienced in C++ programming and now I'm trying to make a small program using dctmk to modify the pixel data of the dicom image. In doing so while reading documentation I found a c++ method about which I'm not quite clear. In the documention for the class DicomImage I found the following method:
int DicomImage::getOutputData ( void * buffer,
const unsigned long size,
const int bits = 0,
const unsigned long frame = 0,
const int planar = 0
)
My confusion is about buffer. It's quoted in the link as
buffer : pointer to memory buffer (must already be allocated)
Here my confusion is how do a I allocate? I'm not sure how I could allocate a memory that's a pointer of void type. Could you please explain. Thank you.
You can do it in the following way (for example):
void * mem = malloc(1024); // 1 kb
image.GetOutputData(mem, 1024);
// Don't forget to free(mem);
Another way:
char * mem = new char[1024];
image.GetOutputData((void *)mem, 1024);
// Don't forget to delete[] mem;
Another way:
char mem[1024];
image.GetOutputData((void *)&mem, 1024);
A pointer to void can point to anything, it's a generic nondescript anonymous pointer to some memory. This means that you can pass any kind of pointer as the first argument of the function, as all pointers can implicitly be converted to void*.
You can allocate any type of buffer. It will be converted using void*. However you will need to pass proper size of element. You will need to refer to documentation of api for size of each buffer element. In the example below it is 1 byte. And total buffer size is 10.
int size_of_buffer = 10;
unsigned char *buffer = malloc(sizeof(unsigned char)*size_of_buffer);
It looks like DicomImage::getOutputData does not care how you allocated your bytes. Simply take take the pointer to some blob of your choice (object, struct, array, whatever) and cast it to void*. You can get the memory with new, malloc or it can be a local variable.
Thing to be sure of:
Make sure you allocate enough space.
Make sure you accurately send the size parameter.
Make sure that you understand what format of data DicomImage::getOutputData works with.
I need to be able to set the size of an array based on the number of bytes in a file.
For example, I want to do this:
// Obtain the file size.
fseek (fp, 0, SEEK_END);
size_t file_size = ftell(fp);
rewind(fp);
// Create the buffer to hold the file contents.
char buff[file_size];
However, I get a compile time error saying that the size of the buffer has to be a constant.
How can I accomplish this?
Use a vector.
std::vector<char> buff(file_size);
The entire vector is filled with '\0' first, automatically. But the performance "lost" might not be noticable. It's certainly safer and more comfortable. Then access it like a usual array. You may even pass the pointer to the data to legacy C functions
legacy(&buff[0]); // valid!
You should use a std::vector and not an array.
Real arrays require you to specify their size so that the compiler can create some space for them -- this is why the compiler complains when you don't supply a constant integer. Dynamic arrays are represented by a pointer to the base of the array -- and you have to retrieve the memory for the dynamic array yourself. You may then use the pointer with subscript notation. e.g.,
int * x;
x = (int *) malloc( sizeof(int) *
getAmountOfArrayElements() /* non-const result*/
);
x[5] = 10;
This leads to two types of problems:
Buffer over/under flows : you might subscript-index past either end of the array.
You might forget to release the memory.
Vector provides a nice little interface to hide these problems from you -- if used correctly.
Replace
char buff[file_size];
with
char *buff = new char[file_size];
and once the use of the buff is done..you can free the memory using:
delete[] buff;
There are two points in your question I'd like to cover.
The actual question, how do you create the array. Johannes answered this. You use a std::vector and create it with a size allocation.
Your error message. When you declare an array of some type, you must declare it with a constant size. So for example
const int FileSize = 1000;
// stuff
char buffer[FileSize];
is perfectly legitimate.
On the other hand, what you did, attempting to declare an array with variable size, and then not allocating with new, generates an error.
Problem is that buff needs be created on the heap (instead of stack). Compiler want s to know the exact size to create on the stack.
char* buff = new char[file_size];