C++ cin to c string dynamic allocation - c++

Trying to figure out the reasoning behind the mechanics of c strings.
char** text;
text = new char*[5];
for(int i = 0; int < 5; int++) {
cout << endl << "Enter a phrase: ";
cin >> text[i];
cout << text[i];
}
I'm not entirely sure as to why this works for the first 2 iterations, even successfully displaying them, but gets a segfault error on the 3rd iteration.

You are using uninitialized memory. You are experiencing undefined behavior.
The line
text = new char*[5];
allocated memory for five pointers but those pointers haven't been initialized to point to anything valid. Before you can use text[i] to read data, you have to allocate memory for it.
for(int i = 0; int < 5; int++) {
cout << endl << "Enter a phrase: ";
text[i] = new char[SOME_SIZE_LARGE_ENOUGH_FOR_YOUR_NEED];
cin >> text[i];
cout << text[i];
}
Then, it should work.

You've allocated memory for 5 pointers, but you are not allocating anything that those five pointers point to. Assuming that you're using a modern 64-bit CPU with 8 byte-wide pointers, your new operator allocated exactly 40 bytes, five eight-byte pointers. Their initial contents are random, uninitialized memory, and when you write to them, they get interpreted as pointers to random memory addresses, which end up being corrupted with what you've read from std::cin. You got lucky initially, and the first two iterations scribbled over some memory somewhere, but your program continued to limp along, but you won the lottery on the third try; hitting a random address that does not exist, and segfaulting.
Although you can rewrite this to do proper allocation, if you're really trying to write C++, rather than C, here, there's no reason to allocate anything. Why do you want to deal with allocating memory, when C++ will happily do it for you?
std::vector<std::string> text;
for(int i = 0; int < 5; int++)
{
std::cout << std::endl << "Enter a phrase: ";
std::string s;
if (std::getline(std::cin, s).eof())
break;
text.push_back(s);
std::cout << s << std::endl;
}

Related

Why does assigning a value to a string in a struct crash the program?

I have commented out the problematic string, attempted to pass the input to a string that is not a member of the struct, then passing it to the correct string, to no avail. To achieve the intended function, the string must go through this struct. Where is it going wrong?
Structure code:
#include <iostream>
#include <string>
#include <fstream>
#include <iomanip>
using namespace std;
class passingdata
{
public:
passingdata()
{
//constructor
};
~passingdata()
{
//destructor
};
int convertedResponse;
const string headers[4] = {"Labor/Materials", "Cost (per unit)", "Total Units", "Total Cost"}; //this is all to be written to a file later.
struct dynInputs
{
string name;
int perCost;
int unitTotal;
int totalCost = perCost * unitTotal;
};
void acceptInputs()
{
string name = "";
string response = "";
const string positiveResponse = "yes";
cout << "Would you like to insert a label?" << endl;
getline(cin, response);
if (response == positiveResponse)
{
populateSaveData();
}
else
{
//nothing yet
}
}
void populateSaveData()
{
if (convertedResponse = 1)
{
cout << "How many labels would you like to create?" << endl;
int labelCount;
cin >> labelCount;
cin.clear();
int labelsNeeded = labelCount;
dynInputs* dynamicInputs;
dynamicInputs = new dynInputs[labelsNeeded];
while (labelsNeeded > 0)
{
cout << "please type the name for this row" << endl;
cin.ignore();
//string tempName = "";
//getline(cin, tempName); this works!
getline(cin, dynamicInputs[labelsNeeded].name); //this breaks, goes to trash memory when done this way
system("pause");
cin.clear();
//tempName = dynamicInputs[labelsNeeded].name; breaks as well
cout << dynamicInputs[labelsNeeded].name << endl;
//cout << tempName << endl;
system("pause");
cout << "please type the cost of the unit, and the number of units" << endl;
cin >> dynamicInputs[labelsNeeded].perCost;
cin.clear();
cin >> dynamicInputs[labelsNeeded].unitTotal;
cin.clear();
labelsNeeded--;
}
cout << dynamicInputs[0].unitTotal << endl;
The dynamicInputs[labelsNeeded] array points to junk memory, yet I'm unsure of why it only crashes assigning value to the string.
In labelsNeeded you store the size of the array.
Then in the first iteration you use labelsNeeded to index into your array. Since C++ indexes an array starting from 0, the largest possible valid index is (the size of the array) - 1.
Eg.: For an array of size 4, your valid index range is [0, 1, 2, 3].
Now what you are doing is setting labelsNeeded to equal labelCount and then allocate an array of the size equalig labelsNeeded. And then in the first iteration you use the value of labelsNeeded as an index with this original value for accessing an element in your array. Which goes past the valid range of your array. Hence the program crashes.
I see that at the and of the iteration you decrement labelsNeeded but that is too late considering that you already tried to use the original value earlier in the code.
Your labelsNeeded > 0 condition for your while loop is also incorrect if you are using this "decrement the index at the end of the iteration" solution since it will fail to write the first (at index 0) element of your array.
Try moving the labelsNeeded-- line to the beginning of the iteration.
Note:
As to "why it only crashes assigning value to the string".
C++ (or rather the runtime) does not care whether your pointer points to a valid address or not. Simply because a pointer is just a memory address. By it self it is just a number stored in memory. A pointer that references invalid memory will only crash your program (or do other weird stuff) if you want to dereference it or in other words -> If you want to actually use the pointer to access that place in memory. It is not the "invalid" memory address in the pointer that crashes but the act of trying to access the memory at that address. The distinction may look subtle but is very important nonetheless. You can have any number of "null pointers" in the program as long as you don't try to dereference null.
Note 2:
Yours is an especially interesting mode of failure since it can fail in one of two places:
Since you are indexing an element that is one past the end of the array, that may as well coincide with the end of the heap that was assigned to the program. So it may crash there. But... Most likely your array is not allocated in such a place and there will still be accessible heap past the end of your array so dereferencing one element past your array may as well give you "something" and by something I mean some memory content cast to the type that you have. But of course from your point of view that is some random data.
If execution survived the previous section and now you have a struct with random data, you also have your string in your struct that is also filled with random garbage. Which means its pointer to the actual string content is also random (most likely pointing somewhere before or past your addressable space) as well as its size and other state information also being garbage. So if you reassign that string then its original content pointer will likely be accessed (eg.: deallocation) which will result in a crash.

Problem with declaring a dynamic array of pointers to strings

While performing a practice assignment online I came across a problem which I am not able to solve.
The user has to a number(number of sentences he will be entering) and then proceed to enter the sentences one by one, which are to be stored as strings(by the way, declaring a dynamic array of pointers is mandatory). However, since the number of sentences is not a priori deducible, I know that the size of the array of pointers actually is the number of sentences but I can't figure out how to declare a dynamic array of pointers to strings.
Using something I had already known beforehand, I figured out how to do the same but with arrays of characters, not arrays of strings. The line that declared a dynamic array of pointers to dynamic arrays of chars looked like this:
char **ptr=new char*[n] {};
So with my understanding, this creates a pointer ptr which points to a dynamic array of pointers, the elements of which each point to one array of characters. I want to do something similar now, where the result should be that ptr is a pointer to a dynamic array of pointers, the elements of which each point to a string.
Can anyone help out? I'd be thankful!
I think what you are looking for is something like
std::size_t num;
std::cout << "enter the number of sentences\n";
std::cin >> num;
std::string *sentences = new std::string[num];
for(std::size_t i=0; i!=num; ++i) {
std::cout << "enter the " << (i+1) << "th sentence\n";
std::cin >> sentences[i];
}
/*
... (do something with the sentences, accessing them as sentences[i])
*/
delete[] sentences; // free the memory
Note that this style of coding is highly discouraged. The problem is the need to manage the allocated memory: avoid memory leaks and dangling pointers (including exception safety). The correct approach is to use a container or smart pointer. For example:
std::size_t num;
std::cout << "enter the number of sentences\n";
std::cin >> num;
std::vector<std::string> sentences{num};
for(std::size_t i=0; i!=num; ++i) {
std::cout << "enter the " << (i+1) << "th sentence\n";
std::cin >> sentences[i];
}
/*
... (do something with the sentences, accessing them as sentences[i])
*/
or
std::size_t num;
std::cout << "enter the number of sentences\n";
std::cin >> num;
std::unique_ptr<std::string[]> sentences{new std::string[num]};
for(std::size_t i=0; i!=num; ++i) {
std::cout << "enter the " << (i+1) << "th sentence\n";
std::cin >> sentences[i];
}
/*
... (do something with the sentences, accessing them as sentences[i])
*/
when in both cases you don't have to worry about calling delete: the allocated memory will be automatically deleted (even if an exception occurs).
You can avoid pointers completely and use
std::vector<std::string> input;
A std::array needs to know the size at compile time, and you learn this at runtime. The vector works like an array but can have items push_backed at runtime.
You could declare pointer to some strings, using n once you know it:
std::string * pInputs = new std::string[n];
but it's easier to use the vector.
Each pInput will be a string, as with the std::vector version.

Entering value to dynamically allocated memory at runtime

Following is the code I wrote for reading a value at run time to dynamically allocated memory:
void main()
{
clrscr();
int *p = new int[5];
int *a = new int();
cin >> *a; // **line 5**
cout << *a << "\n"; // **line 6**
cout << &p; // line 7
cout << *p; // line 8
cout << "\nEnter 5 no for array\n";
for (int i = 0; i <= 4; i++)
{
cout << &p[i] << " :- ";
cin >> p[i]; // LINE 12
}
for (i = 0; i <= 4; i++)
cout << "\n" << p[i]; // LINE 16
delete[] p;
delete a;
getch();
}
I would like to know that while entering data for user in integer, we have to use *a with cin and cout for entering data in line 5 & 6 but in case of array we just gave the pointer variable name in line 12 & 16. Can anyone please tell me why we are having this difference?
Moreover can anyone also please tell me the difference between output of line 7 & 8.
You don't "have to"; you could have written cin >> a[0].
For built-in types and pointers and such, a[b] is *(a+b) is *(b+a) is b[a] and you can interchange them all.
It's only convention that leads to a choice. Like generally if you'd allocated more than one int you'd use "array notation" (a[i]) and if you'd allocated only one int you'd use a straight-up dereference (*(a+0), or *a).
But the language doesn't really care how many elements you allocated because either way you just have a pointer to "one or more" consecutive elements.
tl;dr this is just how the syntax was designed.
As for your second question, &p and *p give different results because they mean different things, and I'll leave discerning that difference as an exercise to the reader.

C++ char/string reading problem

Again, I'm trying to make a simple program. It will read some kind of board, at the size of RxC. Each items on the board are letters, separated with spaces. This is a sample board:
A B C
D E F
G H I
After that, it will read an integer N, and for next N lines, read a string and process them one by one based on the given board. But now, I'm facing a problem with how to read them. Here is the code :
#include<iostream>
using namespace std;
int r,c,el; char **arr;
int main()
{
char *tes;
int n;
//start reading the puzzle
cin >> r >> c; el=r;
cout << el << endl;
arr = new char * [3*(r+c)-6];
for(int i=0;i<r;i++)
{
arr[i] = new char[c+1];
for(int j=0;j<c;j++) cin >> arr[i][j];
arr[i][c] = '\0';
}
for(int i=0;i<el;i++) cout << arr[i] << endl;
cin >> n;
while(n>0)
{
n--;
cin >> tes;
cout << tes << endl;
}
}
I don't know what's wrong with this, it's seems OK to me. However, it always get runtime errors. I'm using latest MinGW and gdb debugger. On gdb I saw something like
"received signal SIGSEGV. Segmentation
fault"
, and an 0xC0000005 error. I really have no idea what's going on here. I've tried both iostream(cin&cout) and cstdio(scanf,puts,etc.)
P.S.: I declare the variables globally, because I will process them on a different function out of the main() function. I set the size of the "height" of the array to (3*(r+c)-6), not to the normal (r) is because I will use the same array to store another strings later.
In addition to the problems already noted by others, you haven't allocated any memory for tes - it's just a dangling pointer.
Change:
char *tes;
to, e.g.:
char tes[80];
A board of size R*C needs, not very surprisingly, r*c chars of storage. I fail to understand why you're allocating the board in so many steps. A single char* board = new char[r * c]; should do it, then just keep track of where in the array your're reading.
Segmentation fault usually means you are trying to access memory which hasn't been allocated, for instance
char* mystr = (char*)malloc(3*sizeof(char));
mystr[4] = 0.0;
will (most likely) cause a seg fault because you're accessing memory which you didn't allocate (mystr goes from 0 - 2).
Are you sure you're allocating the memory correctly? I'm not sure why you have 3*(r+c)-6.
Further to unwind's answer, your array has size 3*(r+c)-6, but you are looping over values i = 0; i < r;, which depending on the values may just run out of bounds (plus it makes no sense).

Can I do a multidimensional char array in c++?

First off, this is a "homework" question so vector libraries and string libraries are off limits. I'm trying to get to the basics of c++.
My intention with this code is to make and use an array of string arrays. A list of words in other words.
When I run this code I get a bunch of nonsense.
If there is a better way to make a list of words in c++, I would love to hear about it.
const int cart_length = 50;
const int word_length = 50;
int main()
{
char cart_of_names[cart_length][word_length];
float cart_of_costs[cart_length];
char name[word_length];
cout << "enter the name of the first item: ";
cin >> name;
for(int i=0; i<word_length; i++)
{
cart_of_names[0][i] = name[i];
}
cout << endl;
cout << "that is: ";
for(int x=0; x<word_length; x++)
{
cout << cart_of_names[0][x];
}
cout << endl;
return 0;
}
If the string entered is not 50 characters long (cart_length), then less than 50 characters will be valid in the name. You should have an if(cart_of_names[0][x]==0) break; in your second loop.
I don't exactly understand what you are looking for. Following code will help you to read and print a list of 50 words. Hope this would help you.
const int cart_length = 50;
const int word_length = 50;
int main()
{
char cart_of_names[cart_length][word_length];
float cart_of_costs[cart_length];
for(int i=0; i<cart_length; i++)
{
cout << "enter the name of the " << i + 1 << "th item: ";
cin >> cart_of_names[i];
}
cout << "that is: ";
for(int x=0; x < cart_length; x++)
{
cout << cart_of_names[x] << endl;
}
return 0;
}
Check out STLSoft's fixed_array_2d (and it's higher order siblings). There's a detailed discussion of how they're implemented for maximum performance in Matthew Wilson's Imperfect C++.
If you can't use std::string, at least look at the functions like strncpy() from C for your name copying. Also, you're forgetting that c-style strings are null terminated.
Unless you're forbidden to use STL (which would be just mean), just use std::list<std::string>. www.cplusplus.com has detailed descriptions and examples for those classes.
Otherwise, you're stuck with an array of char arrays: in that case, be prepared for a lot of buffer overflow errors. Look around on the above site for the char[] management functions (strncpy() and the like), they'll make your life a bit easier (but not a lot).
In C, the best way I found to conceptualize what you are trying to do is using an array of char*. Same effect, but if you start to work with it I believe you may find it is easier on the brain.
It looks pretty close to me. Strings in C are null-terminated, which means that the end of the string is indicated by a null character. In a sense, a string in C is really just an array of bytes.
When you do:
cout << "enter the name of the first item: ";
cin >> name;
If I enter the string "Book", in memory it'll look like something like:
|0|1|2|3|4|5..49|
|B|o|o|k|0|*HERE BE DRAGONS*
Well, really it will contain the ASCII values corresponding to those letters, but for our purposes, it contains those letters. There here be dragons is memory that that you didn't initialize, so it contains whatever garbage your platform sets it to.
So when you copy your string, you need to instead look for that 0 byte at the end of the string.
for(int i=0; name[i]!=0; i++)
{
cart_of_names[0][i] = name[i];
}
Then when you output it, you don't actually need to do it a character at a time. You can just do cout<<cart_of_names[0]. cout knows where the string ends because of that terminating null character.
If you use strcpy() instead of
cart_of_names[0][i] = name[i];
it may work better but I cringe just looking at all that code.
"If there is a better way to make a list of words in c++, I would love to hear about it."
Include #include <string> and use std::string. The std::string type is part of the C++ specification, I think.
#include <iostream>
#include <string>
int main(void) {
std::string list[7];
list[0] = "In C++";
list[1] = "you can use";
list[2] = "the `std::string` type.";
list[3] = "It removes";
list[4] = "many of the problems";
list[5] = "introduced by";
list[6] = "C-style strings.";
for (int k=0; k<7; k++) std::cout << list[k] << ' ';
std::cout << '\n';
return 0;
}