how do you add value in runtime to structural arrays (in c++) - c++

This question was migrated 12 years ago.
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
int main (){
int a,b;
b = 0;
cout<<" this is a family profiling program to test my knowledge of structural arrays. ";
cin>> a;
struct p {
char name[20];
int age;
char hobby[40];
char favcolor[15];
};
p family[2];
**cin.getline(family.name[0]);**
cout<<"enter the name of family member"<<b+1;
I am trying to use this code to create a family profiling program, i know how to add value to an array or structural array during compiler time but not to use cin or cin.getline to add a value to to a specific value in a specific structure of an array.
please respond with a simple answer; Im still new to programming.(my attempt is bolded

If you insist on using an array, the easiest way to do this (add elements to a fixed-size array) would be to copy everything to a NEW array, including the new item.
A much better way would be to use a dynamic structure, such as a linked list. The standard template library and the boost library have many ways to help you here, but you could also easily implement a simple linked list on your own (or find code for it).
As Mike Chess said, this is probably best asked on http://www.stackoverflow.com
(also, to get your code formatted nicely, edit your post, select the code section, and click the button with the ones and zeros icon just above the text area)

Firstly, you'll find it much easier to write reliable code if you use std::string instead of character arrays. You were nearly on the right track though: instead of family.name[0] try family[0].name, then getline will work with std::string as below...
struct p
{
std::string name;
// other stuff...
};
if (getline(std::cin, family[0].name))
{
// it worked!
...
}

The "high performance" and old school option is to use realloc like this.
p * family = malloc(sizeof(p)*2);
family = realloc(family, sizeof(p)*13);
Of course this doesn't invoke constructors, and is not really acceptable in C++ generally. So your best option is.
#include <list>
using namespace std;
...
list<p> family;
p blah;
family.push_back(blah);
That's a linked list so it's perfect for datasets of unknown length. Same code can be used for an STL vector, which if you predict the size of your input in advance well enough will give you a performance boost.

Related

Array causes stack overflow error

My program is this:
#include<iostream>
#include<fstream>
using namespace std;
int main()
{
char choice;
int o,i,marks[i],ttlcredit=0;
double ttlGPA=0,finalGPA=0,credit[7][2],clsavg;
cout<<"Please enter what you want to calculate"<<endl;
cout<<"A for calculating Class Average GPA"<<endl;
cout<<"B for calculating a Specific GPA"<<endl;
cout<<"Your choice is? ";
cin>>choice;
cout<<endl;
if (choice == 'A'||choice == 'a')
{
cout<<"=========================================="<<endl;
cout<<" Class Average GPA"<<endl;
cout<<"=========================================="<<endl<<endl;
cout<<"Please enter the number of students in the class: ";
cin>>number;
for(i=0;i<number;i++)
{
cout<<"\nEnter student #"<<i+1<<"'s marks: ";
cin>>marks[i];
ttlGPA=ttlGPA+marks[i];
}
clsavg=ttlGPA/number;
cout<<"\nThe Average is: "<<clsavg<<endl;
}
else
{
}
}
It is half completed. When I build and run on CodeBlocks, an error instantly appeared:
I tried finding the source of error and I think that it is caused by the following in the code:
int o,i,marks[i],ttlcredit=0;
What makes me think so is because when I remove the [i] from marks[i], I will be not receive that error.
I think is stack overflow because I use Microsoft Visual Studio to help me debug and this is the error they gave me:
Unhandled exception at 0x0041419e in Project (1).exe: 0xC00000FD: Stack overflow.
My question is...
Is that the main cause of problem?
How do I resolve this issue?
You have to initialize the marks array with a positive length.
Get the number of students first, THEN create the array using that number.
Also, you need to declare the variable number.
As the other answers stated correctly, the problem is that int i is used uninitialized. However, the proposed fix
// initialze i
int marks[i];
is not standard C++, but only available through a compiler extension. In C++, the length of a built-in array must be a compile time constant. The better solution would be using std::vector:
// initialize i (better make it std::size_t instead of int)
std::vector<int> marks (i);
This will create a variable length array in a safe and standard conforming way.
First thing to say is that you simply shouldn't use arrays. They just are too weird in C and C++, and we have superior alternatives in modern C++.
Anyway, whether you use arrays or vectors, there are some important issues. Before discussing marks[i], it's simpler to look at credit[7][2] in this code.
int o,i,marks[i],ttlcredit=0;
double ttlGPA=0,finalGPA=0,credit[7][2],clsavg;
The dimensions are explicit in this declaration of credit. It's seven-times-two. Simple enough. You can read and write to credit[0][0] and credit[6][1] and many other values. But if you go outside the range, e.g. try to use credit[7][0], your program will compile and will probably appear correct for a while, but it could behave very badly and it is undefined how it will behave. It could decide to delete all the files on your computer, it is (seriously) entitled to do anything random and crazy. This is Undefined Behaviour.
Anyway, the really weird line is the declaration of marks.
int marks[i];
This definitely doesn't do what you think it does. It doesn't create an array that can be "indexed with arbitrary i". No, it allocates an array whose size is the initial value of i. But i is undefined at this stage so this is meaningless.
But i isn't relevant here anyway. How big do you want this array to be? The answer is number, isn't it? That is the number of people you'll store in your array.
So, a small improvement is to do this instead of int marks[i].
int marks[number];
But even this isn't correct. The value of number isn't set until the line cin >> number;, therefore you must declare int marks[number] after the line cin >> number; in order to ensure that marks has the correct size.
But, but, but, even after all this, we still don't have standard C++. It's OK to do int credit[7][2] because the size is fixed at compile time. You are normally not allowed to set the size of an array at runtime, e.g. int marks[number]. You might be able to use it if your compiler allows this extension (it's called Variable Length Array, from C).
So, this is not standard C++, and it's potentially very dangerous (see the Undefined Behaviour). What's the solution?
The solution is the standard solution for any problem involving arrays. Stop using arrays. (Really advanced programmers, in particular situations, might use std::array in modern C++, or even write their own clone of std:: array in older C++. But raw C [] arrays are to be avoided where possible.)
#include<vector>
int o,i,ttlcredit=0;
std::vector<int> marks;
marks is initially empty. We don't do cin >> marks[i];. Instead we use push_back to append new items to the end of the list.
int next_mark;
cin >> next_mark;
marks.push_back(next_mark);
Also, don't use marks[i] with a vector. It might look OK, but it is dangerous. Better to use marks.at(i) to read or write the element. at will do bounds checking for you, giving you a proper error message if i is too small (less then 0) or too big for the size of the vector.
int o,i,marks[i],ttlcredit=0;
i is not initialized. initialize i first.
If you are not sure of the size of the array, allocate it dynamically.
use new
refer this link on how to use new - cpluspluss

How do I go about editing the variables in a struct array?

I've Googled, asked my classmates, and finally asked my professor about this particular problem, but I haven't achieved a solution yet. I'm hoping someone here can help me out.
Basically, I need to make an array of structs that will contain 4 pieces of information per struct: country name, country population, country area, and country density. This information will be written to the structs in the array from a .txt document. This info will then be written onto the console from said array.
Unfortunately, in attempting to write anything to the structs in the array, I get 2 errors. "Cannot convert from 'const char[8]' to 'char [30]'" and "no operator '[]' matches these operands, operand types are: CountryStats [int]". These errors both refer to the line:
countries[0].countryName = "A";
Keep in mind that I have only started to use structs and this is the first time I've used them in an array. Also, I must use an array, as opposed to a vector.
Here's my code:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
struct CountryStats;
void initArray(CountryStats *countries);
const int MAXRECORDS = 100;
const int MAXNAMELENGTH = 30;
struct CountryStats
{
char countryName[MAXNAMELENGTH];
int population;
int area;
double density;
};
// All code beneath this line has been giving me trouble. I need to easily edit the
// struct variables and then read them.
int main(void)
{
CountryStats countries[MAXRECORDS];
initArray(*countries);
}
void initArray(CountryStats countries)
{
countries[0].countryName = "A";
}
As of now I am just attempting to figure out how to write information to a struct within the array and then read the information off of it onto the console. Everything else should fall into place after I find the solution to this.
Oh, and one final note: I have not quite learned the function of pointers (*) yet. I am still relatively new to C++ as my past programming education has been primarily in Java. Any and all inclusions of pointers in this code have been influenced by my classmates and professor in the pursuit of solving this problem.
Thanks in advance!
Two problems
void initArray(CountryStats countries)
must be:
void initArray(CountryStats *countries)
And you must use strcpy to copy c style string. (but i suggest to use c++ string instead of char[])
strcpy(countries[0].countryName,"A");
But I say again, use c++ features like vector<> and string.
You are not defining a definition for:
void initArray(CountryStats *countries);
but for:
void initArray(CountryStats countries);
in which countries is not an array. Since no operator[] is defined for CountryStats, the expression countries[0] fails to compile.
Since you cannot use std::vector (for some weird reasons), I'd suggest you to use an std::array:
template<std::size_t N>
void initArray(std::array<CountryStats, N>& ref) {
for (std::size_t i = 0; i < N; i++)
// initialize ref[i]
}
Of course, if you feel masochist, you can also use a C-style array:
void initArray(CountryStats* arr, int size) {
for (int i = 0; i < size; i++)
// initialize arr[i]
}
But you'll, probably, need to provide the dimension of the array as a second parameter.

Simple Address Book using dynamic array

I am working on my school project related to "keeping contacts of customers" in C++.
I already finished my project using std::vector to store contact information for every added person. But now i have to write the same thing using DYNAMIC ARRAY.
Does anybody have any idea or sample code how to declare dynamic array with ability to change its dimension according to how many contacts are added by user ?
I need following:
* Declaration of dynamic array with undefined number of persons and with 6 contacts per each.
* Add a new contact.
* List all contacts in array.
I finished my project using vectors without any problems, but right now i am lost. I studied a lot of articles about working with dynamic arrays in c++ but with no progress. I was searching all around the internet for a sample piece of code that does what i need but can't find anything.
Although this is not exactly the same as your project, this was mine from a few days ago and we had to use a 2d dynamic array using the "new" and "delete" method for strings of names. Remember that any time you use "new" you need to have a "delete" otherwise you will get memory leaks. I hope this helps.
#include <iostream>
using namespace std;
#include <memory.h>
#include <string.h>
#include "ReadString.h"
#include "sort.h"
void main ()
{
bool contMain=true;
const long numNames=20;
long nameAc=0;
char ** ppNames;
ppNames=new char* [numNames];
char test;
while(contMain && nameAc<numNames)
{
ppNames[nameAc]=ReadString();
test=ppNames[nameAc][0];
if(test=='\0')
{
contMain=false;
}
nameAc++;
}
cout<<"Your names unsorted are:"<<endl;
print(ppNames, nameAc);
ppNames=sort(ppNames, nameAc);
cout<<"Your names, sorted, are:"<<endl;
print(ppNames, nameAc);
// deallocation... this will delete pNames and pTemp from the ReadString function
// as well as ppNames in main because they are all using the same pointers.
for(int i=0; i<nameAc; i++)
{
delete ppNames [i];
}
delete[] ppNames;
}
And here is the ReadString function.
#include <iostream>
#include <memory.h>
#include "ReadString.h"
using namespace std;
char * ReadString()
{
long aSize=10;
long numChars (0);
char * pNames;
char * pTemp;
char c;
pNames=new char [aSize+1];
while((c = cin.get()) != '\n')
{
if(numChars >= aSize)
{
aSize += numChars;
pTemp = new char[aSize + 1];
memcpy(pTemp, pNames, numChars);
delete[] pNames;
pNames = pTemp;
cout << "Array size increased to " << aSize << endl;
}
pNames[numChars++] = c;
}
pNames[numChars] = '\0'; //end of string
return pNames;
one thing you can easily use for this are linked lists. Your data structure has a pointer to the next list element.
struct ListElement
{
CustomerData cutomer;
ListElement *next;
}
You can add infrastructure for adding removing, finding, print-all etc. using such a datastructure as basis.
Another way is doing it really dynamic:
Example adding one item:
malloc memory for as many items as you already have + 1
copy the data from the old to the new memory
add the new item at the with +1 allocated space
You'll need infrastructure for adding at the beginning, at the end, delete one in the middle etc. going with this scheme. Allocate as much memory as you need after the change, copy the old data, insert/remove one item.
Good luck with your project!
The best that I can so is to suggest links to articles. It sounds like your instructor wants you to write the same program in "the hard way" using a more primitive set of tools. Since std::vector is essentially a dynamic array, I have to assume that he wants you to rewrite the project where you have to manually manage the memory. Here are some starting points. Remember, that google is your friend!
C++ FAQ Lite
Dynamic Memory Cplusplus.com
LMGTFY

The use of arrays within structures

I'm currently studying C++ on a book I bought a month ago. So now here I am, studying the new chapter that talks about structures.
The book gives a problem: Write a program that allows a user to enter high scores of a game, keeping tracking of the name
of the user and the score. Add the ability to show the highest score for each user, all scores for a
particular user, all scores from all users, and the list of users.
My problem is... how to store a lot of scores of the same player, using a structure.
I thought something like this:
struct my_string
{
string name;
int score[100];
int lvp;
};
Declaring an array, within a structure, it's something that can be done? I'm not entirely sure.
After that, in the main function, I declared an array of my_string type.
Like this:
my_string name_score[100];
I was thinking about using 2 counters, one that is related to the name, and the other related to the scores. Something like this:
name_score[0].score[2];
So, this piece of code should give me back the third score, of the first name (player).
Am I saying nonsense, or this can be done?
Seems to me that you are exactly right! That should work perfectly.
Basically your first closed brackets will give you the player and the .score[] will give you their entry.
So this code is valid code:
#include <iostream>
#include <string>
struct my_string
{
std::string name;
int score[100];
int lvp;
};
int main()
{
my_string name_score[100];
//Initializing of data in name_score assumed here
std::cout << name_score[0].score[2] << std::endl ;
}
Since this is C++ you may want to consider using std::vector<int> score as opposed to int score[100] or even std::array if you are using C++11 they are both superior to old C style array. The same thing goes for my_string although you might want to pick a more descriptive name.

Segmentation fault in File I/O

I have written a code to read a file, store it in a structure and just display it. But somehow it is giving me a segmentation fault and I dont know why. Can someone please help me?
Output:
file: /home/neel/map2.txt
file opened
Start Intersection
a->road: 4
a->roadId[0]: 1
a->lane[0][0]: 2
a->lane[0][1]: 2
a->roadId[1]: 2
a->lane[1][0]: 2
a->lane[1][1]: 2
a->roadId[2]: 3
Segmentation fault
Code:
#include <iostream>
#include <fstream>
#include <stdio.h>
using namespace std;
struct Intersection
{
unsigned short road;
long long int *roadId;
short *lane[2];
};
int main(int argc, char** argv)
{
std::ifstream file;
cout<<"file: "<<argv[1]<<endl;
file.open(argv[1], std::ios::in);
cout<<"file opened"<<endl;
while (!file.eof())
{
cout<<"Start Intersection"<<endl;
Intersection *a = new Intersection;
file>>a->road;
a->roadId = new long long int[a->road];
a->lane[0] = new short[a->road];
a->lane[1] = new short[a->road];
cout<<"a->road: "<<a->road<<endl;
for (int i=0; i<a->road; i++)
{
file>>a->roadId[i];
cout<<endl<<"a->roadId["<<i<<"]: "<<a->roadId[i]<<endl;
file>>a->lane[i][0];
cout<<"a->lane["<<i<<"][0]: "<<a->lane[i][0]<<endl;
file>>a->lane[i][1];
cout<<"a->lane["<<i<<"][1]: "<<a->lane[i][1]<<endl;
}
cout<<"Intersection inserted"<<endl;
delete a;
}
}
Text file:
4
1
2
2
2
2
2
3
2
2
4
2
2
Your lane is an array of 2 elements, however when i reaches 2 in your inner loop you are trying to print a->lane[2][0], which doesn't exist.
file>>a->lane[i][0]; //wrong
file>>a->lane[i][1]; //wrong
The indices should be reverse:
file>>(a->lane[0][i]); //correct
file>>(a->lane[1][i]); //correct
I added brackets just for clarity.
Besides, there is memory leak in your program. There should be as many delete as there are new statements, to ensure that there is no memory leak. So write these:
delete [] a->roadId;
delete [] a->lane[0];
delete [] a->lane[1];
delete a; //you've written only this!
Note delete a should be the last statement when deallocating the memory!
I don't mean to be nasty, but this code has enough problems it's almost difficult to decide which ones to start with.
using namespace std;
Here's the first red flag. About all I can say is that using namespace std; is a poor idea. With other namespaces it can be acceptable, but with std, it should always be avoided (IMO).
struct Intersection
{
unsigned short road;
long long int *roadId;
short *lane[2];
};
This strikes me as a pretty poorly designed structure. std::vector is a good thing. Use it. Rather than just a structure of dumb data, you might want to consider defining operator>> for your structure type, so you can read one directly. Even if you don't do that, from the way you're using it, what you really want is something more like:
struct road {
long long Id;
short lane[2];
};
struct Intersection {
int road_count;
road *roads;
};
Then, rather than a couple of parallel arrays all the same size that have to be walked in parallel, you get a a number of roads, each with its own data. std::vector is still better though.
int main(int argc, char** argv)
{
std::ifstream file;
cout<<"file: "<<argv[1]<<endl;
file.open(argv[1], std::ios::in);
Rather than defining an ifstream object and then opening it separately, you should normally plan on passing the name to the ctor so it's defined and opened in a single operation, something like:
std::ifstream file(argv[1]);
But, you also normally want to add a bit of error checking so you only attempt to use the command line argument as a file name if one has been passed, something like this:
if (argc < 2) {
std::cerr << "Usage: your_command <filename>\n";
return EXIT_FAILURE;
}
Then you'd have the code to define the ifstream.
while (!file.eof())
Here's another major problem. A loop of this form is essentially always wrong (including this case, from the looks of things).
cout<<"Start Intersection"<<endl;
Intersection *a = new Intersection;
There seems to be no reason to allocate this dynamically. Are you, perhaps, a recovering (or perhaps not recovering) Java or C# programmer? Java requires that all objects of user defined classes be allocated dynamically, but C++ does not.
file>>a->road;
a->roadId = new long long int[a->road];
a->lane[0] = new short[a->road];
a->lane[1] = new short[a->road];
cout<<"a->road: "<<a->road<<endl;
for (int i=0; i<a->road; i++)
{
file>>a->roadId[i];
cout<<endl<<"a->roadId["<<i<<"]: "<<a->roadId[i]<<endl;
file>>a->lane[i][0];
cout<<"a->lane["<<i<<"][0]: "<<a->lane[i][0]<<endl;
file>>a->lane[i][1];
cout<<"a->lane["<<i<<"][1]: "<<a->lane[i][1]<<endl;
}
I'd prefer to separate the code for reading data from the code for displaying data. Except for things like homework (or debugging) you rarely want to display lots of raw data as you're reading it. In any case, the reading code should normally reside in the operator>> for that class, and the display code in operator<< for the class.
cout<<"Intersection inserted"<<endl;
This seems to be an outright falsehood. You haven't actually inserted an Intersection into anything.
delete a;
When you quit allocating the Intersection dynamically, you'll be able to eliminate this as well. If you insist on handling all the dynamic allocation by hand, you need to delete the components before this to avoid having memory leaks (another reason to prefer to std::vector).
I know that may sound pretty negative, and that leaves me a bit torn. On one hand, I'd really like to suggest better ways to do things. At the same time, this looks enough like homework that I'm extremely hesitant to just post better code either. I've tried to include a few hints about better ways, but realize they're probably not quite as specific as you'd like -- I apologize for that, but given that it's probably homework I don't think I can be a lot more specific.