I am trying to dynamically allocate an array of records. When I run my program with ./a.out it appears to work fine but when I try and run the program inputing the data from a .txt file (./myProg < ) it repeatedly records the first line of text in the whole array and crashes and does not print out the chosen book in the end. My guess is I am not creating the array properly but I cannot seem to figure out what my problem is.
struct Book {
char *title; //entered with no spaces
int date; // in the form ddmmyy
};
Book *createRecord(int);
void input(Book *, int);
void display(Book *, int, int);
void destroyRecord(Book *);
int main() {
int arrN = 0;
int n = 0;
cout << "Enter size of array: ";
cin >> arrN;
Book *bookArr;
bookArr = new Book[arrN];
bookArr = createRecord(arrN);
input(bookArr, arrN);
cin.ignore();
cout << "Book: ";
cin >> n;
display(bookArr, arrN, n);
destroyRecord(bookArr);
return EXIT_SUCCESS;
}
Book *createRecord(int arrN){
struct Book *bookArr;
bookArr = new Book[arrN];
return bookArr;
}
void input(Book *bookArr, int arrN) {
for(int i = 0; i < arrN; i++){
char arrFirst[20];
cin.ignore();
cout << "Name: ";
cin.getline(arrFirst, 20);
strcpy((bookArr[i]).title = new char, arrFirst);
cout << "Score: ";
cin >> (bookArr[i]).date;
}
}
void display(Book *bookArr, int arrN, int n) {
if (0 <= n && n <= arrN){
cout << (bookArr[n-1]).title << " " << (bookArr[n-1]).date << endl;
}
}
void destroyRecord(Book *bookArr) {
delete [] (bookArr)->title;
delete bookArr;
}
Well, first up, you're allocating two arrays:
bookArr = new Book[arrN]; // <-- leaked
bookArr = createRecord(arrN);
That's a memory leak.
Secondly:
(bookArr[i]).title = new char
That is allocating one single char that you're trying to copy a whole string into. That should probably be:
// two lines please!
bookArr[i].title = new char[20];
strcpy(bookArr[i].title, arrFirst);
Thirdly:
if (0 <= n && n <= arrN){
That bounds check is incorrect. The upper bound should be n < arrN, and then just index n. By indexing n - 1, you might print the -1st index.
And last, but not least, prefer:
struct Book {
std::string title;
int date;
}
std::vector<Book> bookArr;
Problem1:
Fix the array indexing problem in the display function:
void display(Book *bookArr, int arrN, int n) {
if (0 <= n && n <= arrN){
cout << (bookArr[n - 1]).title << " " << (bookArr[n - 1]).date << endl;
}
}
to
void display(Book *bookArr, int arrN, int n) {
if (0 < n && n <= arrN){
cout << (bookArr[n - 1]).title << " " << (bookArr[n - 1]).date << endl;
}
}
when n = 0, bookArr[-1] is throwing the error in your code.
Problem 2:
Allocate character array instead of single character to title in line, change:
strcpy((bookArr[i]).title = new char, arrFirst);
to
strcpy((bookArr[i]).title = new char[20], arrFirst);
Not sure about the input problem, but you are definitely not creating the array as you should. In your code you are creating an array of books, then assigning a new array of books in the createRecord function and replacing the original array with it. Unlike what you are expecting to happen, you end up with an array of uninitialized Book pointers.
This is what you should be doing...
// Allocate an array of books
Book *bookArr;
bookArr = new Book[arrN];
// Preallocate the records
for ( int iBook = 0; iBool < arrN; iBook++ )
{
bookArr[ iBook ] = createRecord();
}
...
Book *createRecord()
{
// Allocate one new book
struct Book *pbook = new book;
return pbook;
}
Related
#include <iostream>
#include <iomanip>
#include <string>
#include <algorithm>
using namespace std;
void getinput (string &first,string &second);
void lengthcheck (string first, string second);
//int anagramcheck (string word);
int* lettercounter (string input);
int main()
{
std::string a;
std::string b;
getinput(a,b);
lengthcheck (a,b);
lettercounter(a);
lettercounter(b);
int* one = lettercounter(a);
int* two = lettercounter(b);
if (one == two)
cout << "You Have Entered An Anagram" << endl;
else
cout << "You Have Not Entered An Anagram" << endl;
}
void getinput (string &first, string &second) {
cout << "Enter First Input: ";
getline(cin, first, '\n');
cout << "Enter Second Input: ";
getline(cin, second, '\n');
cout << "You Entered " << first << " and " << second <<endl;
}
void lengthcheck(string first, string second){
int lengtha = first.length();
int lengthb = second.length();
if ((lengthb > 60) || (lengtha > 60)) {
cout << "Input Is Invalid" << endl;
} else if (lengtha !=lengthb) {
cout << "Input is not an anagram" << endl;
} else {
cout << "Input is Valid" << endl;
}
}
int* lettercounter(string input)
{
static int freq[26] = {0};
int length = input.length();
for (int i=0; i<26; i++) {
freq[i]=0;
}
for (int i=0; i <length; i++) {
if(input[i]>='a' && input[i]<='z')
{
freq[input[i] - 97]++;
}
else if(input[i]>='A' && input[i]<='Z')
{
freq[input[i] - 65]++;
}
}
for(int i=0; i<26; i++) {
/* If current character exists in given string */
if(freq[i] != 0)
{
printf("'%c' = %d\n", (i + 97), freq[i]);
}
return freq;
}
}
I am having trouble returning the array named freq from the user definied function called lettercount. Can someone give me a hint? I need the lettercount to return an array. I need to call the function lettercount twice so i can compare the results of each array to determine if the two inputs are anagrams. I am not sure if the function is returning an actual value to the main.
First of all, freq shouldn't be static. By making it static, you would be accessing the same array everytime. For what you want to do, you don't want to always access the same memory.
In second place, you cannot just return a pointer to memory that has not being allocated dynamically or that isn't static. When you get out of scope (i.e. you return from the function lettercounter back to main), the memory that was occupied by the array will be freed. So, you would be returning a pointer to memory that is no longer reserved, resulting in undefined behavior.
If you really need to work with raw pointers, then each time you enter lettercounter, you would need to allocate memory for the array dynamically like this: int * freq = new int[26];. This will reserve memory for an array of size 26. Then, when you return freq, the memory will still be allocated. However, don't forget that the memory allocated with new doesn't delete itself. You have to clean your mess. In this case, at the end of main you would call delete[] one; and delete[] two;.
int* lettercounter(string input)
{
int * freq = new int[26];
.
.
.
return freq;
}
int main()
{
.
.
int* one = lettercounter(a);
int* two = lettercounter(b);
.
.
delete[] one;
delete[] two;
}
In any case, I'd recommend you to learn to use smart pointers and about standard containers (like a vector). These operations would be much simpler.
I need to make a dynamic array in C++, and ask a user to input a name until the user types exit.
It should keep asking for more and more names, recording them to a dynamic string array, then randomly choosing as many names as the user wants from the list.
I should be able to figure out the random numbers part, but the continuous input is giving me issues. I'm not sure how to have the length variable continue changing values.
#include <iostream>
#include <string>
using namespace std;
int main()
{
int length;
string* x;
x = new string[length];
string newName;
for (int i = 0; i < length; i++)
{
cout << "Enter name: (or type exit to continue) " << flush;
cin >> newName;
while (newName != "exit")
{
newName = x[i];
}
}
cout << x[1] << x[2];
int qq;
cin >> qq;
return 0;
}
Any help would be greatly appreciated.
A few errors:
length is never assigned a value
You're overwriting newName with an unassigned value x[i] of the array in newName = x[i];
x is never dynamically reassigned with a new array of different length
Let's consider a solution:
#include <iostream>
#include <string>
using namespace std;
int main()
{
int length = 2; // Assign a default value
int i = 0; // Our insertion point in the array
string* x;
x = new string[length];
string newName;
cout << "Enter name: (or type exit to continue) " << flush;
cin >> newName; // Dear diary, this is my first input
while (newName != "exit")
{
if (i >= length) // If the array is bursting at the seams
{
string* xx = new string[length * 2]; // Twice the size, twice the fun
for (int ii = 0; ii < length; ii++)
{
xx[ii] = x[ii]; // Copy the names from the old array
}
delete [] x; // Delete the old array assigned with `new`
x = xx; // Point `x` to the new array
length *= 2; // Update the array length
}
x[i] = newName; // Phew, finally we can insert
i++; // Increment insertion point
cout << "Enter name: (or type exit to continue) " << flush;
cin >> newName; // Ask for new input at the end so it's always checked
}
cout << x[1] << x[2]; // Print second and third names since array is 0-indexed
int qq;
cin >> qq; // Whatever sorcery this is
return 0;
}
Addressing the errors mentioned:
length is assigned a default value at the start
Reverse the direction to get x[i] = newName;
x is dynamically assigned a new array of exponentially-increasing length
Happy learning!
There is a problem with the code and i could not find it.
i was asked to write a money struct and use functions to manipulate it.
but the code did not work for any function. i tried couting
the array of structers and it came out nicely, for any missing info
please leave a comment and i'll reply shortly.
Money.txt
2
12 20
13 40
#include <iostream>
#include <fstream>
using namespace std;
struct Money { //declaring structure
int dollars;
int cents;
};
Money addMoney(Money *p[], int n) { //adds money data
Money cash{ 0,0 };
int i;
for (int j = 0; j < n; j++) {
cash.dollars = cash.dollars + p[j]->dollars;
cash.cents = cash.cents + p[j]->cents;
}
if (cash.cents >= 100) //100cents = 1 dollar
{
i = (cash.cents) / 100;
cash.dollars = cash.dollars + i;
i = (cash.cents) % 100;
cash.cents = i;
}
return cash;
}
void printMoney(Money *p[], int n) { //printing money data
for (int i = 0; i < n; i++) {
cout << "Dollars: " << p[i]->dollars << endl;
cout << "Cents: " << p[i]->cents << endl;
}
}
Money maxMoney(Money *p[], int n) {
Money cash;
cash.dollars = p[0]->dollars;
cash.cents = p[0]->cents;
for (int i = 0; i < n; i++)
{
if ((p[i]->dollars)>=(cash.dollars))
if ((p[i]->cents)>(cash.cents))
{
cash.dollars = p[i]->dollars;
cash.cents = p[i]->cents;
}
}
return cash;
}
void main() {
Money cash;
ifstream mycin("money.txt");
if (mycin.fail())
cout << "Enable to open file";
int x;
mycin >> x;
Money *arr = new Money[x];
for (int i = 0; i < x; i++)
{
mycin >> arr[i].dollars;
mycin >> arr[i].cents;
}
cout << "The values in money.txt are: ";
printMoney(&arr, x);
cash = addMoney(&arr, x);
cout << "These values added are :";
cout << cash.dollars << " Dollars and " << cash.cents << " cents" << endl;
cash = maxMoney(&arr, x);
cout << "Maximum value is :";
cout << cash.dollars << " Dollars and " << cash.cents << " cents" << endl;
}
These functions appear to accept an array of pointers to Money, but you're trying to use them with an array of Money.
I suggest you play with arrays of pointers to simpler types (like int) until you're comfortable with the concept, before you attempt it with Money.
This sounds a lot like homework so I'm not posting a full solution, but I will explain what appears to be the misunderstanding and give you some pointers.
First you declare your data structure as an array of Money structures, e.g. a continuous series of blocks of memory containing the Money struct, the first of which is pointed to by "arr" in your main program.
But then, in the rest of the program (functions) you seem to expect the data structure being used to be an array of Money pointers. See the difference? They're not the same and this will not work as is. You have to be consistent.
Either you're dealing with an array of structs, in which case you pass effectively a single, simple Money* to your functions everywhere (and you dereference with . not ->)
Or you're dealing with an array of pointers, in which case you pass effectively a pointer to a (Money pointer) and you dereference with -> as you've done. But then you also have to allocate each Money struct individually when you're reading them in in the main program. That is to say, allocating memory for the array of pointers does not automatically allocate memory for each Money pointer reference in the array of pointers and so you need to do this for each entry you're reading in.
So, as you should hopefully now realise, there's multiple ways to fix your program.
As per your later comment, given that the function signatures need to stay as-is, I would suggest you work with an array of Money pointers.
Money** arr = new Money*[x]
Then you need to add a line to your loop during reading, to actually make each Money * point to a Money struct:
for (int i = 0; i < x; i++)
{
arr[i] = new Money
...
Finally then, because "arr" is now a pointer to a pointer to Money, you can directly pass it to your functions, so calling them are just for example:
printMoney(arr, x);
using namespace std;
struct Package_Node
{
int bar_code;
float package_weight;
struct Package_Node *next_packaged;
};
struct Key_Node
{
int key;
struct Package_Node *next_package;
};
Key_Node *keyMain=0;
int weightTemp=0,barcodeTemp=0,keyTemp=0,N=0,X=0,max_value=0,optionChosen=0,optionChosenTwo=0;
float tempWeight;
int main()
{
srand(time(NULL));
do
{
cout << "1 - Enter Number of keys and the Max Value\n2 - Enter Number of Packages (N)\n";
cout << "3 - Create Array of Keys\n4 - Organize Packages\n5 - Table Stats\n6 - Clean Table\n7 - Exit\n\n";
cin >> optionChosen;
switch(optionChosen)
{
case 1://entering keys and max values
{
cout << "\nEnter Number of Keys: ";
cin >>X;
cout <<"\nEnter Max Value of the Barcode: ";
cin >>max_value;
break;
}
case 2://enter number of packages.
{
cout << "\nEnter Number of Packages: ";
cin >> N;
break;
}
case 3://create array of keys.
{
//Key_Node *keyMain = new Key_Node[X];
keyMain= new Key_Node[X];
for(int i=0;i<X;i++)
{
keyMain[i].key=i;
cout << keyMain[i].key<<endl;
}
break;
}
case 4:
{
for(int i=0;i<N;i++)
{
barcodeTemp = rand() % max_value + 1;
keyTemp = barcodeTemp % X;
tempWeight = rand() % 500 + 1;
keyMain[keyTemp] = new Package_Node;
Package_Node->bar_code=barcodeTemp;
Package_Node->package_weight=tempWeight;
Package_Node->next_packaged=NULL;
}
for(int i=0;i<N;i++)
{
cout << totalPackages[i].bar_code <<endl;
cout << totalPackages[i].package_weight << endl;
}
cout << keyTemp;
break;
}
case 5:
{
break;
}
case 6:
{
break;
}
default:
{
break;
}
}
}while(optionChosen!=7);
}
I am sort of confused here. keyMain is a static array.keyMain[1], keyMain[2] etc. will point to a linked list that is made using Package_Node. The index of keyMain where the new package_node will be added is determined by keyTemp. But it seems like thats a far cry. Seems like the code I have written is not working. What am I doing wrong here? Any ideas? Please do not use vectors as this is for a class project and we wont talk about vectors at all.
In your code, you attempt this:
keyMain[keyTemp] = new Package_Node;
Package_Node->bar_code=barcodeTemp;
Package_Node->package_weight=tempWeight;
Package_Node->next_packaged=NULL;
That's not going to work. This is the basic idea:
Package_Node *n = new Package_Node;
n->bar_code = barcodeTemp;
n->package_weight = tempWeight;
n->next_packaged = NULL;
keyMain[keyTemp].next_package = n;
Now you have a single-element list on each item in your Key_Node array. If you want to add to those lists, then normal list-based algorithms apply.
But it looks like you are trying to use this as a hash array. That means you want to append (or prepend) to your list. Prepending makes for more readable code. I'll do that, and if you want to append then that's an exercise for you.
// Do this instead of setting it to NULL (from previous code example)
n->next_packaged = keyMain[keyTemp].next_package;
In the above example you MUST initialise next_package to NULL when you create the keyMain array. Currently you don't do this. Since this is C++, it would be a good idea to familiarise yourself with RAII.
Finally, the following code doesn't make sense:
for(int i=0;i<N;i++)
{
cout << totalPackages[i].bar_code <<endl;
cout << totalPackages[i].package_weight << endl;
}
What you need to do (unless you are storing an array somewhere called totalPackages) is to iterate through your keyMain array and print out all the lists:
for(int i=0;i<X;i++)
{
Package_Node *p = keyMain[i].next_package;
while( p != NULL ) {
cout << p->bar_code << endl;
cout << p->package_weight << endl;
p = p->next_packaged;
}
}
This section does not look right
keyMain[keyTemp] = new Package_Node;
Package_Node->bar_code=barcodeTemp;
Package_Node->package_weight=tempWeight;
Package_Node->next_packaged=NULL;
it should be something like
keyMain[keyTemp].next_package = new Package_Node;
keyMain[keyTemp].next_package->bar_code=barcodeTemp;
keyMain[keyTemp].next_package->package_weight=tempWeight;
keyMain[keyTemp].next_package->next_packaged=NULL;
Also the way you are calculating keyTemp
barcodeTemp = rand() % max_value + 1;
keyTemp = barcodeTemp % X;
does not seem right as depending on what you enter in for the max_value it may be greater than X, the size of you array.
I present to you all a program I'm working on for my college programming course. I still have a little ways to go before it completely meets my assignment's requirements, but I've gotten a basic draft of the program error-free (supposedly) and it appears to run… but then it suddenly kicks me into Xcode's debugger and gives me:
Thread 1: EXC_BAD_ACCESS(code=2, address=0x7fff95c1e5f5)
Here's the command line output, up until it kicks me out:
-----------------------
Quarterly_sales_taxator
-----------------------
How many company divisions will we be dealing with? 2
Am I correct in assuming that there are 4 sales quarters? yes
Please enter the sales Company Division #1 brought in for Sales Quarter #1 20
(lldb)
Here's my code:
//
// quarterly_sales_taxator.cpp
// Ch. 7 program #7
//
// Created by John Doe on 11/27/12.
//
#include <iostream>
#include <iomanip>
#include <string>
#include <sstream>
#include <cctype>
using namespace std;
void read_company_divisions_and_sales_quarters(double **, int, int);
//void write_company_divisions_and_sales_quarters_to_array(double **, int, int); // This will be used later on to read data from a file.
void display_quarterly_sales_array(double **, int, int);
string temp; // A global temporary placeholder variable; I use this several times.
int main()
{
int COMPANY_DIVISIONS,
SALES_QUARTERS = 4;
double **quarterly_sales_form;
cout << "\n\n-----------------------\nQuarterly_sales_taxator\n-----------------------\n\n";
cout << "\nHow many company divisions will we be dealing with? ";
getline(cin, temp);
stringstream(temp)>>COMPANY_DIVISIONS;
while (COMPANY_DIVISIONS < 1 || isdigit(COMPANY_DIVISIONS == false))
{
cout << "\n\n------"
<< "\nError:"
<< "\n------"
<< "\n\nYou have entered an invalid choice."
<< "\nPlease type a number greater than zero. ";
getline(cin, temp);
stringstream(temp)>>COMPANY_DIVISIONS;
}
cout << "\n\nAm I correct in assuming that there are 4 sales quarters? ";
getline(cin, temp);
// Convert to uppercase.
for (int count = 0; count < temp.length(); count ++)
{
temp[count] = toupper(temp[count]);
}
if (temp == "NO" || temp == "NOPE" || temp == "INCORRECT" || temp == "YOU ARE NOT" || temp == "YOU ARE INCORRECT" || temp == "NEGATIVE" || temp == "NEGATORY")
{
cout << "\nOk, then how many sales quarters are we dealing with? ";
getline(cin, temp);
stringstream(temp)>>SALES_QUARTERS;
}
cout << endl << endl;
// This sets up the 2d array.
quarterly_sales_form = new double *[COMPANY_DIVISIONS];
for (int count = 0; count < COMPANY_DIVISIONS; count ++)
{ quarterly_sales_form[COMPANY_DIVISIONS] = new double [SALES_QUARTERS]; }
read_company_divisions_and_sales_quarters(quarterly_sales_form, COMPANY_DIVISIONS, SALES_QUARTERS);
// write_company_divisions_and_sales_quarters_to_array(quarterly_sales_form, COMPANY_DIVISIONS, SALES_QUARTERS); // I'll add this feature later.
cout << "\n\nHere's what you entered:\n\n";
display_quarterly_sales_array(quarterly_sales_form, COMPANY_DIVISIONS, SALES_QUARTERS);
// Since we used a series of pointers, we need to free the allocated space back up.
for (int count = 0; count < COMPANY_DIVISIONS; count ++)
{ delete[] quarterly_sales_form[COMPANY_DIVISIONS]; }
delete[] quarterly_sales_form;
return 0;
}
/*############################################
# read_company_divisions_and_sales_quarters #
############################################*/
void read_company_divisions_and_sales_quarters(double **array, int DIVISIONS, int QUARTERS)
{
for (int count = 0; count < QUARTERS; count++)
{
for (int index = 0; index < DIVISIONS; index++)
{
cout << "\nPlease enter the sales Company Division #" << count+1 << " brought in for Sales Quarter #" << index+1 << " ";
getline(cin, temp);
stringstream(temp) >> array[count][index];
}
}
}
/*################################
# display_quarterly_sales_array #
#################################*/
void display_quarterly_sales_array(double **array, int DIVISIONS, int QUARTERS)
{
for (int count = 0; count < DIVISIONS; count++)
{
cout << "\nCompany division #" << count+1 << ":\n";
for (int index = 0; index < QUARTERS; index++)
{ cout << array[count][index] << ", "; }
}
}
Can some kind soul please tell me what I'm doing wrong?
{ quarterly_sales_form[COMPANY_DIVISIONS] = new double [SALES_QUARTERS]; }
In this line, COMPANY_DIVISIONS should be count.
In addition to what Dan Hulme said, it seems this line
stringstream(temp) >> array[count][index];
should really be
std::istringstream(temp) >> std::skipws >> array[index][count];
In addition to using std::istringstream rather than std::stringstream and making sure that an lvalue is at hand, which isn't strictly needed until the type read becomes more interesting, this also reverses the indices: index runs over COMPANY_DIVISIONS and count over SALES_QUARTERS.
The real question is, of course: Who hands out assignments like this? Pointer manipulations and allocations are best left to low-level library writers. This is C++ not C: we can and should use abstractions. Getting this code exception safe is a major challenge and there is no point in teaching people how to write broken (e.g. exception unsafe) code.