I need in C++ char array that is while initialiazing non-constant size. Size have to be non-constant cause it's generated from function and can't be used vector cause this char array will be used for reading and writing to files. Example:
int i = functionToGetvalue();
unsigned char ch[i];
file1 >> ch;
file2 << ch;
The premise is wrong. While there are reasons to prefer c-style arrays (or std::array) over vectors, yours is certainly not the one. You can certainly use std::vector to read and write to the file, since it is guaranteed to be contiguous in memory.
Example:
std::vector<char> vec;
vec.resize(255);
ssize_t sz = read(fd, vec.data(), vec.size());
In your original example, you are using formatted streams I/O, and in this case, std::string is a best tool:
std::string str;
file1 >> str; // reads up to the next white space into str
Related
I want to create a char array in a function from a string I have passed in.
bool foo(string s1, string s2) {
char s1_char_array[] = s1;
char s2_char_array[] = s2;
}
But I am met with
"Initialization with '{...}' expected for aggregate object."
For both declarations.
I've tried a lot of work arounds but they all have errors of their own. Learning C++ and every tutorial I find has the value hardcoded. How to make this work?
You can dynamically allocate arrays and copy data from the strings there.
#include <string>
#include <cstring> // for strcpy()
#include <algorithm> // for std::copy()
using std::string;
bool foo(string s1, string s2) {
// allocate arrays (+1 for terminating null-characters)
char* s1_char_array = new char[s1.size() + 1];
char* s2_char_array = new char[s2.size() + 1];
// copy data to arrays
#if 0
// if the strings are guaranteed not to contain '\0'
strcpy(s1_char_array, s1.c_str());
strcpy(s2_char_array, s2.c_str());
#else
// if the strings may contain '\0'
std::copy(s1.begin(), s1.end(), s1_char_array);
std::copy(s2.begin(), s2.end(), s2_char_array);
s1_char_array[s1.size()] = '\0';
s2_char_array[s2.size()] = '\0';
#endif
// do things with the arrays
// deallocate the arrays
delete[] s1_char_array;
delete[] s2_char_array;
// return something
return false;
}
The bad news is that there is no way to create an array variable from a std::string in general because std::string can represent strings of any size (very large practial limits exist but you'll run out of memory first on 64 bit systems) and that size is dynamic i.e. determined at run time. By contrast, the size of an array must be known at compile time at which time the size of the string is still unknown.
Another problem is that your arrays have automatic storage and the memory available for automatic storage is very limited - usually one to few megabytes on desktops / servers; potentially much less on embedded - while the dynamic memory owned by the string doesn't have such restriction and thus attempting to fit a large string into automatic storage could easily cause a "stack overflow".
Another issue is that arrays cannot be copy-constructed nor converted from other types so char s1_char_array[] = some_variable; can never work.
The good news is that you don't ever need to do that either. std::string already contains an array of chars internally, so there is no need to create a new array. Just keep using the array that is in the string.
this is what I come up with.
you have to declare the char array size same as strings by using string.lenght() function and
then use loops to copy the strings elements to char array index by index
bool foo(string s1, string s2) {
char s1_char_array[s1.length()] ;
char s2_char_array[s2.length()] ;
for(int i=0; i<s1.length(); i++){
s1_char_array[i]=s1[i];
}
for(int i=0; i<s2.length(); i++){
s2_char_array[i]=s1[i];
}
}
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 so new to C++ and I just can't figure out how to use any multidimesional arrays. I want to do something like that:
input number of product: number; //the products' name can be 7 with NULL char. (max 6)
char arr[number][7];
That works. But when I want to do that in a for loop(i):
cin>>arr[i][7];
and I don't know what the hell is compiler doing?
I just want that:
arr[0][7]=apple;
arr[1][7]=orange;
So please how can I do that?
#include <string>
#include <vector>
Since everybody is recommending it, I thought I'd sketch the options for you.
Note that you would have gotten this kind of answer in 10 milli-seconds by 3 different persons, if you had supplied a short, working sample code snippet (translating code 1:1 is more efficient than 'thinking up' examples that you might recognize)
Here you go:
std::vector<std::string> strings
strings.push_back("apple");
strings.push_back("banana");
// or
std::string s;
std::cin >> s; // a word
strings.push_back(s);
// or
std::getline(std::cin, s); // a whole line
strings.push_back(s);
// or:
// add #include <iterator>
// add #include <algorithm>
std::copy(std::istream_iterator<std::string>(std::cin),
std::istream_iterator<std::string>(),
std::back_inserter(strings));
Direct addressing is also possible:
std::vector<std::string> strings(10); // 10 empty strings
strings[7] = "seventh";
Edit in response to comments:
const char* eighth = "eighth";
if (strings[7] != eighth)
{
// not equal
}
// If you really **must** (read, no you don't) you can get a const char* for the string:
const char* sz = strings[7].c_str(); // warning:
// invalidated when `strings[7]` is modified/destructed
Unless you have a real reason (which you mustn't hide from us), make as Björn says and use a vector of strings. You can even do away with the initial request for the total size:
#include <string>
#include <vector>
#include <iostream>
std::vector<std::string> fruits;
std::string line;
while (std::getline(std::cin, line))
{
fruits.push_back(line);
}
Let's test:
std::cout << "You entered the following items:\n";
for (auto const & f : fruits) std::cout << "* " << f << "\n";
Because arr[i][7] is a char, and in fact one past the last element, which means you may get memory access error.
What you want to do maybe cin>>arr[i];.
How ever, this is not a very good idea, as you cannot control how many characters are read from input, which will easily cause memory overrun.
The easy way would be using std::vector<std::string> as others have suggested.
strcpy(&arr[0], "apple");
strcpy(&arr[1], "orange");
but for C++ is better to use std::vector<std::string> for array of strings
You have a two dimensional array of char
char arr[number][7];
And then trying to assign a string (char* or const char*) to them which will not work. What you can do here is assign a character, for example:
arr[0][1] = 'a';
If you can I would recommend using std::vector and std::string it would make things much clearer. In your case you could do
cin>>arr[i];
But I would not recommend it as you could only store up to 6 character char* strings (plus the null terminator). You can also have an array of char*
char* arr[number];
then dynamically allocate memory to store the strings.
Using std::vector and std::string will usually save you headaches once you understand them. Since you are brand new to C++, it might be useful to understand what is going on with two-dimensional arrays anyhow.
When you say
char array[N][M];
With N and M being constants, not variables, you are telling the compiler to allocate N*M items of type char. There will be a block of memory dedicated to that array of size N*M*sizeof(char). (You can declare an array of anything, not just char. Since sizeof(char) is 1, the memory will be N*M bytes long.) If you looked at raw memory, the first byte in the memory would be where array[0][0] is. The second byte would be where array[0][1] is, an so on, for M bytes. Then you would see array[1][0]. This is called row-major order.
As #jbat100 mentioned, when you say array[i][j] you are referring to a single character. When you say array[i], you are referring to the address of row i in the array. There is no pointer actually stored in memory, but when you say array[i] the compiler knows that you mean that you want the address of row i in the array:
char* row_i = array[i];
Now if i>0, then row_i points to somewhere in the middle of that block of memory dedicated to the array. This would do the same thing:
char* row_i = &array[i][0];
If you have a string, "orange" and you know that the length of it is less than M, you can store it in a given row in the array, like this:
strcpy(array[i], "orange"); // or
array[i][0] = 'o'; array[i][1] = 'a'; ... array[i][6] = 0;
Or you could have said row_i instead of array[i]. This copies 7 bytes into the array in the location of row_i. The strcpy() also copies an extra byte which is a 0, and this is the convention for terminating a character string in C and C++. So the 7 bytes are six bytes, 'o', 'r', 'a', 'n', 'g', and 'e', plus a 0 byte. Now strcmp(row_i, "orange") == 0.
Beware that if your string is longer than M, the strcpy and the simple char assignments will not (probably) produce a compile error, but you will end up copying part of your string into the next row.
Read about pointers and arrays in a good C/C++ book.
Pay attention to base64_decode in http://www.adp-gmbh.ch/cpp/common/base64.html
std::string base64_decode(std::string const& encoded_string)
The function is suppose to return byte array to indicate binary data. However, the function is returning std::string. My guess is that, the author is trying to avoid from perform explicit dynamic memory allocation.
I try to verify the output is correct.
int main()
{
unsigned char data[3];
data[0] = 0; data[1] = 1; data[2] = 2;
std::string encoded_string = base64_encode(data, 3);
// AAEC
std::cout << encoded_string << std::endl;
std::string decoded_string = base64_decode(encoded_string);
for (int i = 0; i < decoded_string.length(); i++) {
// 0, 1, 2
std::cout << (int)decoded_string.data()[i] << ", ";
}
std::cout << std::endl;
getchar();
}
The decoded output is correct. Just want to confirm, is it valid to std::string to hold binary data, to avoid manual dynamic memory management.
std::string s;
s += (char)0;
// s.length() will return 1.
Yes, you can store any sequence of char in a std::string. That includes any binary data.
Yes. std::string can hold any char value ('\0' has no special meaning). However I wouldn't be surprised finding some C++ functions (e.g. from external libraries) having problems with strings with embedded NULs.
Anyway I don't understand what you are going to gain with an std::string instead of std::vector<unsigned char> that would make your intentions more clear and that offers more guarantees (e.g. that all the bytes are in contiguous not-shared memory so that you can pass &x[0] to someone expecting a plain buffer for direct access).
I don't think it's completely valid.
Care must be taken with string and binary data because it uses internally char type and char depends in the implementation if it is defined as unsigned or signed type. I prefer to use basic_string<unsigned char> and be sure of what i'm reading.
I dont think one should use std::string for byte-data-storage. The method provide aren't design to deal with byte-data and you will risk yourself since any changes (or "optimization") on std::string will break your code.
it is better to use std::vector or std::vector (where byte is typedef to uint8 ) to express nature of data. You will no longer have string specific functions available , which is what you want for binary data
You need an array of character( not string) to store the binary data. Best is use vector.