initialize character array on the fly - c++

I want to initialize a char array using pointers, on the fly.That is user giving input do not know the size of array.User keeps on giving input until return is pressed.Condition here is to:
Use pointers to initialize
Not to pass size of array in advance.

Assuming a C question, how about (untested):
char *arr = malloc(10);
size_t size = 10, index = 0;
int ch;
while ((ch = getc(stdin)) != EOF && ch != '\n' && ch != '\r') {
if (index >= size) {
size *= 2;
arr = realloc(arr, size); /* XXX check it first. */
}
arr[index++] = ch;
}
arr[index] = 0;
If it's really a C++ question you want std::getline with a std::string.

The std::string has a method push_back also std::vector would do the job. Still if you are REALLY forced to use a dynamic array and char pointers I would advice you to implement reallocation strategy similar to the one used in vector - double the size each time the number of elements is more then the current size.

Related

C++ Dynamic Ragged Array

I have been trying to figure out this assignment for hours and can't grasp it yet. I'm trying to read in names from a txt document, which is working, and I need to store them in an char pointer array. Once the number of names is as big as the array size, I need to use REALLOCATION to make the array bigger (I can't use vector library).
I'm struggling with changing the name array size to make it bigger and deleting the old array from memory (it just crashes when I write delete [] names;).
Here is my currently broken code:
int numNames = 2;
char * names[numNames] = {};
ifstream namesFile("names.txt");
//get names from user, put names in ragged array
int i = 0;
while (i < numNames) {
if (namesFile.good() && !namesFile.eof()) {
//add name to ragged array
names[i] = new char[257];
namesFile >> setw(256) >> names[i];
i++;
if (i == numNames) {
//need a bigger array
numNames *= 2;
char * temp[20] = {};
for (int j = 0; j < numNames / 2; j++) {
temp[j] = names[j];
}
delete [] names;
names = temp;
}
}
else {
//end of file or corrupt file
break;
}
}
namesFile.close();
Any help is appreciated!
The following statement does not do any dynamic allocation. It just declares an array of pointers to char (char*) on a stack of size numNames. So, it is not dynamic by any means:
char * names[numNames] = {};
As such, you cannot change its size.
Instead you need to create a pointer to the array like the following:
char **names = new (char*)[numNames];
Same story for your temp down the road. Now you are free to delete/new and to assign pointers as well: names = temp.
Now, you need to read your char data from a file line by line and put it in the 'names' array. When you read a string, you can allocate space for it in the array member, i.e.
names[i] = new char [strlen(inputString) + 1]; // you need '+1' for termination char
and you can copy data from your string after allocation, i.e.
strcpy(name[i], inputString); // this is a standard 'c' string copy
you can also use std::copy or a for loop do do a copy or whatever. Another method is to use a standard 'c' malloc function to do allocation:
name[i] = (char *)malloc(strlen(inputString) + 1);
The difference is that when you would need to free memory, you would use delete[] name[i] in the first case and free(name[i]) in the second. Though it looks like you do not need to free the memory in your task.
Now you just have to figure out how to read from the file.

Filling and comparing char* inside a function

I wrote the function readChar() which is designed to read the characters send by my WiFi module one by one(function works has advertised) and pass them to a char buffer of increasing size. The function should stop when char *endChar (multiple characters) have been detected or the number of character returned by timedRead() has exceeded size_t length.
I have several issues:
1/. I don't understand the syntax (found inside the Arduino Stream library) :
*buffer++ = (char)c;
Can you explain how the array buffer gets filled?
And why buffer[index] = (char)c; doesn't work here?
2/. I would like to compare buffer and endChar in the loop, possibly by using strcmp(buffer,endChar) (maybe there is a better way). But that doesn't seem to work. In fact when printing the ASCII values of my char *buffer then seem to increment from the end of the buffer. E.G.:
So what is the best way to do that comparison?
The code, inserted in the loop:
_dbgSerial->println("buffer");
for (int i = 0; i < 32; i++){
_dbgSerial->print(buffer[i], DEC);
_dbgSerial->print(",");
}
_dbgSerial->println("");
prints:
buffer
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,10,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,10,13,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,10,13,10,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,10,13,10,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,10,13,10,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,10,13,10,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,10,13,10,0,0,0,0,
Here is the function readChar():
size_t Debugwifi::readChar(char *endChar, char *buffer, size_t length) {
if (length < 1) return 0;
size_t index = 0;
while (index < length) {
int c = timedRead();
if (c < 0 ) break;
//buffer[index] = (char)c;
*buffer++ = (char)c;
_dbgSerial->println("buffer");
for (int i = 0; i < 32; i++){
_dbgSerial->print(buffer[i], DEC);
_dbgSerial->print(",");
}
_dbgSerial->println("");
if (strcmp(buffer,endChar)==0) {
break;
_dbgSerial->println("brk");}
index++;
}
return index;
}
As Rickard has explained, *buffer++ = (char)c; is how you assign a character to the memory a pointer points at, and then increment the pointer.
However, your function has a lot of problems - you keep comparing unset memory with *endChar. I suggest:
size_t Debugwifi::readChar(const char * const endStr, // const pointer to const.
char * const buffer, const size_t length) {
if (length < 1) return 0;
const size_t endLen = strlen(endStr);
for (size_t index = 0; index < length; index++) {
const int c = timedRead();
if (c < 0 ) break;
buffer[index] = (char)c;
// Debug
_dbgSerial->println("buffer");
for (size_t i = 0; i < length; i++){ // Better to use size_t here,
// and compare against length not 32
_dbgSerial->print(buffer[i], DEC);
_dbgSerial->print(",");
}
_dbgSerial->println("");
// Finished?
if (index >= endLen) {
if (memcmp(&buffer[index-endLen], endStr, endLen)==0) {
_dbgSerial->println("brk"); // Must do this *before* "break"!
break;
}
}
}
return index;
}
I have added a lot of consts. It's hard to have too many.
The important point is that once you have read enough characters, to start comparing the last characters you have read to the end marker.
Note that this function does not remove the end marker, and if you pass a 32-byte zero-filled array and it reads 32 characters, the result will NOT be zero terminated.
Finally, I changed the argument name to endStr because I had expected endChar to be a pointer to a single character - not a NUL-terminated string.
*buffer++ = (char) c;
First writes the value of c to what buffer is currently pointing to.
Then it increments the buffer
This is also why your loop to print buffer doesn't work.
You start printing from the position after what was just filled.
This is also why your strcmp doesn't work. It doesn't actually compare what you have filled your buffer with. It compares the content beyond what have been filled.
If you want your printing code to work you should save the initial value of buffer before the loop;
const char *buffer_start = buffer;
Then use that in your printing code instead of buffer.

C++ How to remove double quotes in char

I want to remove double-quotes from a string, for example 13.3" Rentina becomes 13.3 Rentina
const char* s = sheet->readStr(row, col);
int ii = strlen(s);
char* b;
b=(char*)s;
char ch;
for (int i = 0; i < ii ;++i) {
strncpy(&ch, b+ii, 1);
if(ch == '\"'){
ch = '\"';
memcpy(b+i, &ch, 1);
}
}
myfile << b;
If you deal with strings in C++, you should use character arrays and functions like strncpy only when you have a strong reason to use them. By default you should use standard string, which makes e.g. memory management much easier. The solution to your problem with std::string is
std::string s = sheet->readStr(row, col);
size_t pos = 0;
while ((pos = s.find('"', pos)) != std::string::npos)
s = s.erase(pos, 1);
myfile << s;
You cannot do b=(char*)s!!!
The compiler lets you in on this one, but you will get a runtime exception as soon as you attempt to write into the memory address space pointed by b.
The variable s is possibly pointing to an address in the code-section, which is a read-only memory address space within your program ("possibly", because perhaps that const declaration of s is just something you added on your own initiative).
You should allocate a new char array, and copy the output string into that array instead.
So first of all, change the above statement to b = (char*)malloc(strlen(s)).
In addition, do not pass to strncpy (or any other str function for that matter) an address of a char variable. These functions operate on char arrays, and either assume that the array ends with a 0 character, or set the character at the end of the array to 0.
You can try the following piece of code (assuming that your purpose is to remove the '"'):
const char* s = sheet->readStr(row, col);
int ii = strlen(s);
char* b = (char*)malloc(ii+1);
if (b != NULL)
{
int i,j;
for(i=0,j=0; i<ii; i++)
{
if (s[i] != '"')
b[j++] = s[i];
}
b[j] = 0;
// Add your code here (do whatever you wanna do with 'b')
free(b);
}
else
{
printf("Out of memory\n");
}

Splitting char array into chunks quickly c++

Is there a faster/ more efficient way to split a char array into chunks (say 21 chars/ array) other than looping over the whole array?
This is my attempt right now
const char* arr = line.c_str();
char smallArr[(int)ceil((double)strlen(arr)/(double)21)][21];
int arrSisze[(int)ceil((double)strlen(arr)/(double)21)][1];
int m=0;int n=0;
for (int i=0; i<strlen(arr); i++) {
smallArr[m][i]=arr[i];
arrSisze[m][0]=(i+1)-n;
if ((i-n)==19) {
m++;
n+=20;
}
}
1) Using memcpy
char myname[] = "hello";
char dest[20] = {0};
/* using memcpy to copy string: */
memcpy ( dest, myname, 5);
2) using strncpy
char str1[]= "To be or not to be";
char str2[40];
strncpy ( str2, str1, sizeof(str2) );
Yes, pointer arithmetic and memcpy. However, seeing as you're using C++, let's stick to std::strings and assume they do a memcpy for us.
std::vector<std::string> output;
output.reserve(line.length() / 21 + (line.length() % 21) ? 1 : 0);
auto i = line.begin(), j = i + 21;
for(; line.end() - j > 21; i = j, j+= 21)
{
output.emplace(i, j)
}
if(j != line.end())
{
output.emplace(j, line.end());
}
So, what is going on here? For our purpose, it is good enough to think of a std::string as a char array and a length variable.
First, we reserve enough space for our output. You did this too.
Next, we define 2 variables i and j. i represents the beginning of the current substring and j the one-past-the-end iterator. Iterators here can be thought of as pointers into the internal structure of the string's char array - they may even be char*s!
We then iterate over the original string a line at a time. emplace just constructs a new element of a vector in the correct place. The call is equivalent to output.push_back(std::string(i, j)) and is only available in C++11.
To finish, we check whether there is another whole chunk using line.end() - j > 21; line.end() is the one-past-the-end iterator for the char array - it points at the NUL character (if there is one). If there is not a whole chunk, we check for a partial chunk using j != line.end().
Don't re-optimize the standard library.
If you have a std::string, just use it.
Don't use floating point for integer calculations: just use integer arthmetic porperly
the problem complexity is O(1). No other solution will cover it with less of one string walk span, and related copies
Use C++ properly, and forget C.
=
std::vector<std::string> chunks;
chunks.resize(21);
size_t chunksize = line.size()/21+1;
for(size_t i=0,j=0; i<line.size(); i+=chunksize, ++j)
{ chunks[j] = line.substr(i,chunksize); }
Note that sting::size takes N^0, while strlen takes N^1 complexity (it has a loop inside).
In this code, my loop is 21^1 on chunks and substr is (N/21)^1 each chunk content, giving N^1 on the whole length.
There is no need to track string length and null terminate the strings. All is handled by std::string class.

why char array's size is same using sizeof()

I meet a problem with the char array size. I pass an char array into the function and after run the function, I still want to use sizeof to check the size of the array, it won't give me the new size of the array, but the old size? I would like to know why? Thank you very much!
#include<iostream>
using namespace std;
void replacement(char* arr, int len){
int count=0;
for(int i=0; i<len; i++){
if(arr[i]==' '){
count++;
}
}
int newlen=count*2+len;
//arr[newlen]='\0';
int k=newlen-1;
for(int i=len-1; i>=0; i--){
if(arr[i]!=' '){
arr[k--]=arr[i];
}
else{
arr[k--]='0';
arr[k--]='2';
arr[k--]='%';
}
}
}
int main(){
char arr[]="ab c d e g ";
cout<<sizeof(arr)<<endl;
replacement(arr, sizeof(arr));
int i=0;
while(arr[i]!=NULL) cout<<arr[i];
}
You can't change an array's size. If you want to know the length of the string in the array, use strlen() -- this counts the number of characters before the null terminator.
Even better would be to use C++ std::string class.
Right, so you are trying to replace spaces with "%20", right?
Since C++ (or C) doesn't allow an existing array to be resized, you will either need to have enough space in the first place, or use an array allocated on the heap. Then allocate a new "replacement" string in the replacement function and return that.
The proper C++ method of doing this is of course to use std::string, in which case you could just pass it in as a reference, and do the replacement in the existing variable:
void replacement(std::string* str, int len){
std::string perc20 = "%20";
std::string space = " ";
while((pos = str.find(space, pos)) != std::string::npos)
{
str.replace(pos, space.length(), perc20);
pos += perc20.length();
}
}
Much easier...
You can use sizeof() to find the size of only static arrays when the size is known at compile time. Hence it will always return the size of the array as determined at compile time.
Your program technically has Undefined Behavior because your use of sizeof returns the size in bytes of your char array. But a char implicitly contains a null byte \0. That means the for loop is iterating 1 past the length of the array.
It's recommended that you use std::string along with its size member function instead.