std::copy from vector's position to vector's position - c++

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);

Related

Populate a vector<char> in an old fashioned (and dirty) way

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);

invalid operands to binary *

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.

C++ Checking if param dynamic array. Is it necessary?

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.

Null Pointer issue using string::iterator in Visual Studio 2005

I am working with some legacy code. The legacy code works in production mode in the following scenario. I'm trying to build a command line version of the legacy code for testing purposes. I suspect there is an environmental setting issue at work here, but I'm relatively new to C++ and Visual Studio (long time eclipse/java guy).
This code is attempting to read in a string from a stream. It reads in a short, which in my debug scenario has a value of 11. Then, it is supposed to read in 11 chars. But this code craps out on the first char. Specifically, in the read method below, ptr is null, and so the fread call is throwing an exception. Why is ptr NULL?
Point of clarification, ptr becomes null between the operator>>(string) and operator>>(char) calls.
Mystream& Mystream::operator>>( string& str )
{
string::iterator it;
short length;
*this >> length;
if( length >= 0 )
{
str.resize( length );
for ( it = str.begin(); it != str.end(); ++it )
{
*this >> *it;
}
}
return *this;
}
The method for reading the short is here and looking at the file buffer etc. this looks like it is working properly.
Mystream& Mystream::operator>>(short& n )
{
read( ( char* )&n, sizeof( n ) );
SwapBytes( *this, ( char* )&n, sizeof( n ) );
return *this;
}
Now, the method for reading in a char is here:
Mystream& Mystream::operator>>(char& n )
{
read( ( char* )&n, sizeof( n ) );
return *this;
}
and the read method is:
Mystream& Mystream::read( char* ptr, int n )
{
fread( (void*)ptr, (size_t)1, (size_t)n, fp );
return *this;
}
One thing I don't understand, in the string input method, the *it is a char right? So why does the operator>>(char &n) method get dispatched on that line? In the debugger, it looks like the *it is a 0, (although a colleague tells me he doesn't trust the 2005 debugger on such things) and thus, it looks like the &n is treated as a null pointer and so the read method is throwing an exception.
Any insights you can provide would be most helpful!
Thanks
John
ps. For the curious, Swap Bytes looks like this:
inline void SwapBytes( Mystream& bfs, char * ptr, int nbyte, int nelem = 1)
{
// do we need to swap bytes?
if( bfs.byteOrder() != SYSBYTEORDER )
DoSwapBytesReally( bfs, ptr, nbyte, nelem );
}
And DoSwapBytesReally looks like:
void DoSwapBytesReally( Mystream& bfs, char * ptr, int nbyte, int nelem )
{
// if the byte order of the file
// does not match the system byte order
// then the bytes should be swapped
int i, n;
char temp;
#ifndef _DOSPOINTERS_
char *ptr1, *ptr2;
#else _DOSPOINTERS_
char huge *ptr1, huge *ptr2;
#endif _DOSPOINTERS_
int nbyte2;
nbyte2 = nbyte/2;
for ( n = 0; n < nelem; n++ )
{
ptr1 = ptr;
ptr2 = ptr1 + nbyte - 1;
for ( i = 0; i < nbyte2; i++ )
{
temp = *ptr1;
*ptr1++ = *ptr2;
*ptr2-- = temp;
}
ptr += nbyte;
}
}
I'd throw out this mess and start over. Extrapolating from the code, if what you had actually worked, it would be roughly equivalent to something like this:
MyStream::operator>>(string &s) {
short size;
fread((void *)&size, sizeof(size), 1, fP);
size = ntohs(size); // oops: after reading edited question, this is really wrong.
s.resize(size);
fread((void *)&s[0], 1, size, fp);
return *this;
}
In this case, delegating most of the work to other functions doesn't seem to have gained much -- this does the work more directly, but still isn't significantly longer or more complex than the original (if anything, I'd say rather the opposite).
I found a gray beard in the company who could explain what's going on to me. (I had already spoken to 2 old timers so I figured I had covered the old timer avenue of attack.) The code above is not ANSI compliant STL code. In Visual Studio 2005, Microsoft first introduced STL and there were issues. In particular older code that used to work would now fail in 2005 (I think 64bit mode may play a role in this as well.) Because of this, code will not work in debug mode (but it will work in release mode). One partial article is located here.
http://msdn.microsoft.com/en-us/library/aa985982%28v=vs.80%29.aspx
The particular issue I saw has to do with the line: it = str.begin() in the first method in the question. str is an empty string. So str.begin() is technically not defined. Visual Studio treats this situation differently between debug and release modes. (Can't do this in debug, you can do it in release.)
Bottom line, the gray beard suggested rewrite was exactly Jerry's. Ironically, the gray beard had fixed this problem in several files, but neglected to check it into the mainline. Uh oh. That scares the &#$!! out of me.

How to push char array? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
How do I use arrays in C++?
I have no idea how to push a char array.
For example if i have "HI.MY.NAME.IS" in a char array,
I would like to put one char in the middle and push the char's right to it.
So it would be something like "HI.MY.SLAME.IS" or something like that.
Any possible solutions?
Use string::insert.
std::string s("test");
s.insert(s.begin()+2, 'c');
There is no "automatic" push which relocates elements in an array. At the lowest levels, there is only read from an array element and write to an array element.
That means you need to copy each element after the insert "one index" down the array. Then you need to set the "inserted" value at its inserted index.
Library routines will do this for you without you noticing; however, you should be aware of the underlying mechanism. Otherwise, you might fall under the impression that inserting into arrays at arbitrary indexes is cheap (when it usually isn't).
//This allocates new memory that you receive responsibility for freeing after use.
char *push(char *charArray, char *charsToPush, int pushPos) {
char *thePushed = new char[strlen(charArray) + strlen(charsToPush) + 1];
memcpy(thePushed, charArray, pushPos);
memcpy(thePushed + pushPos, charsToPush, strlen(charsToPush));
memcpy(thePushed + pushPos + strlen(charsToPush), charArray + pushPos, strlen(charArray) - pushPos);
thePushed[strlen(charArray) + strlen(charsToPush)] = '\0';
return thePushed;
}
To do that you'd have to:
Create a new array that is large enough to hold the original and the new items. Arrays cannot be resized.
Copy all items from the old to the new array, leaving the places for the new characters open.
Insert the new characters.
This is quite complex. But C++ offers a simpler way - std::string:
#include <string>
#include <iostream>
int main() {
std::string text = "HI.MY.NAME.IS";
std::string new_text = text.substr(0, 6) + "SL" + text.substr(7, 6);
std::cout << new_text << std::endl;
}
This program prints HI.MY.SLAME.IS. Or, even better, use insert, as #rasmus suggests.
If you are limited to c-strings or require it to be replaced in-buffer, then you can do something like the below, but your buffer must be large enough to hold the modified string since it's pushing all characters down. That said, you'd be much better off using the std::string as the others suggest.
// ASSUMES buffer is large enough to store one more char
void insertAt(char* buffer, char insertMe, size_t at)
{
size_t len = strlen(buffer);
if (at <= len)
{
memcpy(buffer + at + 1, buffer + at, len - at + 1);
buffer[at] = insertMe;
}
}
char* string = (char*) malloc(14);
string = "HI.MY.NAME.IS";
realloc(string, 15);
for (int i = 14; i > 5; --i) {
string[i+1] = string[i];
}
string[5] = 'S';
string[6] = 'L';
Here you go...lol