Had this program in C and was trying to convert some to C++ as I learn the language. Basically char arrays to strings and some of the input/output. Only issue is I get a segfault when attempting to put the input string into the string array (test2 prints. test3 does not).
Any ideas? Any bad coding habits I should be aware of as I learn c++?
int main() {
int nstr=0, nchar=0, nint=0, nfloat=0;
string input;
int i, z=0;
float inputFloat;
string *strList = (string*)malloc(sizeof(string) * nstr);
char *charList = (char*)malloc(sizeof(char) * nchar);
int *intList = (int*)malloc(sizeof(int) * nint);
float *floatList = (float*)malloc(sizeof(float) * nfloat);
while (z != -42) {
cout << "Input: ";
cin >> input;
cin.ignore();
inputFloat = strtof(input.c_str(), NULL);
if (inputFloat) {
if (fmod(inputFloat, 1.0)) {
nfloat++;
floatList = (float*)realloc(floatList, sizeof(float) * nfloat);
floatList[nfloat-1] = inputFloat;
}
else {
nint++;
intList = (int*)realloc(intList, sizeof(int) * nint);
intList[nint-1] = (int)inputFloat;
}
}
else {
if (input.length() == 1) {
nchar++;
charList = (char*)realloc(charList, sizeof(char) * nchar);
if (input.at(0) == 10)
input = " ";
charList[nchar-1] = input.at(0);
}
else {
nstr++;
cout << "test1" << endl;
strList = (string*)realloc(strList, sizeof(string) * nstr);
cout << "test2" << endl;
strList[nstr-1] = input;
cout << "test3" << endl;
}
}
cout << "Integers: ";
for (i=0; i<nint; i++)
cout << intList[i] << " ";
cout << endl << " Floats: ";
for (i=0; i<nfloat; i++)
cout << floatList[i] << " ";
cout << endl << " Chars: ";
for (i=0; i<nchar; i++)
cout << charList[i] << " ";
cout << endl << " Strings: ";
for (i=0; i<nstr; i++)
cout << strList[i] << " ";
cout << endl << endl;
}
}
As a rule you don't use malloc,calloc,realloc etc. in c++ at all, even though you can.
It less meaningful for simple items like: int, char etc. but when using on objects (like std::string) it cause this kind of problems:
When this line runs:
string *strList = (string*)malloc(sizeof(string) * nstr);
You allocate storage to array of strings, but you didn't called any constructor, therefor all the storage you've allocated is still useless.
In c++ you must use new like this:
string *strList = new string[nstr];
it is shorter, easier and call the constructor of each allocated object.
In the end you dealocate it with delete [] like this:
delete [] strList;
Even better is to use:
vector<string> strList;
and add elements by using:
strList.push_back("something"); or strList.push_back(some_string);
vectors are take care for the memory allocation and free, and are freed automatically as regular object at end of life, so it won't needed to be deleted at all.
realloc reassigns a larger array than the previous one. The new element at the end of the array, you fill it as a integer, float, char , which are basic C types. For C++ objects like strings, the last element in your array is not a new string, one of the possibilities is to create arrays of string pointers.
at the start of your code
string **strList = (string**)malloc(sizeof(string *) * nstr);
and by the end of your code, allocate a new string object at the end of the array.
nstr++;
strList = (string**)realloc(strList, sizeof(string *) * nstr);
strList[nstr-1] = new string(input);
at the end of the program you must delete everything you created through new operator and thru malloc/realloc.
while (nstr--)
{
delete strList[nstr];
}
free(strList);
Related
I am getting error from cin >> theGift.m_wrap[i].m_pattern; part. I am new to C++. How do I store the patterns that the user enters? For example:
Enter wrapping pattern #1: Spots
Enter wrapping pattern #2: Stripes
Enter wrapping pattern #3: Zigzags
also, how would I access these?
struct Wrapping {
char m_pattern[MAX_WRAP];
};
struct Gift {
char m_description[MAX_DESC + 1];
double m_price;
int m_units;
int m_wrapLayers = 0;
Wrapping* m_wrap = new Wrapping[m_wrapLayers];
};
bool wrap(Gift& theGift){
if (theGift.m_wrapLayers == 0) {
cout << "Wrapping gifts..." << endl;
do {
cout << "Enter the number of wrapping layers for the Gift: ";
cin >> theGift.m_wrapLayers;
}while ((theGift.m_wrapLayers <= 0) && cout << "Layers at minimum must be 1, try again." << endl);
for (int i = 0; i < theGift.m_wrapLayers; i++) {
cout << "Enter wrapping pattern #" << i + 1 << ": ";
cin >> theGift.m_wrap[i].m_pattern;
}
return true;
}else {
cout << "Gift is already wrapped!" << endl;
return false;
}
}
Wrapping* m_wrap = new Wrapping[m_wrapLayers];
This line heap-allocates an array of zero elements because m_wrapLayers is zero at the moment this allocation happens. You never reallocate the array, so attempting to access any element of this array is undefined behavior since no elements exist.
You should be using std::vector which is a dynamically-sized container that does all of the following for you:
Makes a memory allocation to hold elements.
Reallocates when attempting to add an element to a full vector, copying over the old values.
Copies itself properly.
Deallocates memory when it's destroyed.
Right now you only do the first step, and you make an allocation that can't hold anything.
Vectors also know how many elements they hold, so you don't need to track that separately.
Additionally, you should use std::string instead of character arrays for strings. std::string is much like a vector of chars; it will grow as necessary.
I would redefine your types like this:
struct Wrapping {
std::string m_pattern;
};
struct Gift {
std::string m_description;
double m_price;
int m_units;
std::vector<Wrapping> m_wrap;
};
Then your code to populate the vector goes like this:
int layers;
do {
cout << "Enter the number of wrapping layers for the Gift: ";
} while ((!(cin >> layers) || layers <= 0) && cout << "Layers at minimum must be 1, try again." << endl);
for (int i = 0; i < layers; i++) {
cout << "Enter wrapping pattern #" << (i + 1) << ": ";
theGift.m_wrap.emplace_back();
cin >> theGift.m_wrap.back().m_pattern;
}
I am learning the basics of C++. The code is working fine as I wanted, but what I want to know is in case 2 where the function is to swap the strings, what is basically going on? Is the string at array[pos1 -1] being copied to temp and then swapped or just the addresses of the strings to be swapped are being reallocated?
#include <iostream>
using namespace std;
int main()
{
const char *array[] {"Albert",
"Newton",
"Gallilio",
"Hawking"};
cout << "What do you want to do:\n1-Display Strings\n2-Swap Positions" << endl;
unsigned short int choice{};
cin >> choice;
switch (choice)
{
case 1:
{
for (short int i = 0; i < _countof(array); i++)
{
cout << "\n" << array[i];
}
cout << endl;
break;
}
case 2:
{
short int pos1{}, pos2{};
const char *temp{ nullptr };
cout << "Whom do you want to swap? Enter two numbers when prompted: " << endl;
cout << "Swap --- "; cin >> pos1;
cout << "With --- "; cin >> pos2;
temp = array[pos1 - 1];
array[pos1 - 1] = array[pos2 - 1];
array[pos2 - 1] = temp;
cout << "\nChanged Order is";
for (short int i{} ; i < _countof(array); i++)
{
cout << "\n" << array[i];
}
cout << endl;
break;
}
default:
cout << "\a";
}
return 0;
}
Let's assume pos1 is 1 and pos2 is 2.
Then array[pos1-1] holds a pointer to a character A that is interpreted as a string of characters Albert\0 terminated by a null. Likewise array[pos2-1] holds a pointer to the string Newton\0.
When case 2 is hit, temp is initialized to hold a null pointer. Then temp is assigned to hold a copy of the pointer to Albert\0. Then array[pos1-1] is reassigned to hold a pointer to Newton\0. We then want array[pos2-1] to point to Albert\0, but the pointer value in array[pos1-1] doens't point there anymore. That's where the copy in temp comes in, because it is still a pointer to Albert\0, so this pointer is copied to array[pos2-1].
forum!
I have a project where we are supposed to add numbers that are length 14 or greater. I did some digging and realized that there is no current type that takes numbers this big. So, I have the user enter the numbers as a string and the numbers they would like to add are stored in a static string array.
I would like to add the numbers from the static array together. The issue is I have no idea how to deal with numbers this large. I am assuming you would have to convert the string values into int's and add them up one by one? I am having a big issue coming up with the logic for this. Any help would be appreciated.
If not, if you can provide some context which could help me come up with some logic.
The only library functions I can use is iostream and string.
Here is my code if you'll like to see my logic! I have some test cases I am trying to figure out so please ignore the comment outs. But, if you run the code you should get a better sense of what I am trying to get out. I am trying to sum up the numbers the user enters.
#include <iostream>
#include <string>
using namespace std;
void amountOfNumbers(string &userAmount, int MIN_AMOUNT, int MAX_AMOUNT){
//string alpha = "abcdefghijklmnopqrstuvwxyz";
cout << "How many numbers? -> ";
cin >> userAmount;
cout << endl;
while(!userAmount.find("abcdefghijklmnopqrstuvwxyz")){
cout << "ERROR: must be a number, try again ->";
cout << userAmount;
//cin.clear();
//cin.ignore(1000, '\n');
cin >> userAmount;
cout << endl;
}
int temp = stoi(userAmount);
while((temp < MIN_AMOUNT) or (temp > MAX_AMOUNT)){
cout << "ERROR: Program can only take in " << MIN_AMOUNT << " - "<< MAX_AMOUNT << " numbers. Try again ->";
cin >> userAmount;
cout << endl;
temp = stoi(userAmount);
}
}
void takeNumbers(string &userAmount, string (&numberArray)[11]){
int temp = stoi(userAmount);
for (int i = 0; i < temp; i++){
cout << "Input number #" << i+1 << " ->";
cin >> numberArray[i];
cout << endl;
}
}
void display(string &userAmount, string (&numberArray)[11]){
int temp = stoi(userAmount);
for (int i = 0; i < temp; i++){
cout << numberArray[i];
cout << endl;
}
}
void addNumber(string &userAmount, string (&numberArray)[11]){
}
int main() {
const int MIN_AMOUNT = 2, MAX_AMOUNT = 11, MAX_INPUT = 14;
string userAmount = "0";
string numberInput;
// static array
string numberArray [MAX_AMOUNT];
amountOfNumbers(userAmount, MIN_AMOUNT, MAX_AMOUNT);
takeNumbers(userAmount, numberArray);
display(userAmount, numberArray);
}
I am very much a beginner at C++, and I've been trying for the past 6 hours to try to figure out how to get the number of characters in a dynamic array.
This is the code I have:
using namespace std;
int array_size;
typedef char* charPtr;
charPtr a = new char[array_size];
char *p=a;
int len(char p[]) {
int count = 0;
while (*p != '\0'); {
count++;
p++;
return count;
}
}
int main() {
cout << "Type a phrase" << endl;
cin >> array_size;
cout << "Your phrase was " << len(p) << " characters long." << endl;
return 0;
}
Any help would be greatly appreciated!
You have to remove the semicolon (;) after the temination condition of your while loop. ; is the end of an statement, after that a new statment beginns. Apart from this your return statement would be inside the while loop. Remove it outside the loop. Adapt your code like this:
int len(char p[]) {
int count = 0;
while (*p != '\0')
{
count++;
p++;
}
return count;
}
Further you have to read a string from input into your dynamicly allocated array of char:
int main() {
int array_size = 100;
char *p=new char[array_size]; // allocate memory
cout << "Type a phrase" << endl;
cin >> p; // read string into allocated memory
cout << "Your phrase was " << len(p) << " characters long." << endl;
delete p; // free memory
return 0;
}
The function strlen gives you the length of a \0-terminated string.
#include <string.h>
int main() {
int array_size = 100;
char *p=new char[array_size]; // allocate memory
cout << "Type a phrase" << endl;
cin >> p; // read string into allocated memory
cout << "Your phrase was " << strlen(p) << " characters long." << endl;
delete p; // free memory
return 0;
}
But I recommend to use std::string:
#include <string>
int main() {
std::string str;
cout << "Type a phrase" << endl;
cin >> str;
cout << "Your phrase was " << str.size() << " characters long." << endl;
return 0;
}
std::string represents a sequences of characters with dynamic length.
Getting the size of dynamically allocated array
A dynamically allocated array does not have any information about its size that is available in a standards compliant way.
We are able to compute the length of C style strings since there is sentinel element, '\0', to mark the end of the string. There are no such elements for other types.
Even then, you cannot compute the size of an array of characters allocated using heap memory like you have.
Problems with posted code
You have the following lines outside all functions.
int array_size;
typedef char* charPtr;
charPtr a = new char[array_size];
char *p=a;
They are executed before anything in main gets executed. When these lines are executed, array_size gets initialized to 0. Then you allocate memory for charPtr using 0 as the value of array_size.
Function len has an error due to a typo, which could lead to either (a) a hanging program or an incorrect return value.
int len(char p[])
{
int count = 0;
while (*p != '\0');
// ^^^ The semicolon is a problem
{
count++;
p++;
return count;
}
}
If *p is not equal to '\0', the program will never get out of the while statement. It will hange.
If *p is equal to '\0', the program will get out of the while statement but it will still execute the the lines after that. As a consequence, you will end up returning 1 as the length where 0 is the right answer.
In main, you have:
cout << "Type a phrase" << endl;
cin >> array_size;
When the user sees the output, they will try to enter a phrase. However, array_size is an int. There is a mismatch between the prompt to the user and the line to read the data.
You could change it them to:
cout << "Type array size" << endl;
cin >> array_size;
cout << "Type a phrase" << endl;
That is one step better but that still does not change the fact that memory for a was allocated using a size of 0.
Using uninitialized memory
You are calling len(p) in the cout line but the elements of p have not been initialized.
It's not clear from your post what the program is supposed to do. I am guessing that you want to read a phrase from stdin and write it out to stdout. You can use the following simplified version for that.
int main()
{
std::string phrase;
cout << "Type a phrase" << endl;
// Get the entire line as a phrase.
std::getline(std::cin, phrase);
cout << "Your phrase is " << phrase << endl;
cout << "It is " << phrase.size() << " characters long." << endl;
return 0;
}
First problem: you cannot use array_size till it has been initialized.
char* a = new char [array_size]
since array_size has not been initialized and has garbage data in it, you have no idea how big that array is going to be.
that's why first you have to initialize array_size, and only after allocate your char array.
like
int array_size = 0 //no reason to have this variable as global, but that's up to you
char *a = nullptr; //same
int main()
{
cin >> array_size;
if (array_size <= 0) //make sure the input is valid and not negative
return 0;
a = new char[array_size];
//now you can work on your newly allocated array of characters
//the number of characters the array has equals to the array_size variable.
delete[] a;
return 0;
}
your len function checks for a '\0' character, but again, you have not initialized that char array either, so it contains garbage data. therefore sometimes you may get a result of len 5, 10, 502043, anything can happen really (undefined behavior).
I'm learning dynamic memory and something isn't quite going right. I have a function that accepts a number as input and is supposed to make an array of that size.
class Doctor {
public:
Doctor();
void fillOut();
void listPatients();
void patientReset();
~Doctor();
private:
string name;
int numPatients;
string *patientList;
};
Doctor::Doctor() {
name = "";
numPatients = 0;
patientList = new string[numPatients];
}
(Most relevant code in the 3rd code block).
void Doctor::fillOut()
{
string buffer = "";
string buffer2 = "";
size_t found;
bool valid = false;
int numP = 0;
int tester = 0;
bool validNum = false;
while(!valid)
{
cout << "Enter doctor name: ";
getline(cin, buffer);
found = buffer.find_first_of("1234567890!##$%^&*()-=_+/<>?;':][");
if(string::npos == found)
{
name = buffer;
valid = true;
}
}
while (!validNum)
{
cout << "\nEnter number of patients: ";
buffer = "";
getline(cin, buffer);
buffer2 = buffer;
stringstream ss(buffer);
if(ss >> tester)
{
stringstream ss2(buffer2);
ss2 >> numP;
validNum = true;
}
else
{
cout << "Not a number. Please try again." << endl;
}
}
patientList = new string[numP];
cout << patientList->size() << endl;
for(int i = 0; i < (numP + 0); i++)
{
valid = false;
while(!valid)
{
cout << "\nEnter patient " << (i + 1) << ": ";
getline(cin,buffer);
found = buffer.find_first_of("1234567890!##$%^&*()-=_+,./<>?;':][");
if(string::npos == found)
{
*(patientList + i - 0) = buffer;
//patientList[i-1] = buffer;
valid = true;
}
else
{
valid = false;
}
}
}
}
I then try to display the contents of the list.
void Doctor::listPatients()
{
cout << "size: " << patientList->size() << endl;
cout << "\nDoctor: " << name << endl;
for(int i = 0; i < (patientList->size() - 1); i++)
{
cout << "Patient " << (i+1) << ": " << patientList[i] << endl;
}
cout << "end patients" << endl;
}
But for some reason the number I submit as the size isn't the size of the array. For example, in fillOut() I have the function output the size. It outputs the size as 0 every time. Then in listPatients(), I have something that prints the size again, to verify I'm doing it right. If I initially input 3, it has outputs 5 in this function.
I'm completely mystified.
The line patientList->size() is equivalent to patientList[0].size(), the length of the initial string in your patientList array. At the point where you have just allocated your array, the result is always zero; in other instances, it is the length of the first string.
A preferred way of making containers in C++ is std::vector or std::array. In your case using std::vector is more appropriate, because your code allocates the patientList dynamically.
Ok, I found your problem. You are declaring an array of strings. But a raw array is really just a pointer to the contents of the array. When you call ->size, it dereferences that pointer, which points to the first string in the array and tells you the size of that string.
If you want an array that actually knows its size, use std::array.
OK so you declare patientList as a string* but when you call size() on this you are actually calling it on the first item in the array you have created. The only reason your code compiled is because string has a size() function and as this is the type contained in your array you got away with it because patientList actually points to the item at the start of the array (a string). In general an array does not have a size() function.
One other problem you will have though is here in your loop
for(int i = 0; i < (patientList->size() - 1); i++) {
^
^
cout << "Patient " << (i+1) << ": " << patientList[i] << endl;
}
this will cause your loop to terminate one before the end of patientList. You should use
for(int i = 0; i < patientList->size(); i++) {
cout << "Patient " << (i+1) << ": " << patientList[i] << endl;
}
You would be better off using a std::vector here to put your strings in. Also be careful here
if(string::npos == found) {
*(patientList + i - 0) = buffer;
//patientList[i-1] = buffer;
valid = true;
}
else {
valid = false;
}
because you would only be assigning to your array on the occasions when your if statement is true - the indices in the array when it is false are left uninitialised. I would honestly start again from scratch and use a vector of strings.