dynamic memory allocation of strings in cpp - c++

so here's the thing I've been working on a code for 5 hours now and logic looks good the program seems to do it's job, the only thing that keeps bugging me is dynamic memory allocation of strings. The question does not specify the initial number of strings user has to enter. Here's what I've been trying to do to dynamically take the strings :
int t;
cin>>t //number of strings user wishes enter
char *s1[1000009]; //1000009 is the maximum number of digits each string can have
for(i=0;i<t;i++)
{
s1[i]=(char *)malloc(1000009)
cin>>s1[i];
}
not sure if it is the right way or not. A way through which i could store a 2D character array would also do if not dynamic strings.
Thanking you,
gaurav

Use a vector of strings instead of using malloc/new.
int t;
std::cin >> t;
std::vector<std::string> strings(t); //Create t strings
for(int i = 0; i < t; i++)
std::cin >> strings[i]; //Read into each string

Since you tagged this question as C++ I would do it like this:
std::vector<std::string> s1(1000009);
That's all - no need to use malloc, no need to take care about destruction.
If you are using C++ use the Tools you have available.

i would do it like this :
int i = 0;
char **s1;
s1 = (char **)malloc(t * sizeof(char *));
while (i < t)
{
s1[i] = (char *)malloc(1000009 * sizeof(char));
i++;
}
the first malloc create you t line.
The second one fill alloc 100000009charactere for each lines

Related

Not able to input strings using getline() .It is reading only one string

char* name[4];
int j=0;
while(cin.getline(name[j],80))//input given:you(ent)me(ent)he(ent)she
cout<<name[j++];
this code is reading only one string upto one newline.should'nt it read all 4 strings and print them ?and is this a good way to input string using getline?
Problem: You are not allocating the memory properly. You are declaring an array of pointers not an array of c style strings.
Possible Solutions: You need to read about pointers and memory allocation first. You can either allocate memory first to each of the four pointers that you declared name[0], name[1], name[2], and name[3] using the following code:
char* name[4];
for (int i = 0; i < 4; i++)
{
name[i] = new char[80];
}
OR you can use a 2D array for which the code is posted below:
char name[4][80];
int j=0;
while(j<4 && cin.getline(name[j],80))
{
cout<<name[j++];
}
I made a bit of correction. And it works on my computer.
char* name[4];
for (int i = 0; i < 4; i++)
name[i] = new char[80];
int j = 0;
while (j < 4)
{
cin.getline(name[j], 80); //input given:you(ent)me(ent)he(ent)she
cout << name[j++] << endl;
}
You need to read some more about pointers, arrays and memory management in C++ i guess. You try to operate on C array of strings, but you didn't initialize it properly. You need to allocate memory before you use such pointers. Currently your program results in UB so you are actually really lucky that it did anything same at all.
Another issue is that, when you reach the end of your input, when j=4, you will still attempt to perform cin(getline(name[j], 80) but you are passing the name[4] as a parameter, which may be a cause of another UB, even if you allocate the memory correctly beforehand.
Other then that you are writing in C++, so use C++ string and vector instead of C arrays.
This is easily done with strings and std::getline:
#include <iostream>
#include <vector>
using namespace std;
int main(){
vector<string> names;
string name;
while(getline(cin, name)){
names.push_back(name);
cout<<name<<endl;
}
return 0;
}

c++ read into c-style string one char at a time?

in c++ id like to read input into a c-style string one character at a time. how do you do this without first creating a char array with a set size (you don't know how many chars the user will enter). And since you can't resize the array, how is this done? I was thinking something along these lines, but this does not work.
char words[1];
int count = 0;
char c;
while(cin.get(c))
{
words[count] = c;
char temp[count+1];
count++;
words = temp;
delete[] temp;
}
Since you cannot use std::vector, I am assuming you cannot use std::string either. If you can use std::string, you can the solution provide by the answer by #ilia.
Without that, your only option is to:
Use a pointer that points to dynamically allocated memory.
Keep track of the size of the allocated array. If the number of characters to be stored exceeds the current size, increase the array size, allocate new memory, copy the contents from the old memory to new memory, delete old memory, use the new memory.
Delete the allocated memory at the end of the function.
Here's what I suggest:
#include <iostream>
int main()
{
size_t currentSize = 10;
// Always make space for the terminating null character.
char* words = new char[currentSize+1];
size_t count = 0;
char c;
while(std::cin.get(c))
{
if ( count == currentSize )
{
// Allocate memory to hold more data.
size_t newSize = currentSize*2;
char* temp = new char[newSize+1];
// Copy the contents from the old location to the new location.
for ( size_t i = 0; i < currentSize; ++i )
{
temp[i] = words[i];
}
// Delete the old memory.
delete [] words;
// Use the new memory
words = temp;
currentSize = newSize;
}
words[count] = c;
count++;
}
// Terminate the string with a null character.
words[count] = '\0';
std::cout << words << std::endl;
// Deallocate the memory.
delete [] words;
}
You asked for C-style array. Stack or dynamic allocation will not serve you in this case. You need to change the count of the array number in each time you add new element which is not possible automatically. You have to work around and delete and reserve the array each time a new chae is read. So you have to options:
Use std::vector (which was created for this purpose)
Duplicate what is inside std::vector and write it yourself during your code( which seems terrible)
std::vector solution:
std::vector<char> words;
words.reserve(ESTIMATED_COUNT); // if you you do not the estimated count just delete this line
char c;
while(cin.get(c)){
words.push_back(c);
}
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s1;
char c;
while (cin.get(c))
{
if (c == '\n')
continue;
s1 += c;
cout << "s1 is: " << s1.c_str() << endl; //s1.c_str() returns c style string
}
}
You have two ways, first is to use an zero size array, after each input you delete the array and allocate a new one that is +1 bigger, then store the input. This uses less memory but inefficient. (In C, you can use realloc to improve efficiency)
Second is to use a buffer, for example you store read input in a fixed size array and when it get full, you append the buffer at the end of main array (by deleting and re-allocating).
By the way, you can use std::vector which grows the size of itself automatically and efficiently.
If you're set on using c-style strings then:
char* words;
int count = 0;
char c;
while(cin.get(c))
{
// Create a new array and store the value at the end.
char* temp = new char[++count];
temp[count - 1] = c;
// Copy over the previous values. Notice the -1.
// You could also replace this FOR loop with a memcpy().
for(int i = 0; i < count - 1; i++)
temp[i] = words[i];
// Delete the data in the old memory location.
delete[] words;
// Point to the newly updated memory location.
words = temp;
}
I would do what Humam Helfawi suggested and use std::vector<char> since you are using C++, it will make your life easier. The implementation above is basically the less elegant version of vector. If you don't know the size before hand then you will have to resize memory.
You need to allocate a string buffer of arbitrary size. Then, if the maximum number of characters is reached upon appending, you need to enlarge the buffer with realloc.
In order to avoid calling realloc at each character, which is not optimal, a growth strategy is recommended, such as doubling the size at each allocation. There are even more fine-tuned growth strategies, which depend on the platform.
Then, at the end, you may use realloc to trim the buffer to the exact number of appended bytes, if necessary.

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.

stack-overflow in string decleration [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Very large array on the heap (Visual C++)
i need to declare 10 strings each of length 100000 characters long.
int main(void)
{
long t;
cin>>t;
string str[10][100000];
for(long i=0;i<=t;i++)
{
getline(cin,str[i][100000]);
}
for(long i=1;i<=t;i++)
{
getStringSize(str[i][100000]);
}
system("PAUSE");
}
i wrote the code in VC++ but as soon as i compile the code i have a stack overflow.
if i keep the size of the string to str[10][10000] then the code works great. what do i need to make to code work?
This is not how you declare ten strings of 10,000 characters each - you declared a 2D array of strings, 10x10000.
This is how you do it the C++ way if you want each string to have 10,000 characters:
vector<string> str(10, string(100000, ' '));
Note that you need to specify the character that you want repeated 10,000 times. Since std::string is designed to grow dynamically, you can skip the 10,000 part altogether: the library will allocate as much memory as it needs.
vector<string> str(10);
You can also use array in C++11.
You need to allocate the memory dynamically: the stack in your case is not big enough to hold that much data
const size_t len = 10;
string* str[len];
for(long i=0; i<len; ++i) {
str[i] = new string[100000];
}
Note: Don't forget to delete the allocated memory when you no longer need it.
Note: To make life easier, use an appropriate container (e.g. vector<>) that does the memory management for you automatically
Update: your code has some other problems too:
for(long i=0;i<=t;i++) // t could be lager than 9
{
getline(cin,str[i][100000]); // you are accessing a non-existent element
}
Try instead:
long t;
cin>>t;
vector<string> str; // declare an auto-resizing container of strings
for(long i=0; i<t; i++)
{
string tmp; // this string will be able to store a lot of characters by itself
getline(cin, tmp); // read in the next line
str.push_back(tmp); // add the line to our container
}
for(long i=0; i<t; i++)
{
// do something with str[i] // values str[0]..str[t-1] are guaranteed to be valid
}
You need to allocate memory in heap. Like this..
string *str[10];
for(int i = 0; i < 10; i++)
str[i] = new string[100000];
If you use std::string then it's not fixed length - that's the whole point. what you maybe want is:
char str[10][100000];
which would give you 10 x char[100000]. As it stands you've got a matrix of 10 x 100000 strings.

Some problem using pointers to enter a string

I'm a beginner and i need to ask a question..
I wrote this small code that accepts a string from the user and prints it..very simple.
#include <iostream>
using namespace std;
int main()
{
int i;
char *p = new char[1];
for(i = 0 ; *(p+i) ; i++)
*(p+i) = getchar();
*(p+i) = 0;
for(i = 0 ; *(p+i) ; i++)
putchar(*(p+i));
return 0;
}
when i enter any string..like "stack overflow" for example..it will print "sta" and drop the rest of the string. I know it's an easy one to solve but since I've just started i can't understand what's wrong here . Thanks in advance .
There are several problems with this code. First, you have a buffer overflow, because char *p = new char[1] allocates only one character for storage. This is exceeded when i > 0. Next, your first loop will keep going until it reaches a point in unallocated memory (undefined behavior) that has a value of zero. This just happens to be after the third value in your case. You probably wanted something more like *(p+i-1) == 0 to give "the last character read meets some condition." Finally, you're allocating memory with new[] and not properly deallocating it with a matching delete[].
Consider using std::cin and std::string for much safer and correct code:
#include <iostream>
#include <string>
int main(int, char**) {
std::string s;
std::cout << "Enter a string: ";
std::cin >> s;
std::cout << s << std::endl;
}
Here is some code along your lines that seems to work. I'm sure there are better (and more C++-ish) ways to do this...
#include <iostream>
using namespace std;
#define MAXLEN 80
int main()
{
int i=0;
char c;
char *p = new char[MAXLEN + 1]; // 1 char will not be sufficient
do // Doing this with a for loop would be unreadable
{
c = getchar();
*(p+i) = c;
i++;
} while( c != '\n' && i < MAXLEN ); // Check for a newline. How do you enter the zero with a keyboard?
*(p+i) = 0; // Ensure that the last character is zero
for(i = 0 ; *(p+i) ; i++) putchar(*(p+i)); // This is OK but difficult to read
delete [] p; // Don't forget this
return 0;
}
The fact that your program does anything is just luck; what stops *(p+i) from being \0 to begin with? It's weird that you're using getchar() and putchar() in a C++ program, too. What's the story behind this program?
If you read into memory, be sure that you allocate enough. new char[1] creates an array of only one char, but you are reading more then that. A simple temporary fix would be to simply allocate more, say new char[255].
Other notes:
you never delete the memory you allocated: delete[] p;
you should check wether you read as much characters as your buffer can hold: for(..;.. && i<bufferSize;..)
the condition in the first loop always checks the next character, not what you just read
*(p+i) is equivalent to p[i], which is more readable
why read and write only one character at a time?
why not use iostreams (std::in, std::out) and std::string as you are using C++?
you only allocate space for one character but you try to put many chars in it.
Is this homework? if so please tag it as such. Are you allowed to use STL?
If so then use std::vector instead on new char[1];
EDIT:to do it without any fiddly bits or STL
const int MAX = 100;
char *p=new char[MAX];
for(i = 0 ; *(p+i) && i < MAX ; i++)
*(p+i) = getchar();
probably some out by ones - left as exercise