Error in passing 2-D array to double function_name - c++

I am working on a program that reads in altitude values from a file into a 2-D array, a matrix, and I am trying to pass that array to another function that finds the maximum value. I understand that, by default, arrays are passed by reference, but I am not trying to change the values of the array in the function so this shouldn't matter much. I have gone through several pages about calling arrays but I haven't been able to find any mention of the type of error I am getting when I compile the code. The problem seems to be in the number of arguments that are called or the way in which the are called, but I can't see any discrepancies in the various appearances of the function. My guess is there is something about passing a 2-D array that I wasn't told in class and that I haven't learned yet on my own. Any help would be greatly appreciated.
The code is:
#include <fstream>
#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
// First instance of function declaration
double find_max(double elevations[][3600], double ilat, double ilon, int nlat, int nlon);
int main(int argc, char *argv[]) {
// Declare program variables
double lat_init, lon_init;
double lat_res, lon_res;
double peak, valley;
int lon_col, lat_row;
string indat, inpoints;
.
.
.
double elevations[lat_row][lon_col];
// Open and read topographic data file
ifstream topo_points;
topo_points.open(inpoints.c_str());
for (int i=0; i<lat_row; i++) {
for (int j=0; j<lon_col; j++)
topo_points >> elevations[i][j];
}
// Call function to find peak in the data
peak = find_max(elevations, lat_init, lon_init, lat_row, lon_col);
return 0;
}
// ***** Here lie the functions *****
// This function reads in the array of elevations, initial latitude and longitude
// of the data, and the number of data points and uses this information to find
// the latidude and longitude of the highest point on earth
double find_max(double elev[][3600], double ilat, double ilon, int nlat, int nlon) {
double num, max;
double latpos, lonpos;
max = 0;
for (int i=0; i<nlat; i++) {
for (int j=0; j<nlon; j++) {
num = elev[i][j];
if (num > max) {
max=num;
latpos= ilat - i;
lonpos= ilon + j;
}
}
}
cout << "The tallest peak on earth has an altitude of " << max;
cout << " and is located at " << latpos << "deg latitude and ";
cout << lonpos << "deg longitude";
return max;
}
However, when I call the function I get the following error:
error: cannot convert 'double (*)[(((long unsigned int)(((long int)lon_col) - 1)) + 1u)]' to 'double (*)[3600]' for argument '1' to 'double find_max(double (*)[3600], double, double, int, int)'

From what i see in the code, there are a few glitches.
You have defined the array elevations as
double elevations[lat_row][lon_col];
which isn't gonna work, because the size of the c-style arrays must be determinable during compile-time. And since lat_row and lon_col are variables, that's an error.
So, you could either use arrays with dynamic memory allocation, or std::vector, which in most cases is preferable. So, in your case you could have something like:
typedef std::vector< std::vector<double> > ElevationsType;
ElevationsType elevations;
and then just use that array or array of double.
Then, your find_max function can be declared as:
double find_max(const ElevationsType &elevations, double ilat, double ilon);
Note that in this case you won't need to pass nlat and nlon, because you could just do:
ElevationsType::size_type nlat, nlon, i, j;
nlat = elevations.size();
for (i = 0; i != nlat; ++i) {
nlon = elevations[i].size();
for (j = 0; j != nlon; ++j) {
const double element = elevations[i][j];
// do whatever you need to do with the element
}
}
Of course, if your arrays will have fixed size you could set it (std::vector::resize) once you create the object of type ElevationsType, or just allocate enough space (std::vector::reserve) and then initialize it. If it's large, that may increase performance.
However, if you choose to go with c-style arrays, it would be something like:
double **elevations = (double **)malloc(sizeof(double*) * lat_row);
for (size_t i = 0; i != lat_row; ++i) {
elevations[i] = (double*)malloc(sizeof(double) * lat_col);
// initialize the elements
for (size_t j = 0; j != lat_col; ++j) {
elevations[i][j] = 100.0; /* your value */
std::cout << "elevations[" << i << "][" << j << "] = " << elevations[i][j] << std::endl;
}
}
which is more tedious for many people.. so to speak. And if you go in that route, just don't forget to deallocate all allocated memory with free().
you could also use the c++ new operator to allocate the memory, but the principle is pretty much the same.
So I'd suggest you to use the std::vector. It's easier to work with, at least if you have limited experience. It will also take care of memory allocation/deallocation, and that causes many bad things, overflows, leaks, etc. which will be avoided if you use the vector.

You're trying to pass an array whose size is determined dynamically (i.e. at runtime), and pass it to a function which expects the array to have its 2nd dimension determined at compile time to be 3600 (which seems like a pretty reasonable thing to complain about, actually).

Related

Converting array int values to doubles

I have a two-dimensional templated array of integers that I need to perform division on and convert to doubles (in order to create a percentage). It is being passed to my function in the function definition as
int votesarr[4][2]
For each int in the array, I need to run a for loop (I assume) to divide the number by 10,000 and cout the resulting double value.
I'm unsure how to work this with the conversion as well as what I need to pass to the function that I haven't already (if anything).
This should do:
int arint[4][2] { {1,2},{ 2,3 },{0,1},{0,2} }; //example intarray arint[x][y];
for (auto &x : arint)for (auto &y : x)std::cout << y / 10000.0 << std::endl;
This will iterate each of arint[x] and for them each of arint[y], and output those with a line seperating. I just left the formatting as basic as possible. The .0 after 10.000 will output the result with decimals.
Based on the extra information you provided in the comments, here is a simple way to just iterate through the int matrix and output the values as floating-point values.
const std::size_t rows = 4;
const std::size_t cols = 2;
double divisor = 10000.0;
int votesarr[rows][cols]; // fill this somewhere...
for (std::size_t i = 0; i < rows; ++i) {
for (std::size_t j = 0; j < cols; ++j)
std::cout << static_cast<double>(votesarr[i][j])/divisor << ' ';
std::cout << '\n';
}
That said, if you are passing votesarr around to different functions then I'd advise to use either:
std::array<std::array<int, 2>, 4> votesarr; // compile time dimensions known
or
std::vector<std::vector<int>> votesarr(4, std::vector<int>(2));
to make it simpler, instead of using C-style arrays which decay to pointers when passing to methods (preventing proper use of sizeof to determine dimensions, forcing you to pass the rows, cols to the functions).
so you need something like:
double percentage = (double)votesarr[i][j]/10000.0;
std::cout >> percentage >> std::endl;
the (double) tells the compiler that you want to cast this to a double. You can do this with (char), (int), (customType) etc...
However, division is a special case--because my 10000.0 has that ".0" at the end, the compiler treats it as a double, and (int) / (double) is treated like (double)/(double)
#include <iostream>
using namespace std;
int main()
{
int votesarr[4][2] = {{1,1},{1,1},{1,1},{1,1}};
double result[4][2];
double temp;
for (int i = 0; i <= 3; i++) {
for (int j = 0; j <= 1; j++) {
temp = votesarr[i][j];
temp = temp/10000;
result[i][j] = temp;
}
}
// I just filled out the arrays by i+j
//then you need to divide each one by 10,000
//
return 0;
}

I get the error invalid types 'float[int]' for array subscript?

I am quite new to programming,so I really need help. I need to wrtie a function which produce 2d arrays with random values. here is my code:
#include <iostream>
#include <ctime>
#include <cstdlib>
using namespace std;
float randArray(int row, int column);
int main()
{
int r = 10, c = 8;
float fckMmd = randArray(r,c);
///printing the array:
for (int row=0; row<r; row++){
for (int column=0; column<c; column++){
cout << fckMmd[row][column] << " ";
}
cout << endl;
}
}
float randArray(int row, int column){
srand(time(NULL));
float *randArr;
randArr = new int [row][column];
for(int k=0; k<row; k++){
for(int kk=0; kk<column; kk++){
randArr[k][kk] = rand();
}
}
return randArr;
}
But I get the error mentioned above. Where is the problem? help me please
randArr is a float * but you try to allocate a 2d array in it. A 2d array is not the same thing as a pointer. Your function only returns 1 float as well. I suggest you use vectors (also so you don't leak memory). Furthermore you should only call srand ONCE, not every time, and be aware rand() returns an integer, not a floating point value.
std::vector<std::vector<float>> randArray(int row, int column)
{
std::vector<std::vector<float>> randArr(row);
for (auto& v : randArr)
{
v.resize(column);
}
for(int k=0; k<row; k++)
{
for(int kk=0; kk<column; kk++)
{
randArr[k][kk] = static_cast<float>(rand());
}
}
return randArr;
}
It's because fckMmd is only a float and not a pointer or array.
First:
float *randArr;
declares a pointer to float. You then do
randArr = new int [row][column];
which allocates memory for a 2D array of ints (incompatible types, technically you allocate memory for a pointer to arrays of type int[column]), hence the error.
You're better using a std::vector instead, or, if you want a manually-managed dynamically allocated 2D array, use float **randArr; instead, and allocate
float** randArr;
randArr = new float* [rows];
for(int i = 0; i < row; ++i)
randArr[i] = new float[col];
or
float (*randArr)[col]; // pointer to array float[col]
randArr = new float[row][col];
Other issues: most of the time, srand must be used only once in the program. It is a good idea to call it in main() and not bury it into a function, since you may end up calling the function multiple times.
Last issue: if you want speed, you're better off using a single flat array (or std::vector) and map from 2D to 1D and vice versa, since your data will be guaranteed to be contiguous and you'll have very few cache misses.

Error: cannot convert 'int (*)[(((sizetype)(((ssizetype)n) + -1)) + 1)]' to 'int (*)[100]' for argument '1' to 'int determ(int (*)[100], int)'|

I have that error but I'm sure I have the same data type and I didn't do anything wrong I suppose. It's for calculating the determinant of a matrix. Someone help. I really can't think of why I have this error :(
#include <iostream>
#include <stdio.h>
#include <cmath>
using namespace std;
double determinant(double matrix[100][100], int order)
{
double det, temp[100][100]; int row, col;
if (order == 1)
return matrix[0][0];
else if (order == 2)
return ((matrix[0][0] * matrix[1][1]) - (matrix[0][1] * matrix[1][0]));
else
{
for (int r = 0; r < order; r++)
{
row = 0;
col = 0;
for (int i = 1; i < order; i++)
{
for (int j = 0; j < order; j++)
{
if (j == r)
continue;
temp[row][col] = matrix[i][j];
col++;
}
row++;
}
det += (matrix[0][r] * pow(-1, r) * determinant(temp, order - 1));
}
return det;
}
}
int main()
{
int n;
cout << "Enter the dimension: ";
cin >> n;
double elem[n][n];
for (int i = 0; i < n; i++)
{
cout << "Enter row " << i << ": ";
for (int j = 0; j < n; j++)
{
cin >> elem[i][j];
}
cout << endl;
}
cout << determinant(elem, n);
return 0;
}
your prototype is
double determinant(double matrix[100][100], int order)
and you call it with
determinant(elem, n);
when
double elem[n][n]; that is a "dynamic" array size so not 100x100
it seam compiler assumes n is 1 at compile time so
obviously double array [1][1] can't be converted to [100][100]
as you wrote it even if your input matrix data is 1x1 you have to store it in 100x100 array.
just declare double elem[100][100];
finally at run time ensure user input n < 100 to avoid a bug
You have three problems.
First, the size of elem is unknown at compile time. You should use elem[100][100] if you really want the variable on the stack and the size of the matrix really is 100x100.
Second, your determinant function creates a 10 thousand element matrix on the stack and it is recursive, which means you'll get a lot of them and likely run out stack space. You should consider using a single temp matrix and reusing this for each recursive step.
Third, since you need the matrix size it to be dynamic, declare it on the heap. Something like:
double* elem = new double[n * n];
Strictly speaking you do not need to do this, but it will not waste as much memory as a 100x100 matrix if you are calculating the determinant of small matrices.
If you use a one dimensional array, you can pass in an array of any size to determinant (the determinant function should also take a one-dimensional array or double* instead of double[100][100]). You will have to calculate the index yourself using matrix[order*j+i].
double elem[n][n]; is illegal in C++. Arrays must have dimensions known at compiletime.
Your bizarre error message is a result of a compiler attempting to support double elem[n][n] as an extension, but not doing a very good job of it.
One way to fix this would be to change your code to be double elem[100][100]; .
To fix it without wasting memory and sticking to Standard C++, you should use std::vector instead of a C-style array. It is simpler to code to use a vector of vectors, although for performance reasons you may want to use a 1-D vector.
Also, you would need to refactor determinant slightly as you don't really want to be allocating new memory each time you do another step of the recursion. The determinant function needs to know what dimension of memory is allocated, as well as what dimension you want to calculate the determinant on.

Segmentation fault and mysterious loop behavior

I am working on a homework assignment with a few specific requirements. There must be a class named TestScores that takes an array of scores as its argument. It throws an exception if any scores are negative or greater than 100. Finally, it must have a member function that returns an average for all the scores. I wasn't clever enough to find a way to only pass the array into the constructor, so I also added in an int that tells the size of the array.
Running the code (I haven't even gotten around to testing the exceptions yet), I keep getting a Segmentation fault error. Valgrind and gdb have been rather unhelpful, outputting messages like:
==9765== Jump to the invalid address stated on the next line
==9765== at 0x2200000017: ???
Even more mysteriously (to me at least), in the for loop in the client code, my incrementor, i, somehow gets bumped from 0 to a seemingly random two-digit number right after creating the TestScores object. In previous versions, before I started using rand() to populate the array, i just never incremented and did the infinite loop thing.
Here's the contents of TestScores.cpp:
#include <iostream>
using std::cout;
using std::endl;
#include "TestScores.h"
#include <stdexcept>
using std::runtime_error;
// Constructor.
TestScores::TestScores(int a[], int s):
_SIZE(s), _scores()
{
// Look at each item in a[], see if any of them are invalid numbers, and
// only if the number is ok do we populate _scores[] with the value.
for (int i = 0; i < _SIZE; ++i)
{
if (a[i] < 0)
{
throw runtime_error ("Negative Score");
}
else if (a[i] > 100)
{
throw runtime_error ("Excessive Score");
}
_scores[i] = a[i];
cout << _scores[i] << " ";
}
cout << endl;
}
// Finds the arithmetic mean of all the scores, using _size as the number of
// scores.
double TestScores::mean()
{
double total = 0;
for (int i = 0; i < _SIZE; ++i)
{
total += _scores[i];
}
return total / _SIZE;
}
// median() creates an array that orderes the test scores by value and then
// locates the middle value.
double TestScores::median()
{
// Copy the array so we can sort it while preserving the original.
int a[_SIZE];
for (int i = 0; i < _SIZE; ++i)
{
a[i] = _scores[i];
}
// Sort the array using selection sort.
for (int i = 0; i < _SIZE; ++i)
{
int min = a[i];
for (int j = i + 1; j < _SIZE; ++j)
{
if (a[j] < min)
{
min = a[j];
a[j] = a[i];
a[i] = min;
}
}
}
// Now that array is ordered, just pick one of the middle values.
return a[_SIZE / 2];
}
And here's the client code:
#include <iostream>
#include "TestScores.h"
#include <stdexcept>
#include <cstdlib>
#include <ctime>
using std::exception;
using std::cout;
using std::endl;
int main()
{
const int NUM_STUDENTS = 20,
NUM_TESTS = 4;
int test [NUM_TESTS][NUM_STUDENTS];
// Make random seed to populate the arrays with data.
unsigned seed = time(0);
srand(seed);
// Populate the scores for the individual tests graded for the semester.
// These will all be values between 0 and 100.
for (int i = 0; i < NUM_TESTS; ++i)
{
for (int j = 0; j < NUM_STUDENTS; ++j)
{
test[i][j] = rand() % 100;
cout << test[i][j] << " ";
}
cout << endl;
}
// Now we have the data, find the mean and median results for each test.
// All values should be valid, but we'll handle exceptions here.
for (int i = 0; i < NUM_TESTS; ++i)
{
cout << "For Test #" << i + 1 << endl;
try
{
cout << "i = " << i << endl; // i = 0 here.
TestScores results(test[i], NUM_STUDENTS);
cout << "i = " << i << endl; // i = some random number here.
cout << "Mean: " << results.mean() << endl;
cout << "Median:" << results.median() << endl << endl;
}
catch (exception &e)
{
cout << "Error, invalid score: " << e.what() << endl;
}
cout << "For Test #" << i + 1 << endl;
}
return 0;
}
Edit:
The header was requested as well:
#ifndef TEST_SCORES_H
#define TEST_SCORES_H
class TestScores
{
private:
const int _SIZE;
int _scores[];
public:
// Constructor
TestScores(int a[], int);
double mean() const,
median() const;
};
#endif
I played around with making the array dynamic, and didn't initialize the array as empty, which fixed my problems, so that's what I ended up turning in. That leads me to a few follow-up questions.
Before going dynamic, I played around with initializing the array, _scores, by trying to give it the size value that was supposed to already be initialized. This led to compiler problems. I talked with my teacher about that, and he said that you can't allocate space for an array unless there's a hardwired global constant. That is, you can't pass a size value in the constructor to initialize an array. Is that true, and if so, why?
Stepping back a bit, it seems to me that dynamic arrays are better if you need a lot of values, because then you don't need a contiguous block of space in memory. So if you are making small arrays, it seems like a waste of space and time typing to make dynamic arrays. Is this untrue? Should I be doing all arrays from now on as dynamic? This experience certainly changed my opinion on the utility of regular arrays, at least as they pertain to classes.
Also, though I got full credit on the assignment, I feel like I violated the spirit by passing an argument for size (since the literal problem statement reads: "The class constructor should accept an array of test scores as its argument"). Aside from a hardwired global constant or having a size argument, is there a way to pass just the array? I swear I spent a good hour trying to think of a way to do this.
It seems you don't initialize _scores at all. You need _scores = new int[s]; at the top of the constructor (and also delete[] s; in the destructor).
Without initializing _scores, you write things to undefined memory locations.
Without TestScores.h one has to guess, but given what you say about the value of i being corrupted in the loop where you're creating the TestScores objects, that points to your _scores member variable not being properly initialized and when you're trying to load it you are actually trashing memory.
Once TestScores.h is visible, I'll revisit this answer taking the file into account.
Updated now that TestScores.h is available.
The problem is that you are not initializing _scores. You are not actually allocating any memory to hold the array, let alone setting the pointer to point to that memory. So when you attempt to store things into the array you're just trashing memory somewhere.
The first line in your constructor should be:
_scores = new int[_SIZE];
That will allocate memory to hold _SIZE ints and set _scores to point to that memory. Then your assignments to _scores[i] will actually go into defined memory belonging to your program.
Of course, you also have to release this memory (C++ won't do it for you) when instances of TestScore get destroyed. So you will need to define and implement a destructor for TestScores and that destructor needs to contain the line:
delete [] _scores;
This will free the block of memory that _scores points to. You can read docs on the delete operation to see why the [] have to be there in this case.

give feedback on this pointer program

This is relatively simple program. But I want to get some feedback about how I can improve this program (if any), for example, unnecessary statements?
#include<iostream>
#include<fstream>
using namespace std;
double Average(double*,int);
int main()
{
ifstream inFile("data2.txt");
const int SIZE = 4;
double *array = new double(SIZE);
double *temp;
temp = array;
for (int i = 0; i < SIZE; i++)
{
inFile >> *array++;
}
cout << "Average is: " << Average(temp, SIZE) << endl;
}
double Average(double *pointer, int x)
{
double sum = 0;
for (int i = 0; i < x; i++)
{
sum += *pointer++;
}
return (sum/x);
}
The codes are valid and the program is working fine. But I just want to hear what you guys think, since most of you have more experience than I do (well I am only a freshman ... lol)
Thanks.
Fix the memory leak.
i.e delete temp;
Also, check if the file is open/created..etc
ideally, you should manipulate/traverse the array using your temp variable instead of using *array itself
You are not initializing your array correctly. This statement:
double *array = new double(SIZE);
Allocates one double and initializes it to the value of SIZE. What you should be doing is using array allocation:
double *array = new double[SIZE];
Another general problem is you rarely ever want to assign dynamically allocated memory to a raw pointer. If you want to use base types instead of higher level objects such as std::vector, you should always use a smart pointer:
boost::scoped_array<double> array(new double[SIZE]);
Now the array will automatically get freed regardless of how you leave your scope (i.e. from a newly added return or from an exception).
Since we're talking about C++, I would suggest using STL containers and algorithms. I also find that in most cases it's better to use references or smart pointers (e.g. boost::shared_ptr) instead of raw pointers. In this case there's no need for pointers at all.
Here is how you could write your program:
#include <fstream>
#include <vector>
#include <iostream>
#include <numeric>
#include <iterator>
using namespace std;
int main()
{
ifstream f("doubles.txt");
istream_iterator<double> start(f), end;
vector<double> v(start, end);
if (v.empty())
{
cout << "no data" << endl;
return 0;
}
double res = accumulate(v.begin(), v.end(), 0.0);
cout << "Average: " << res / v.size() << endl;
return 0;
}
If x is 0, then Average will generate a divide-by-zero error.
Here are some "code review" comments:
In main():
Change SIZE to "size_t" instead of int
Why SIZE is uppercase? (May be the author's convention is to have constants as uppercase, in that case it is fine.)
Combine temp declaration and assignment into one statement as: double * temp = array;
What if inFile is not available or can't be opened for reading?
What if inFile have less than SIZE number of items?
Change the loop variable i to size_t.
Remove blank line before declaration of inFile.
Return some number (e.g. 0) from main().
Correct the allocation of array.
In Average():
Change the second argument of Average to size_t.
Assert and/or guard for pointer being non-NULL
Assert and/or guard against division by zero.
Acknowledgement: Some points are collected from other answers. I tried to make a complete list as far as I could.