I need to violently write into a vector (to avoid superfluous memcpy).
Let's consider this very simplified piece of code
unsigned read_data ( char * buffer , unsigned maxsize )
{
const char * data = "Hi folks! I'm the data" ;
unsigned size = strlen( data ) ;
if (size > maxsize) return 0 ;
memcpy( buffer,data,size ) ;
return size ;
}
void main ()
{
std::vector<char> v ;
v.reserve( 50 ) ;
unsigned size = read_data( v.data(),v.capacity()) ;
v.force_actual_size( size ) ;
}
Here is the way I imagined : the data is actually written into the vector, but the vector's size is still 0.
So I need this force_actual_size method...
Is there a way implement it, or better, a clean way to do the same thing.
And of course, read_data comes from an old fashioned API I can't modify.
You can use std::vector::resize to allocate the memory you require and also correctly update the vector's size:
std::vector<char> v;
v.resize(50);
const auto new_size = read_data(v.data(), v.size());
v.resize(new_size);
Related
This probably me being extremely tired, but I can't figure out how to copy part of a vector into a new vector.
What I am trying to do, is find inside an std::vector (where char is typedefed as byte) where the starting tag is, and copy the data from there, up to the closing tag (which is at the end, and is 7 chars long).
typedef char byte;
std::vector<byte> imagebytes;
std::vector<byte> bytearray_;
for ( unsigned int i = 0; i < bytearray_.size(); i++ )
{
if ( (i + 5) < (bytearray_.size()-7) )
{
std::string temp ( &bytearray_[i], 5 );
if ( temp == "<IMG>" )
{
// This is what isn't working
std::copy( std::vector<byte>::iterator( bytearray_.begin() + i + 5 ),
std::vector<byte>::iterator( bytearray_.end() - 7 )
std::back_inserter( imagebytes) );
}
}
}
I know this loop looks horrible, I am open to suggestions!
Please note, bytearray_ contains raw bytes of images, or audio files. Hence the vector.
The answer is simple: just copy, don't loop. The loop is already inside std::copy.
typedef char byte;
std::vector<byte> imagebytes;
std::vector<byte> bytearray_;
// Contents of bytearray_ is assigned here.
// Assume bytearray_ is long enough.
std::copy(bytearray_.begin() + 5,
bytearray_.end() - 7,
std::back_inserter( imagebytes) );
Instead of copying you can also construct a new vector directly from the existing one:
std::vector<byte> imagebytes(bytearray_.begin() + i + 5, bytearray_.end() - 7);
I have a class with a std::vector<unsigned char> mPacket as a packet buffer (for sending UDP strings). There is a corresponding member variable mPacketNumber that keeps track of how many packets have been sent so far.
The first thing I do in the class is reserve space:
mPacket.reserve(400);
and then later, in a loop that runs while I want packets to get sent:
mPacket.clear(); //empty out the vector
long packetLength = 0; //keep track of packetLength for sending udp strings
memcpy(&mPacket[0], &&mPacketNumber, 4); //4 bytes because it's a long
packetLength += 4; //add 4 bytes to the packet length
memcpy(&mPacket[packetLength], &data, dataLength);
packetLength += dataLength;
udp.send(mPacket.data(), packetLength);
Except I realized that nothing was getting sent! How peculiar.
So I dug a bit deeper, and found that mPacket.size() returns zero, while packetLength returns the size I think the packet should be.
I can't think of a reason for mPacket to have zero length -- even if I'm mishandling the data, the header with mPacketNumber should have been written just fine.
Can anyone suggest why I'm running into this problem?
thanks!
The elements you reserve are not for normal use. The elements are created only if you resize the vector. While it might somehow look it works, it would be a different situation with types having constructors - you could see that the constructors were not called. This is undefined behaviour - you're accessing elements which you aren't allowed in this situation.
The .reserve() operation is normally used together with .push_back() to avoid reallocations, but this is not the case here.
The .size() is not modified if you use .reserve(). You should use .resize() instead.
Alternatively, you can use your copy operation together with .push_back() and .reserve(), but you need to drop the usage of memcpy, and instead use the std::copy together with std::back_inserter, which uses .push_back() to push the elements to the other container:
std::copy(reinterpret_cast<unsigned char*>(&mPacketNumber), reinterpret_cast<unsigned char*>(&mPacketNumber) + sizeof(mPacketNumber), std::back_inserter(mPacket))
std::copy(reinterpret_cast<unsigned char*>(&data), reinterpret_cast<unsigned char*>(&data) + dataLength, std::back_inserter(mPacket));
These reinterpret_casts are vexing, but the code still has one advantage - you won't get buffer overrun in case your estimate was too low.
vector, apparently, doesn't count the elements when you call size(). There's a counter variable inside the vector that holds that information, because vector has plenty of memory allocated and can't really know where the end of your data is. It changes counter variable as you add/remove elements using methods of vector object, because they are programmed to do so.
You added data directly to its array pointer, which awakens no reaction of your vector object because it does not use any of its methods. Data is there, but vector doesn't acknowledge it, so counter remains at 0 and size() returns 0.
You should either replace all size() calls with packageLength, or use methods inside your vector to add/remove/read data, or use a dynamically allocated array instead of a vector, or create your own class for containing array and managing it the way you like it. To be honest, using a vector in a situation like this doesn't really make sense.
Vector is a conventional high-level object-oriented component and in most os the cases it should be used that way.
Example of one's own Array class:
If you used your own dynamically allocated array, you'd have to remember its length all the time in order to use it. So lets create a class that will cut us some slack in that. This example has element transfer based on memcpy, and the [] notation works perfectly. It has an original max length, but extends itself when necessary.
Also, this is an in-line class. certain IDEs may ask of you to actually seperate it in header and source file, so you may have to do that yourself.
Add more methods yourself if necessary. When applying this, do not use memcpy unless you're going to change arraySize attribute manually. You've got integrated addFrom and addBytesFrom methods that use memcpy inside (assuming calling array being the destination) and separately increase arraySize. If you do want to use memcpy, setSize method can be used for forcing new array size without modifying the array.
#include <cstring>
//this way you can easily change types during coding in case you change your mind
//more conventional object-oriented method would use templates and generic programming, but lets not complicate too much now
typedef unsigned char type;
class Array {
private:
type *array;
long arraySize;
long allocAmount; //number of allocated bytes
long currentMaxSize; //number of allocated elements
//private call that extends memory taken by the array
bool reallocMore()
{
//preserve old data
type *temp = new type[currentMaxSize];
memcpy(temp, array, allocAmount);
long oldAmount = allocAmount;
//calculate new max size and number of allocation bytes
currentMaxSize *= 16;
allocAmount = currentMaxSize * sizeof(type);
//reallocate array and copy its elements back into it
delete[] array;
array = new type[currentMaxSize];
memcpy(array, temp, oldAmount);
//we no longer need temp to take space in out heap
delete[] temp;
//check if space was successfully allocated
if(array) return true;
else return false;
}
public:
//constructor
Array(bool huge)
{
if(huge) currentMaxSize = 1024 * 1024;
else currentMaxSize = 1024;
allocAmount = currentMaxSize * sizeof(type);
array = new type[currentMaxSize];
arraySize = 0;
}
//copy elements from another array and add to this one, updating arraySize
bool addFrom(void *src, long howMany)
{
//predict new array size and extend if larger than currentMaxSize
long newSize = howMany + arraySize;
while(true)
{
if(newSize > currentMaxSize)
{
bool result = reallocMore();
if(!result) return false;
}
else break;
}
//add new elements
memcpy(&array[arraySize], src, howMany * sizeof(type));
arraySize = newSize;
return true;
}
//copy BYTES from another array and add to this one, updating arraySize
bool addBytesFrom(void *src, long byteNumber)
{
//predict new array size and extend if larger than currentMaxSize
int typeSize = sizeof(type);
long howMany = byteNumber / typeSize;
if(byteNumber % typeSize != 0) howMany++;
long newSize = howMany + arraySize;
while(true)
{
if(newSize > currentMaxSize)
{
bool result = reallocMore();
if(!result) return false;
}
else break;
}
//add new elements
memcpy(&array[arraySize], src, byteNumber);
arraySize = newSize;
return true;
}
//clear the array as if it's just been made
bool clear(bool huge)
{
//huge >>> 1MB, not huge >>> 1KB
if(huge) currentMaxSize = 1024 * 1024;
else currentMaxSize = 1024;
allocAmount = currentMaxSize * sizeof(type);
delete[] array;
array = new type[currentMaxSize];
arraySize = 0;
}
//if you modify this array out of class, you must manually set the correct size
bool setSize(long newSize) {
while(true)
{
if(newSize > currentMaxSize)
{
bool result = reallocMore();
if(!result) return false;
}
else break;
}
arraySize = newSize;
}
//current number of elements
long size() {
return arraySize;
}
//current number of elements
long sizeInBytes() {
return arraySize * sizeof(type);
}
//this enables the usage of [] as in yourArray[i]
type& operator[](long i)
{
return array[i];
}
};
mPacket.reserve();
mPacket.resize(4 + dataLength); //call this first and copy into, you can get what you want
mPacket.clear(); //empty out the vector
long packetLength = 0; //keep track of packetLength for sending udp strings
memcpy(&mPacket[0], &&mPacketNumber, 4); //4 bytes because it's a long
packetLength += 4; //add 4 bytes to the packet length
memcpy(&mPacket[packetLength], &data, dataLength);
packetLength += dataLength;
udp.send(mPacket, packetLength);
I am trying to find out what is the easiest way to get a subset of C-Array if there are start and end points give.
Example: I have a class Trip:
class Trip
{
private:
char* final_destination;
char* description;
public:
//all constructors, operators and stuff
};
And, lets say I have an array of Trips:
Trip* trips = new Trip[10];
I am trying to write a function that takes the Trip array, starting point(given destination), end point(given destination) and return a subset of type Trip*.
E.g.
Trip* GetSubTrip(Trip* trips, char* start_point, char* end_point)
{
//Logics that returns Trip*
}
In other words, If I had:
[{"London", "Big Ben"}, {"New York", "Manhattan"}, {"Paris", "Eifell Tower"}, {"Moscow", "Lots of fun"}]
That would be the Trip* trips and "New York" as a start and "Moscow" as an end passed to the GetSubTrip I am trying to make it return Trip*.
And the return has to be:
[{"Paris", "Eifell Tower"}, {"Moscow", "Lots of fun"}]
What I do is:
In an integer counter I get the length between start and end
Create a new pointer Trip* and assign it with length of the counter from 1
Iterate over the 'trips' parameter and keeping a track if I am between start and end and if yes-> add the object to the result else procceed further.
But this is a lot of code. I am sure that there is much easier way.
EDIT:
It has to be done WITHOUT the use of VECTOR!
Using std::vector:
std::vector<Trip> route;
bool go = false;
for( int i=0; i<tripsSize /* trips[i] != TRIP_GUARD */; ++i )
{
if( go )
{
route.push_back( trips[i] );
if( trips[i] == end )
break;
}
else if( trips[i] == start )
go = true;
}
Why use std::vector? You don't have to keep the size of resulting array. You may modify it freely and conveniently. You don't have to worry about memory allocation for Trip objects.
In case you don't want to use std::vector you would need some sort of guard for both of your arrays (input and output one ) or to pass length of the array.
Without std::vector:
Trip * route;
int tripsNum;
int startNum, endNum;
for( int i=0; i<tripsSize /* trips[i] != TRIP_GUARD */; ++i )
{
if( trips[i] == start )
startNum = i;
else if( trips[i] == end )
{
endNum = i;
break;
}
}
tripsNum = endNum - startNum;
route = new Trip[ tripsNum ];
for( int i=startNum + 1, j=0; i<=endNum; ++i, ++j )
route[ j ] = trips [ i ];
Since you are using C++ you can consider using std::vector class instead of raw C arrays.
For raw C arrays you would need to keep the size (number of elements) of the array somewhere.
If you prefer arrays the solution depends on whether you are going to modify the original array/sub-arrays.
If you don't modify the Trips array, you can get the pointer to the sub-array with pointer arithmetic:
return trips + 2;//The returned pointer points to {"Paris", "Eifell Tower"}
You would also need to store the size of the sub-array.
If you do need to modify the original array (and/or sub-array), then you would have to create a copy (I would strongly suggest using vectors in that case). You might find this useful:
Best way to extract a subvector from a vector?
typedef struct pixel_type
{
unsigned char r;
unsigned char g;
unsigned char b;
} pixel;
buffer = (int *) malloc (sizeof(pixel) * stdin );
I keep getting an error that says "invalid operands to binary *(have unsigned int' and 'struct _IO_FILE *)." The struct is defined outside of a function so it is universal. The buffer is defined within the main. I can provide more code if needed. What is my problem?
EDIT: Alright so apparently I was a little confusing. What I'm trying to do is pass a file in, and then malloc enough space for that file. I was thinking of using a FILE function to pass the file in, and then using that, but was hoping to just use "stdin" instead. Is this not allowed? And this is in C. Just tagged C++ hoping someone else might see a similar problem.
Sorry for the silly question. Not new to C as a whole, but new to malloc. Second year student :P
I think you want to read the number of pixels from stdin:
int n;
scanf("%d", &n);
and then allocate memory for that many pixels:
unsigned char * buffer = (unsigned char *) malloc (sizeof(pixel) * n );
The right way to allocate the memory would be something like
size_t elements = 0;
... // get the number of elements as a separate operation
pixel *buffer = malloc( sizeof *buffer * elements ); // note no cast,
// operand of sizeof
if ( buffer )
{
// load your buffer here
}
In C, casting the result of malloc is considered bad practice1. It's unnecessary, since values of void * can be assigned to any pointer type, and under C89 compilers it can suppress a diagnostic if you forget to include stdlib.h or otherwise don't have a declaration for malloc in scope.
Also, since the expression *buffer has type pixel, the expression sizeof *buffer is equivalent to sizeof (pixel). This can save you some maintenance time if the type of buffer ever changes.
How you get the number of elements for your array really depends on your application. The easiest way would be to stick that value at the head of your data file:
size_t elements = 0;
FILE *data = fopen( "pixels.dat", "r" );
if ( !data )
{
// You will want to add real error handling here.
exit( 0 );
}
if ( fscanf( data, "%zu", &elements ) != 1 )
{
// You will want to add real error handling here
exit( 0 );
}
pixel *buffer = malloc( sizeof *buffer * elements );
if ( buffer )
{
for ( size_t i = 0; i < elements; i++ )
{
if ( fscanf( data, "%hhu %hhu %hhu", // %hhu for unsigned char
&buffer[i].r, &buffer[i].g, &buffer[i].b ) != 3 )
{
// more real error handling here
exit( 0 );
}
}
}
Naturally, this assumes that your data file is structured as rows of 3 integer values, like
10 20 30
40 50 60
etc.
1. As opposed to C++, where it's required, but if you're writing C++ you should be using the new operator anyway. Yes, you will see thousands of examples that include the cast. You will also see thousands of examples that use void main(). Most C references are simply crap.
void Example1( char* ArrayA, unsigned int Length )
{
if( ArrayA == 0 )
{
ArrayA = new char[ Length + 1 ];
// Fill it with 2 - whatever
::memset( ArrayA, 0x02, sizeof( char ) * Length );
ArrayA[ Length ] = '0\n';
}
// Do whatever with ArrayA
// Clean-Up
// Error occurs
delete [ ] ArrayA;
};
void Example2( char* ArrayB, unsigned int Length )
{
bool IsDynamic = false;
if( ArrayB == 0 )
{
ArrayB = new char[ Length + 1 ];
// Fill it with 2 - whatever
::memset( ArrayB, 0x02, sizeof( char ) * Length );
ArrayB[ Length ] = '0\n';
IsDynamic = true;
}
// Do whatever with ArrayA
// Clean-Up
// Have to check...
if( IsDynamic )
delete [ ] ArrayB;
};
int main( void )
{
Example1( "\x01\x02\0x03", 3 ); // Example1 WILL NOT* declare ArrayA as a dynamic array - ERROR (caused by deleting non dynamic array)
Example2( 0, 3 ); // ArrayB will be a dynamic array - OK
Example1( 0, 3 ); // OK
Example2( "\x04\x05\0x06", 3 ); // ArrayB isn't a dynamic array - OK
return ( 0 );
};
The problem occurs when attempting to delete char* ArrayA in function Example1 because ArrayA is not a dynamic array. It will only be a dynamic array if it is equal to zero/null. So, to resolve that I created a similar function - Example2. The only difference is that Example2 has a boolean that checks to see if char* ArrayB is a dynamic array or not.
I know what I am doing is either incorrect or "noobish". So please help me. I will learn from my mistake.
How would you do it?
void Example3( char* ArrayC, unsigned int Length );
Maybe you could use this:
void Example2( char* ArrayB, unsigned int Length )
{
std::vector< char > internalArray;
if ( ArrayB != 0 )
{
internalArray.assign( ArrayB, ArrayB + Length );
}
else
{
internalArray.resize( Length, 0x2 );
}
// Do whatever with internalArray !!! <-------
// No (!!!) clenup need
};
I know what I am doing is either incorrect or "noobish". So please help me.
My overall recommendation would be to move from using C arrays to using std::vector instead.
Your example1 is definitely bad, since it tries to free an array that isn't dynamically allocated - that is NEVER right. As explained elsewhere, if you call across a DLL boundary, you may also have different allocators, so if the memory was not allocated where it is being deleted, things will go wrong. Let whoever allocated it delete it. Preferrably by using already existing standard functionality, such as std::vector
Your example2 only uses delete on something that was created within the function, which is perfectly fine. It doesn't try to delete something that it doesn't know is allocated in the same allocator. Yet, a std::vector would certainly be easier to handle.