Variable length arrays depending on length of file C++ - c++

I'm encountering a problem trying to generalize my algorithm for any-size problems.
The code is working for the test problem I used, but I had to insert manually the lenght of some arrays. Next, I've tried reading the lenght of input files in two variables, but then I'm not able to use them in all of my code, but just in some pieces. I think it's quite a stupid thing, but I'm really new to C++ and I'd like to get help.
Here's the piece of code:
#include <fstream>
#include <iostream>
#include <time.h>
using namespace std;
struct node{
int last_prod;
int last_slot;
float ZL;
float ZU;
float g;
bool fathomed;
node *next;
node *padre;
node *primofiglio;
};
clock_t start, end;
double cpu_time_used;
int l=0;
int cont_slot=0;
int cont_prod=0;
float temp_cont;
float distanze[360]; // dichiarazione variabili
int slot[111];
int slot_cum[111];
float COIp[111];
int domanda[111];
float Zb=9999999999999999;
float LowerBound(struct node *n);
float UpperBound(struct node *n);
float h(struct node *l,struct node *n);
void creasottolivello(struct node *n);
void fathRule2(struct node *n);
void fathRule3(struct node *n);
void stampaRisultati(struct node *n, ofstream &f);
int unFathomedNodes(struct node *n);
void append(struct node* temp, struct node* n);
void ricercaOttimo(struct node *n, ofstream &f);
void calcoloBounds(struct node *n);
int main(){
start = clock();
ifstream contdist_file ( "/Users/MarcoBi/Desktop/TESI di LAUREA/Xcode/dati/distanze.txt" ); // conteggio dati input
if ( !contdist_file.is_open() ) { //conta righe file slot
}
else {
for(int i=0; !contdist_file.eof(); i++){
contdist_file >> temp_cont;
cont_slot++;
}
}
ifstream contslot_file ( "/Users/MarcoBi/Desktop/TESI di LAUREA/Xcode/dati/slot.txt" );
if ( !contslot_file.is_open() ) { //conta righe file prodotti
}
else {
for(int i=0; !contslot_file.eof(); i++){
contslot_file >> temp_cont;
cont_prod++;
}
}
....
As you can see, in the main() I count the lenght of input files into cont_prod and cont_slot variables, but then I can't use them in variable declaration. The variable lenght arrays I need have to be global variables 'cuz I need them also in other functions. And also cont_prod and cont_slot need to be global, as I need them in local variable declarations in some functions.
Here is one of the functions I need to use them in:
float LowerBound(struct node *n){ //funzione LowerBound
int S[111];
int Sp=0;
float d[111];
float dmin[111];
float D;
float LB;
for(int i=n->last_prod;i<111;i++){
Sp=Sp+slot[i];
}
for(int i=0;i<111;i++){ //Calcolo S_pigreco
S[i]=0;
}
if(n->last_prod==0){ //condizione necessaria per nodo radice
S[0]=slot[0];
for(int i=n->last_prod +2;i<111;i++){
for(int j=n->last_prod +1;j<=i;j++){
S[j]=S[j-1]+slot[j];
}
}
}
else{
for(int i=n->last_prod +1;i<111;i++){
for(int j=n->last_prod;j<=i;j++){
S[j]=S[j-1]+slot[j];
}
}
}
S[110]=S[109] + slot[110];
//calcolo somma distanze da slot j+1 a q
for(int i=0;i<111;i++){
d[i]=0;
}
for(int j=n->last_prod;j<111;j++){
for(int i=n->last_slot; i < n->last_slot +S[j]; i++){
d[j]=d[j]+distanze[i];
}
}
//calcolo dmin_pigreco
for(int i=n->last_prod; i<111; i++){
dmin[i]= d[i]/S[i];
}
D=0;
for(int i=n->last_prod; i<111; i++){
D=D+dmin[i]*domanda[i];
}
LB=n->g+2*D;
return LB;
}
111 is cont_prod and 360 is cont_slot.
I'm programming on a Mac in Xcode and it says that variable lenght arrays cannot be declared at file scope, which I think it means as global variables.
How can I manage that?

Just focusing on your actual question here: in C++, you create variable length-arrays using std::vector, like this:
std::vector<char> myCharArray( n * 1000 );
You can then use the expression
&myCharArray[0]
to use the vector object in all cases where you'd normally pass a raw C array.

Perhaps declare pointers at file scope and allocate memory dynamically as and when you know the values...
Declare
int *slot
and allocate memory as
slot = new int[cont_slot];
and after using dont forget to "delete [] slot" it .. :)

Disclaimer: I didn't read the whole question, but it seems to me like you need either a dynamically allocated array:
float* distanze = new float[length];
or, better yet, a std::vector:
std::vector<float> distanze; // <-- this is the proper C++ way
You can insert values in the vector via distanze.push_back(float) and iterate through it just like it was an array, with operator [].

For starters, you should learn to format your code.
Secondly, in C++, an array is normally declared with something like:
std::vector<float> anArray;
The declaraion using a [] is a left-over from C, and is only used in
very special cases (once you've fully mastered std::vector). And a
vector will extend itself automatically if you use push_back to insert
values. And an std::vector carries its size around with it, so you
can iterator using:
for ( int i = 0; i != v.size(); ++ i ) {
// use `v[i]` here...
}
You can also iterate using iterators, which is more idiomatic in general
(but perhaps not in the case where you are doing numerical work).
Finally, std::istream::eof() is really only useful once input has
failed (to know whether the failure is due to end of file, or something
else). The usual idiom to read would be something like:
float value;
while ( contdist_file >> value ) {
distanze.push_back( value );
}
(I'm supposing that this is what you actually want in the first loop.
In the code you've posted, you just read into a temporary variable,
overwriting each time, but not otherwise doing anything with the value
you read.)
Finally, unless your vectors may be very large, it's usual to use
double in C++, rather than float. (But this depends on the
total amount of data you need to handle, as well as the precision you
need.) Note too that a loop with:
Sp += slot[i];
will likely give very poor results if the size of slot is large,
unless you're lucky with the values in slot. If the values are in the
range of 0.5...1, for example, after a couple of thousand values, with
float, you only have about 3 or 4 decimal digits of precision, and if
the first value happens to be 10000000, any following values less than 1
are treated as zero. Typically, you need special algorithms to sum up
floating point sequences. (Using double will improve things, but not
eliminate the problem.)

Related

C++ Arrays and Vectors

I am new to C++ and this is not really part of my major so I am a little lost! If I can contact anyone personally for help please let me know :)
My program will need to read in ten integer values from a file, and store them in an array or vector. The reading of the values should be done in a separate function that takes an integer array as a parameter, and read from a file named tempInput.txt. I am unsure how to create an integer array as a parameter.
Then, from main, you will call another function, whose signature and return type is thus:
bool isDangerous(int tempArray[ ]);
If you could help me with part one or two that would be great!
namespace std;
int divison(int,int);
int main()
{
void readData(int tempArray[ ]);
int tempInput[10];
readData(tempInput);
//int size=10; //Array size
int sum =0;
//for(int i=0;i<size;i++) //Loop which inputs arrays data and
// {
//cout << myArray[i] << endl;
// }
return 0;
}
As best as I can understand the question, here's some code to get you started (Note that I haven't filled in everything exactly, I don't want to do your work for you)
#include<fstream> //So we can read from files
#include<iostream>
using namespace std;
void readData(int tempArray []) {
//Open file and read data into temp array
//If you need help reading data, see:
//http://www.cplusplus.com/doc/tutorial/files/
}
bool isDangerous(int tempArray []) {
//Do things
}
int main() {
int tempInput [10];
readData(tempInput); //Read the data into tempInput
bool result;
result = isDangerous(tempInput); //Do something with isDangerous
return 0;
}

Returning a string * type array from a function back into the main

I'm new to C++ and I am working on a function to shuffle strings
It takes an array of strings, shuffles them, and returns them back to the main.
I am returning a pointer to an array of strings called shuffled. The problem I have is that when I try to save that new pointer to the array to another pointer in the main, I start getting weird values that either reference to a file location in my computer or a bunch of numbers.
I'll post the entire code here but really what you want to look at is the return types, how I return it and how I save it in main. Please tell me why my pointer is not referencing the working array that is created in the function. Here's the code:
#include <cstdio>
#include <string>
#include <ctime>
#include <new>
#include <cstdlib>
using namespace std;
const char * getString(const char * theStrings[], unsigned int stringNum)
{
return theStrings[stringNum];
}
string * shuffleStrings(string theStrings[])
{
int sz = 0;
while(!theStrings[sz].empty())
{
sz++;
}
sz--;
int randList[sz];
for(int p = 0; p < sz; p++)
{
randList[p] = sz;
}
srand(time(0));//seed randomizer to current time in seconds
bool ordered = true;
while(ordered)
{
int countNumberInRandList = 0;//avoid having a sz-1 member list length (weird error I was getting)
for(int i = 0; i < sz; i++)
{
int count = 0;
int randNum = rand()%(sz+1);//get random mod-based on size
for(int u = 0; u < sz; u++)
{
if(randList[u] != randNum)
{
count++;
}
}
if(count == sz)
{
randList[i] = randNum;
countNumberInRandList++;
}
else
i--;
}
//check to see if order is same
int count2 = 0;
for(int p = 0; p < sz; p++)
{
if(randList[p] == p)
{
count2++;
}
}
if(count2 < sz-(sz/2) && countNumberInRandList == sz)
{
ordered = false;
}
}
string * shuffled[sz];
for(int r = 0; r < sz; r++) //getting random num, and str list pointer from passed in stringlist and setting that value at shuffled [ random ].
{
int randVal = randList[r];
string * strListPointer = &theStrings[r];
shuffled[randVal] = strListPointer;
}
for(int i = 0; i < sz; i++)
{
printf("element %d is %s\n", i, shuffled[i]->c_str());//correct values in a random order.
}
return *shuffled;
}
int main()
{
string theSt[] = {"a", "b", "pocahontas","cashee","rawr", "okc", "mexican", "alfredo"};
string * shuff = shuffleStrings(theSt);//if looped, you will get wrong values
return 0;
}
Strings allocate their own memory, no need to give them the "length" like you would have to do for char arrays. There are several issues with your code - without going into the details, here are a few working/non-working examples that will hopefully help you:
using std::string;
// Returns a string by value
string s1() {
return "hello"; // This implicitly creates a std::string
}
// Also returns a string by value
string s2() {
string s = "how are you";
return s;
}
// Returns a pointer to a string - the caller is responsible for deleting
string* s3() {
string* s = new string;
*s = "this is a string";
return s;
}
// Does not work - do not use!
string* this_does_not_work() {
string s = "i am another string";
// Here we are returning a pointer to a locally allocated string.
// The string will be destroyed when this function returns, and the
// pointer will point at some random memory, not a string!
// Do not do this!
return &s;
}
int main() {
string v1 = s1();
// ...do things with v1...
string v2 = s2();
// ...do things with v2...
string* v3 = s3();
// ...do things with v3...
// We now own v3 and have to deallocate it!
delete v3;
}
There are a bunch of things wrong here -- don't panic, this is what happens to most people when they are first wrapping their brains around pointers and arrays in C and C++. But it means it's hard to put a finger on a single error and say "this is it". So I'll point out a few things.
(But advance warning: You ask about the pointer being returned to main, your code does indeed do something wrong with that, and I am about to say a bunch of things about what's wrong and how to do better. But that is not actually responsible for the errors you're seeing.)
So, in shuffleStrings you're making an array of pointers-to-string (string * shuffled[]). You're asking shuffleStrings to return a single pointer-to-string (string *). Can you see that these don't match?
In C and C++, you can't actually pass arrays around and return them from functions. The behaviour you get when you try tends to be confusing to newcomers. You'll need to understand it at some point, but for now I'll just say: you shouldn't actually be making shuffleStrings try to return an array.
There are two better approaches. The first is to use not an array but a vector, a container type that exists in C++ but not in C. You can pass arrays around by value, and they will get copied as required. If you made shuffleStrings return a vector<string*> (and made the other necessary changes in shuffleStrings and main to use vectors instead of arrays), that could work.
vector<string *> shuffleStrings(...) {
// ... (set things up) ...
vector<string *> shuffled(sz);
// ... (fill shuffled appropriately) ...
return shuffled;
}
But that is liable to be inefficient, because your program is then having to copy a load of stuff around. (It mightn't be so bad in this case, because a smallish array of pointers isn't very large and because C++ compilers are sometimes able to figure out what you're doing in cases like this and avoid the copying; the details aren't important right now.)
The other approach is to make the array not in shuffleStrings but in main; to pass a pointer to that array (or to its first element, which turns out to be kinda equivalent) into shuffleStrings; and to make shuffleStrings then modify the contents of the array.
void shuffleStrings(string * shuffled[], ...) {
// ... (set things up) ...
// ... (fill shuffled appropriately) ...
}
int main(...) {
// ...
string * shuffled[sz];
shuffleStrings(shuffled, theSt);
// output strings (main is probably a neater place for this
// than shuffleStrings)
}
Having said all this, the problems that are causing your symptoms lie elsewhere, inside shuffleStrings -- after all, main in your code never actually uses the pointer it gets back from shuffleStrings.
So what's actually wrong? I haven't figured out exactly what your shuffling code is trying to do, but that is where I bet the problem lies. You are making this array of pointers-to-string, and then you are filling in some of its elements -- the ones corresponding to numbers in randList. But if the numbers in randList don't cover the full range of valid indices in shuffled, you will leave some of those pointers uninitialized, and they might point absolutely anywhere, and then asking for their c_strs could give you all kinds of nonsense. I expect that's where the problem lies.
Your problem has nothing to do with any of the stuff you are saying. As you are a beginner I would suggest not presuming that your code is correct. Instead I would suggest removing parts that are not believed to be problematic until you have nothing left but the problem.
If you do this, you should quickly discover that you are writing to invalid memory.
part two : you can't seem to decide on the type of what you are returning. Are you building a pointer to an array to return or are you returning an array of pointers.... you seem to switch between these intermittently.
part three : read #Gareth's answer, he explains about passing parameters around nicely for your instance.

c++: passing vector of pointers into a function

In a program I am writing I have a vector of pointers to try and save memory usage and although this will make my program more efficient I am having trouble passing the vector of pointers into the function direct(). Any help with the correct syntax for passing this into the function is greatly appreciated
The current error being shown is : "error cannot convert 'std::vector*>' to 'const string'... for argument '1'...
The line this error is being flagged on is the line in which the function direct is called
#include <iostream>
#include <vector>
using namespace std;
// a function used to display an array used for testing purposes
void display_array(const string *arr, size_t size )
{
int i;
for (i = 0; i < size; i++){
cout<<(int(arr[i][0]))-64;
cout<<(int(arr[i][1]))-64;
cout<<",";
}
}
// Takes in the connections to the start and the connections to the end and returns the connection if
//there is a direct connection else returns 0
string direct(const string *destination, char *start, size_t destination_size) {
for (int i = 0; i<destination_size;i++)
if ((&destination[i][0] == start) or (&destination[i][1] == start))
return destination[i];
}
int main()
{
string current;
std::vector<string> paths;
std::vector<string*> start_connections;
std::vector<string*> destination_connections;
char start;
char destination;
cout<<"Input paths in the form 'AB'(0 to exit)\n";
cin>>current;
while (current != "0"){
paths.push_back(current);
cin>>current;
}
cout<<"Input starting location\n";
cin>> start;
cout<<"Input final destination\n";
cin>>destination;
for(int i = 0; i < paths.size(); i++) {
if ((paths[i][0] == destination) or (paths[i][1] == destination)) //all connections to the destination
destination_connections.push_back(&paths[i]); // paths stored as a pointer to paths array
if ((paths[i][0] == start) or (paths [i][1] == start)) //all connections to the start
start_connections.push_back(&paths[i]); // paths stored as a pointer to paths array
}
cout<<direct(&destination_connections,&start,destination_connections.size());
if( !paths.empty() )
display_array( &paths[0], paths.size() );
}
The compiler's telling you exactly what's wrong - a vector is not a pointer.
Ideally, you shouldn't be using pointers at all - declare your vectors as
std::vector<std::string>
and pass a reference to the function using it
... direct(const std::vector<std::string> & dest, ...)
You then just pass the vector as if by value, but the reference operator tells the compiler to just pass its address instead of the whole object.
You also get the benefit of not having to pass its size separately, as the function iterating through it can access that directly (although accessing it by index isn't really the OO way).
In C++, if you're using a naked pointer, you're probably doing it wrong ;)
You are trying to pass a vector<string*>* where a string* is expected.
Change this:
direct(&destination_connections, &start, destination_connections.size());
To this:
direct(&destination_connections[0], &start, destination_connections.size());
Or this, if you are using C++11:
direct(destination_connections.data(), &start, destination_connections.size());
That being said, or is not a valid C++ keyword, you need to use || instead. And I think you are mishandling pointers inside of display(). You need to do a code review of what you are really trying to accomplish.

Constructor issue <Unable to read memory>

I have to create a class Histogram and make operations on this class. The input can be one dimensional array or a two dimensional array. The problem appears when i convert the array into a matrix. This what i have tried so far. The error is <Unable to read memory>
histrogram.h
#ifndef HISTOGRAM_H
#define HISTOGRAM_H
#include<iostream>
class Histogram
{
private:
int** matrix;
int lines;
void SortMatrix();
public:
Histogram(){ }
Histogram(int elements[], int elementsNr);
Histogram(int** m, int l);
void Print();
};
#endif
historgram.cpp
#include"histogram.h"
using namespace std;
Histogram::Histogram(int** m, int l)
{
matrix=m;
lines=l;
SortMatrix();
}
Histogram::Histogram(int elements[], int elementsNr)
{
lines=0;
//initialize matrix : elementrNr lines and 2 columns
int** matrix=new int*[elementsNr];
for(int i=0;i<elementsNr;i++)
{
matrix[i]=new int[2];
matrix[i][0]=INT_MIN;
matrix[i][1]=INT_MIN;
}
//search each element from the array in the matrix
bool found=false;
for(int i=0;i<elementsNr;i++)
{
found=false;
for(int j=0;j<elementsNr;j++)
{
//the element was found in the matrix ( on the first column )
if(matrix[j][0] == elements[i])
{
matrix[j][1]++;
found=true;
break;
}
}
if(!found)
{
matrix[lines][0]=elements[i];
matrix[lines][1]=1;
lines++;
}
}
SortMatrix();
}
void Histogram::SortMatrix()
{
bool flag=true;
int temp;
for(int i=0;(i<lines) && flag;i++)
{
flag=false;
if(matrix[i+1][0]>matrix[i][0])
{
temp=matrix[i][0];
matrix[i][0]=matrix[i+1][0];
matrix[i+1][0]=temp;
flag=true;
}
}
}
void Histogram::Print()
{
for(int i=0;i<lines;i++)
{
cout<<matrix[i][0]<<" : " <<matrix[i][1]<<endl;
}
}
main.cpp
#include"histogram.h"
#include<iostream>
using namespace std;
int main()
{
int arr[]={6,7,3,1,3,2,4,4,7,5,1,1,5,6,6,4,5};
Histogram h(arr,17);
h.Print();
}
Here
int** matrix=new int*[elementsNr];
replace with
matrix=new int*[elementsNr];
becausematrix is already a member variable. You are creating a new temporary variable double pointer named matrix and allocating memory to it rather than your member variable matrix
A couple of people have already given you advice about how to fix some of the problems with this code. I'll give slightly different advice that may initially seem a bit brutal by comparison, but I'll try to demonstrate how it's honestly useful rather than nasty.
I would throw out your existing code with the possible exception of what you have in main, and start over, using an std::map. What you're doing right now is basically trying to re-create the capabilities that std::map already provides (and even when your code is fixed, it's not doing the job as well as std::map does right out of the box).
Using map, your whole program comes out to something like this:
std::ostream &operator<<(std::ostream &os, std::pair<int, int> const &d) {
return os << d.first << " : " << d.second;
}
int main() {
std::map<int, int> h;
for (int i=0; i<17; i++)
++h[arr[i]];
std::copy(h.begin(), h.end(),
std::ostream_iterator<std::pair<int, int> >(std::cout, "\n"));
return 0;
}
If you want to maintain virtually the same interface as your histogram class provided, it's pretty easy to do that -- the for loop goes into the constructor, the copy into print (and SortMatrix disappears, because a map is always sorted).
By doing this, you change from an O(N2) algorithm to an O(N log N) algorithm. The bugs others have pointed out disappear completely, because the code that contained them is no longer needed. The only real disadvantage I can see is that the result will probably use a bit more memory -- it uses a balanced tree with individually allocated nodes, which is likely to introduce a fair amount of overhead for nodes that only contain 2 ints (and a bit for balancing). I can't quite imagine worrying about this though -- long before you have enough nodes for the memory usage to become significant, you have way too many to present to even consider presenting to the user.
#mathematician1975 already provided an answer for the main problem. There's another bug in SortMatrix(): you only swap the elements of the first column, therefore after sorting, the counts (in the second column) will not be correct anymore. You'll have to insert
temp=matrix[i][1];
matrix[i][1]=matrix[i+1][1];
matrix[i+1][1]=temp;
to get it working.

Delete a record in an array

int i;
int Input;
cin >> Input;
for(i = 0; i < Size ; i ++ )
if (List[i].PersonID == Input) {
}
I am trying to make a function that deletes a record from the array based on the id input provided. I am not sure what to do beyond this here. Will I also need to shift the values in the array after a record is removed?
I can't tell what type your List is.
But you should go for something like this:
List.RemoveAt(i--);
List.DeleteAt(i--);
i-- will decrement i AFTER the function has been called.
You should not need to shift any values in the array if you are using the standard containers.
If you are responsible for the array, then you do need to shift your values.
** EDIT
Here is a link to an introduction to the standard containers. If you are managing your own dynamic array you should consider using these instead.
Here I'm assuming List is a primitive array of ints.
#include<algorithm> // where std::remove() resides
#include<iterator> // where std::distance() resides (not strictly necessary)
struct BadPerson {
BadPerson(int Bad) : Bad_(Bad) { }
bool operator()(const Element& Elem) const {
return Elem.PersonID == Bad_;
}
};
// ...
int *NewEnd = std::remove_if(List, List + ListLength, BadPerson);
// the list now has a new end, because elements were "removed".
// but they weren't really removed; the array still has the same fixed size.
int ListLength = std::distance(List, NewEnd);
I think the best way to remove elements from an array/vector is to use a copy approach with something like:
int write_ptr = 0;
for (int read_ptr=0; read_ptr < n; read_ptr++)
{
if (... keep element array[write_ptr] ? ...)
{
if (read_ptr != write_ptr)
array[write_ptr] = array[read_ptr];
write_ptr++;
}
}
// The new size of the array is write_ptr
This will allow to remove even multiple elements with just one pass.
The standard library includes this approach as std::remove_if, however until C++0X arrives it's annoying to use because of limitations of the language (the code needed to be able to specify the test becomes easily quite ugly).
int i;
int Input;
cin >> Input;
for(i = 0; i < Size ; i ++ )
{
if (List[i].PersonID == Input)
{
for(int j=i;j<size-1;j++)
{
List[j]=List[j+1];
}
}
}