I need to create a buffer that contains 300 symbols and pass it to the function described below:
void printThis(char *info);
What is the best way to generate this buffer?
If this is good:
char *buffer = new char()
then, how to add characters to this buffer? The following method is not good and it raises an access violation:
for (int i=0; i<300;i++)
{
sprintf(s,"%s",'a');
}
std::vector<char> buffer(300, 'a');
// I'm guessing that printThis wants a zero-terminated string
buffer.push_back(0);
printThis(&buffer[0]);
If you're using the C++11 library, then buffer.data() might look nicer than &buffer[0].
If you really want to manage the memory yourself (hint: you don't), either create an automatic array:
char buffer[300];
or a dynamic array:
char * buffer = new char[300];
// Don't forget to delete it, and hope than nothing threw an exception
delete [] buffer;
if this is good:
It isn't. It really, really, isn't. It's not even a buffer. Nor is this even close to a good idea.
std::string s;
for(int i = 0; i < 300; i++)
s.push_back('a'); // good job all round
std::cout << s; // 300*a. Why? Who knows?
printThis(s.c_str());
Related
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'm just studying C and C++ programming.
I've searched and can't seem to find an answer that has a decent response. Of course using <string> is much easier but for this task I am REQUIRED to use only clib <string.h> functions; I'm also not allowed to use C++11 functions.
I have the 2 variables below, and want to move the contents of buffer into c.
vector<char> buffer;
char* c = "";
How can I do this easily?
I have this so far but it obviously doesn't work, otherwise I wouldn't be here.
for (int b = 0; b < buffer.size(); b++)
{
c += &buffer[b];
}
The simplest way I can think of is;
std::vector<char> buffer;
// some code that places data into buffer
char *c = new char[buffer.size()];
std::copy(buffer.begin(), buffer.end(), c);
// use c
delete [] c;
std::copy() is available in the standard header <algorithm>.
This assumes the code that places data into buffer explicitly takes care of inserting any trailing characters with value zero ('\0') into the buffer. Without that, subsequent usage of c cannot assume the presence of the '\0' terminator.
If you want to ensure a trailing '\0' is present in c even if buffer does not contain one, then one approach is;
std::vector<char> buffer;
// some code that places data into buffer
char *c = new char[buffer.size() + 1]; // additional room for a trailing '\0'
std::copy(buffer.begin(), buffer.end(), c);
c[buffer.size()] = '\0';
// use c
delete [] c;
One could also be sneaky and use another vector;
std::vector<char> container;
// some code that places data into buffer
std::vector<char> v(container); // v is a copy of container
v.push_back('\0'); // if we need to ensure a trailing '\0'
char *c = &v[0]
// use c like a normal array of char
As long as the code that uses c does not do anything that will resize v, the usage of c in this case is exactly equivalent to the preceding examples. This has an advantage that v will be released when it passes out of scope (no need to remember to delete anything) but a potential disadvantage that c cannot be used after that point (since it will be a dangling pointer).
First, allocate space for the data by assigning c = new char[buffer.size()];
Then use memcpy to copy the data: memcpy(c, buffer.data(), buffer.size())
Your for loop would work in place of memcpy, too.
Also note that if vector<char> stays in place all the time when you use char*, and you are allowed to change the content of the vector, you could simply use the data behind the vector with a simple assignment, like this:
char *c = buffer.data();
I'm noticing some weird behavior when I create my char* of the given size is that it creates it bigger with some random "hereýýýý««««««««" values after my word
It looks like you do need a null-terminated C string after all. In this case you need to allocate one extra character at the end, and set it to zero:
char *c = new char[buffer.size()+1];
memcpy(c, buffer.data(), buffer.size());
c[buffer.size()] = 0;
You can do it in this way:
vector<char> buffer;
//I am assuming that buffer has some data
char *c = new char[buffer.size()+1];
for( int i=0; i<buffer.size(); i++ )
c[i] = buffer[i];
c[i] = '\0';
buffer.clear();
I'm reading the 3rd edition of The C++ Programming Language by Bjarne Stroustrup and attempting to complete all the exercises. I'm not sure how to approach exercise 13 from section 6.6, so I thought I'd turn to Stack Overflow for some insight. Here's the description of the problem:
Write a function cat() that takes two C-style string arguments and
returns a single string that is the concatenation of the arguments.
Use new to find store for the result.
Here's my code thus far, with question marks where I'm not sure what to do:
? cat(char first[], char second[])
{
char current = '';
int i = 0;
while (current != '\0')
{
current = first[i];
// somehow append current to whatever will eventually be returned
i++;
}
current = '';
i = 0;
while (current != '\0')
{
current = second[i];
// somehow append current to whatever will eventually be returned
i++;
}
return ?
}
int main(int argc, char* argv[])
{
char first[] = "Hello, ";
char second[] = "World!";
? = cat(first, second);
return 0;
}
And here are my questions:
How do I use new to find store? Am I expected to do something like std::string* result = new std::string; or should I be using new to create another C-style string somehow?
Related to the previous question, what should I return from cat()? I assume it will need to be a pointer if I must use new. But a pointer to what?
Although the problem doesn't mention using delete to free memory, I know I should because I will have used new to allocate. Should I just delete at the end of main, right before returning?
How do I use new to find store? Am I expected to do something like std::string* result = new std::string; or should I be using new to create another C-style string somehow?
The latter; the method takes C-style strings and nothing in the text suggests that it should return anything else. The prototype of the function should thus be char* cat(char const*, char const*). Of course this is not how you’d normally write functions; manual memory management is completely taboo in modern C++ because it’s so error-prone.
Although the problem doesn't mention using delete to free memory, I know I should because I will have used new to allocate. Should I just delete at the end of main, right before returning?
In this exercise, yes. In the real world, no: like I said above, this is completely taboo. In reality you would return a std::string and not allocate memory using new. If you find yourself manually allocating memory (and assuming it’s for good reason), you’d put that memory not in a raw pointer but a smart pointer – std::unique_ptr or std::shared_ptr.
In a "real" program, yes, you would use std::string. It sounds like this example wants you to use a C string instead.
So maybe something like this:
char * cat(char first[], char second[])
{
char *result = new char[strlen(first) + strlen(second) + 1];
...
Q: How do you "append"?
A: Just write everything in "first" to "result".
As soon as you're done, then continue by writing everything in "second" to result (starting where you left off). When you're done, make sure to append '\0' at the end.
You are supposed to return a C style string, so you can't use std::string (or at least, that's not "in the spirit of the question"). Yes, you should use new to make a C-style string.
You should return the C-style string you generated... So, the pointer to the first character of your newly created string.
Correct, you should delete the result at the end. I expect it may be ignored, as in this particular case, it probably doesn't matter that much - but for completeness/correctness, you should.
Here's some old code I dug up from a project of mine a while back:
char* mergeChar(char* text1, char* text2){
//Find the length of the first text
int alen = 0;
while(text1[alen] != '\0')
alen++;
//Find the length of the second text
int blen = 0;
while(text2[blen] != '\0')
blen++;
//Copy the first text
char* newchar = new char[alen + blen + 1];
for(int a = 0; a < alen; a++){
newchar[a] = text1[a];
}
//Copy the second text
for(int b = 0; b < blen; b++)
newchar[alen + b] = text2[b];
//Null terminate!
newchar[alen + blen] = '\0';
return newchar;
}
Generally, in a 'real' program, you'll be expected to use std::string, though. Make sure you delete[] newchar later!
What the exercise means is to use new in order to allocate memory. "Find store" is phrased weirdly, but in fact that's what it does. You tell it how much store you need, it finds an available block of memory that you can use, and returns its address.
It doesn't look like the exercise wants you to use std::string. It sounds like you need to return a char*. So the function prototype should be:
char* cat(const char first[], const char second[]);
Note the const specifier. It's important so that you'll be able to pass string literals as arguments.
So without giving the code out straight away, what you need to do is determine how big the resulting char* string should be, allocate the required amount using new, copy the two source strings into the newly allocated space, and return it.
Note that you normally don't do this kind of memory management manually in C++ (you use std::string instead), but it's still important to know about it, which is why the reason for this exercise.
It seems like you need to use new to allocate memory for a string, and then return the pointer. Therefore the return type of cat would be `char*.
You could do do something like this:
int n = 0;
int k = 0;
//also can use strlen
while( first[n] != '\0' )
n ++ ;
while( second[k] != '\0' )
k ++ ;
//now, the allocation
char* joint = new char[n+k+1]; //+1 for a '\0'
//and for example memcpy for joining
memcpy(joint, first, n );
memcpy(joint+n, second, k+1); //also copying the null
return joint;
It is telling you to do this the C way pretty much:
#include <cstring>
char *cat (const char *s1, const char *s2)
{
// Learn to explore your library a bit, and
// you'll see that there is no need for a loop
// to determine the lengths. Anything C string
// related is in <cstring>.
//
size_t len_s1 = std::strlen(s1);
size_t len_s2 = std::strlen(s2);
char *dst;
// You have the lengths.
// Now use `new` to allocate storage for dst.
/*
* There's a faster way to copy C strings
* than looping, especially when you
* know the lengths...
*
* Use a reference to determine what functions
* in <cstring> COPY values.
* Add code before the return statement to
* do this, and you will have your answer.
*
* Note: remember that C strings are zero
* terminated!
*/
return dst;
}
Don't forget to use the correct operator when you go to free the memory allocated. Otherwise you'll have a memory leak.
Happy coding! :-)
I need an array to store char arrays of variable size. I could use vectors or anything else, but unfortunately this is for a MPI project and I am forced to use an array so I can send it using MPI::COMM_WORLD.Send(...) function.
My idea comes from this link.
This is a simplified example of the problem I have:
char* arrayStorage[3]; //I want to store 3 char arrays of variable size!
int index = 0;
char array_1[RANDOM_SIZE] = {.....};
char array_2[RANDOM_SIZE] = {.....};
char array_3[RANDOM_SIZE] = {.....};
arraySorage[index] = array_1;
index++;
arraySorage[index] = array_2;
index++;
arraySorage[index] = array_3;
index++;
I have also seen people talking about malloc and stuff like that, but I don't know much about pointers. I do malloc, I have to call free and I don't know where, so I am avoiding that for now.
This code obviously doesn't work, array_1, array_2, array_3 are all OK, but when I try to access them I get garbage. The problem seems to be inside the index variable. Maybe I shouldn't be doing index++, perhaps I should be doing index += RANDOM_SIZE, but that also fails.
How can I store variable size char arrays in an array?
Use malloc and free (or new and delete in C++). You can do it with vectors too - as vectors can be treated as arrays.
char *str = "hello world";
// need the +1 for null character
arraySorage[0] = (char *)malloc (strlen(str) + 1);
strcpy(arraySorage[0], str);
...
free(arraySorage[0]);
with new/delete
arraySorage[0] = new char[strlen(str)+1];
strcpy(arraySorage[0], str);
...
delete arraySorage[0];
Using vector and std::string is the correct C++ way, for lots of reasons, including not leaking memory and proper handling of exceptions.
Okay the previous question was answered clearly, but i found out another problem.
What if I do:
char *test(int ran){
char *ret = new char[ran];
// process...
return ret;
}
And then run it:
for(int i = 0; i < 100000000; i++){
string str = test(rand()%10000000+10000000);
// process...
// no need to delete str anymore? string destructor does it for me here?
}
So after converting the char* to string, I don't have to worry about the deleting anymore?
Edit: As answered, I have to delete[] each new[] call, but on my case its not possible since the pointer got lost, so the question is: how do I convert char to string properly?
Here you are not converting the char* to a [std::]string, but copying the char* to a [std::]string.
As a rule of thumb, for every new there should be a delete.
In this case, you'll need to store a copy of the pointer and delete it when you're done:
char* temp = test(rand()%10000000+10000000);
string str = temp;
delete[] temp;
You seem to be under the impresison that passing a char* into std::string transfers ownership of the allocated memory. In fact it just makes a copy.
The easiest way to solve this is to just use a std::string throughout the entire function and return it directly.
std::string test(int ran){
std::string ret;
ret.resize(ran - 1); // If accessing by individual character, or not if using the entire string at once.
// process... (omit adding the null terminator)
return ret;
}
Yes, yes you do.
If you are using linux/os x, look into something like valgrind which can help you with memory issues
You can change your test function so that it returns a string instead of char *, this way you can delete [] ret in the test function.
OR you could just use a string in test as well and not have to worry about new/delete.
You must call delete for every new otherwise you will leak memory. In the case you have shown you are throwing away the pointer, if you must leave the function as returning a char* then you will need to use two lines to create the std::string so you can retain a copy of the char* to delete.
A better solution would be to rewrite your test() function to return a std::string directly.
You need to do something like this:
for(int i = 0; i < 100000000; i++){
int length = rand()%10000000+10000000;
char* tmp = test(length);
string str(tmp);
delete[length] tmp;
}
This deletes the allocated char-array properly.
By the way, you should always zero-terminate a string if you create it this way (i.e. inside the function test), otherwise some functions can easily get "confused" and treat data behind your string as part of it, which in the best case crashes your application, and in the worst case creating a silent buffer overflow leading to undefined behaviour at a later point, which is the ultimate debugging nightmare... ;)