C++: Syntax of passing a pointer array through a function - c++

So I have these 2 methods: the first is meant to take in 5 integer values, sum them up, then call the findLowest() method that returns the lowest found value, and subtracts that from the sum (then divides by 4 and prints results to screen).
I think the issue I'm having is the values it's returning are memory addresses. I've tried to understand how to dereference integers to get the value, but truth be told all of the online resources I've looked up have gone over my head.
Below is what I have so far:
void calcAverage(int* arr[5])
{
int sum = 0;
for (int a = 0; a < 5; a++)
sum += *arr[a];
sum -= findLowest(*arr);
cout << "AVERAGE " << (sum / 4) << endl;
}
int findLowest(int* arr[5])
{
int lowest = *arr[0];
for (int a = 1; a < 5; a++)
{
if ((int)arr[a] < lowest)
lowest = *arr[a];
}
return lowest;
}
On top of that, on the line that says
sum -=findLowest(*arr);
it pops up an error that reads
argument of type "int *" is incompatible with parameter of type "int **"
Thanks for the help in advance, and sorry if the post's a bit scattershot: I'm not really confident with this pointer/reference stuff to begin with.

You are almost there, but you should not dereference on this line:
sum -= findLowest(*arr);
Instead, just pass in the array, because that is what the function expects:
sum -= findLowest(arr);
Unrelated:
If you can, use a std::vector or std::array, the former for dynamically sized arrays, the latter for a compile time array. These both are safer, have more functions, and are easier to pass around.
Also use smart pointers for ownership of pointers instead of raw pointers. Smart pointers manage the ownership of an object so that you do not need to manually call new and delete.

Related

C++ Void double pointer interference with another

I am trying to do a project that involves overloading new and delete. I am storing an array of void pointers (pointers to random memory that is allocated) in a double void pointer. Of course, this array will need to be resized to account for further void pointers that come in.
This is the intialization of the array, allocArraySize(int) is set to 4.
void** allocArray = (void**) calloc ( allocArraySize, sizeof(void*) );
Setting all values to nullptr..
for(int i=0; i<allocArraySize; i++){ *(allocArray + i*sizeof(void*)) = nullptr; }
However, when trying to resize the array, I noticed that my original array of void pointers is modified when I create a new temporary array(temp) to store them in.
// PRINTS THE ORIGINAL ARRAY
for(int i=0; i<allocArraySize; i++){std::cout<<i<<" = "<<*( allocArray + i*sizeof(void*))<<"\n";}
void** tempArray = (void**)calloc(allocArraySize, sizeof(void*));
// PRINTS THE ORIGINAL ARRAY
for(int i=0; i<allocArraySize; i++){std::cout<<i<<" = "<<*( allocArray + i*sizeof(void*))<<"\n";}`
Notice, I am not even putting the array values in the temp array yet and I am still getting this problem. Why is that? why is this random value being assigned to this spot when it is indeed initialized? How is this one new temp array variable messing with my array?
NOTE: This is basically the complete code. Only thing missing is a main function, iostream, and the declaration for allocArraySize. Yes, WELL aware that I am not freeing these poor double pointers. I just wanted to create the problem in simplest terms possible.
The sizeof multiplier shouldn't be there:
*(allocArray + i*sizeof(void*))
// ^^^^^^^^^^^^^^ this shouldn't be here
void** is strongly typed. It participates in proper offset calculation via pointer arithmetic. There is no need here for sizeof offset calculations. That loop, which appears to be crafted to dump the pointer values in the sequence, should therefore be:
for(int i=0; i<allocArraySize; i++)
{
std::cout<< i << " = " << allocArray[i] << "\n";
}
You are indexing the pointers incorrectly i * sizeof(void*) rather than i.
for(int i=0; i<allocArraySize; i++){ allocArray[i] = nullptr; }
Firstly, you rather shouldn't use calloc in C++ code. Especially if you program uses both new expression and calloc\malloc, it may lead to to UB due to mismatching deletors.
allocArraySize got type void** , so it's pointer to pointer. Result of expression *allocArraySize got same sizeof as void* or uintptr_t type. Arithmetic with pointers automatically increment pointer by amount required to point at next object of same type.
C++ way to write it doesn't even require such arcane knowledge either, all you should do is to use a new expression and list-initialize it with empty list to get same effect as calloc does in C.
void** allocArray = ::new void*[allocArraySize] {};
for(int i = 0; i < allocArraySize; ++i)
{
std::cout<< i << " = " << allocArray[i] << "\n";
}
When using new/delete from within of overloaded one, it's essential to use :: or it would lead to infinite recursion.
allocArray[i] is an equivalent of *(allocArray + i)
Overloading new\delete aside. But truly C++ way to do that is to avoid naked pointers and use containers if possible. New\delete might be wrappers around usage of some memory pool class.
// do we really need a vector of pointers?
auto allocArray = std::vector<void*>(allocArraySize, nullptr);
int i = 0;
for( auto &v : allocArray )
std::cout<< (i++) << " = " << v << "\n";
In C++20 range-based for loop becomes more contained thanks to init-statement
for(int i = 0; auto &v : allocArray )
std::cout<< (i++) << " = " << v << "\n";

Pointer for array to calculate average in C++

I got a question on pointer in C++ :
Write a function that computes the average value of an array of floating-point data:
double average(double* a, int size)
In the function, use a pointer variable, not an integer index, to traverse the array elements.
And here is my solution :
int main()
{
const int size = 5;
double num_array[] = {2,2,3,4,5};
double* a = num_array;
cout << average(a,size);
cout << endl;
system("PAUSE");
return 0;
}
double average(double* a,const int size)
{
double total = 0;
for (int count =0; count< size; count++){
total = total + *(a + count);
}
return total/size;
}
It works fine but I have question on the for loop on pointer in average function. If I replace the statement in for loop with :
total = total + a*;
(I thought we supposed to do like this to add up all the number in array but unfortunately it gives me the wrong answer)
So what does the *(a + count) do? If possible, can somebody please simply brief me on how it works?
Thanks in advance.
a is a pointer to a double.
If you write *a, this pointer gets dereferenced and you get the data where the pointer points at, i.e. the double value. Note that the asterisk has to be in front of the pointer. (It's a "prefix" unary operator.)
a* is no valid syntax (it tries to multiply a with something which still has to follow ...)
a + count is pointer arithmetic. It gives you a but with count numbers of elements offset to the original a pointer. So it now points to the count-th element in the array.
*(a + count) now dereferences exactly this pointer, which gives you the count-th element of the array.
a[count] is exactly the same; it's just a nicer syntax.
Note: You can also use a++ in your loop. What it does is it increments the pointer by one position in the array. The next time you dereference a using *a, it returns the next entry. So your loop can be rewritten like this:
double total = 0;
for (int count = 0; count < size; count++){
total = total + *a; // Access the element a currently points to
a++; // Move the pointer by one position forward
}
You can even combine the increment and dereferencing operations into one expression. The postfix-increment syntax a++ will return the old pointer and increment the pointer by one position. Dereferencing a++ now means that you dereference the old pointer.
double total = 0;
for (int count = 0; count < size; count++){
total = total + *(a++);
}
The second note I want to give you is that you don't need your integer variable here to count the element. Since your pointer now already carries the information, your counter is now only used to stop the loop. This can also be done by comparing the pointer with some "end pointer", which we keep in a variable:
double total = 0;
double *end = a + size; // Store the end of the array
while(a < end) {
total = total + *(a++);
}
As you can see, I converted the for loop into a while loop since I no longer need to initialize or increment something (remember: going to the next entry of the array is done in the body!).
I hope this illustrates pointer arithmetic a little bit. You can "calculate" with pointers similarly as with indexing variables (your count variable). You can even subtract them to calculate offsets between pointers, for example.
* is the dereferencing operator, operating on the address a increased by count.
Read Pointers.

Error in passing 2-D array to double function_name

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).

How do I return a array from a function?

I'm learning about pointers in class but I never really understood arrays 100%
I have a assignment where I have to read in an array of student scores from a function. Each element of the array would hold a different score and the element identifies what student it is.
I'm trying to read the scores into a array but when it comes to returning it I'm lost. I've tried google but just get more confused because people talking about dynamic memory and using the new and delete operand which I haven't gotten to yet, and I don't want to do the
assignment wrong.
I have to user pointer instead of index to access elements in the array.
The code below gives me the error "redefinition of formal parameter 'scoreArray'"
#include <iostream>
using namespace std;
const int maxStudents = 30;
double readScores(double[]);
int main()
{
double scoreArray[maxStudents];
readScores(scoreArray);
cout<<scoreArray[1],scoreArray[2];
system ("PAUSE");
return 0;
}
double readScores(double scoreArray)
{
double scoreArray[maxStudents];
double *scorePTR;
*scorePTR = scoreArray;
for(int count = 0; count < maxStudents; count++)
{
cout<<"Please enter score for student "<<count+1<<" or -999 to end.\n";
cin>>*(scorePTR+count);
if(*(scorePTR+count) == -999)
break;
}
}
The error you get is because you named a local variable the same as the function's argument.
double readScores(double scoreArray /* parameter named scoreArray */)
{
double scoreArray[maxStudents]; // this cannot have the same name!
The code you've shown reveals a lot of confusion. I'll try to explain the mistakes in it.
cout<<scoreArray[1],scoreArray[2];
This will not output the elements 1 and 2. To do that, it should be cout << scoreArray[1] << scoreArray[2];. Also, note that arrays in C++ are 0-based, so the first element will be scoreArray[0], the second scoreArray[1], the third scoreArray[2], and so on.
The code declares a function named readScores taking a pointer to double and returning a double:
double readScores(double[]);
But it only defines a function taking a double:
double readScores(double scoreArray)
I'm sure that's not what was intended, and once the compiler error is fixed, it will produce a linker error because there's no definition for the double readScores(double[]) function.
Now, the arrays.
When you write a parameter as double x[], it's not an array. It's a pointer to a double. It's exactly the same as double* x. Yes, the syntax is highly misleading. That's why you shouldn't use it. It sows confusion. It's better to be explicit and call a pointer a pointer.
You cannot directly return arrays in C++ and you cannot directly pass array arguments in C++. You can pass references to arrays and return references to arrays, but here it seems you have instructions to use pointers, so I won't go there.
The code doesn't seem to be making use of the value returned from readScores, so it's probably better to just use a void return type. The code writes the values directly into the array anyway.
void readScores(double* scorePtr)
The syntax *(scorePTR+count) is exactly the same as scorePTR[count], so there's no gain in using it. And the code is iterating with an index (count) anyway.
I suppose what the assignment meant with that restriction was something actually useful, even if only marginally: iterate using a pointer, not an index. In order to do that, you need to find three things: how to start the loop, how to move to the next element and how to end the loop.
How to start the loop? You should start with a pointer to the first element. Luckily, such a pointer is exactly what gets passed as an argument to the function.
for(double* ptr = scorePtr; /* ... */; /* ... */)
How to move to the next element? If you increment the pointer, it moves to the next element.
for(double* ptr = scorePtr; /* ... */; ++ptr)
How to end the loop? The loop ends when the pointer has passed over the entire array. The array has maxStudents elements, so the loop ends when the pointer is maxStudents elements away from the start:
double* end = scorePtr + maxStudents;
for(double* ptr = scorePtr; ptr != end; ++ptr)
And how do you use this pointer in the loop? As normal, with the dereferencing operator.
for(double* ptr = scorePtr; ptr != end; ++ptr)
{
cout<<"Please enter score for student "<< /* (1) */ <<" or -999 to end.\n";
cin>>*ptr;
if(*ptr == -999)
break;
}
// (1) left as an exercise for the reader
double readScores(double scoreArray)
{
double scoreArray[maxStudents];
...
}
The compile error happens because you declared a local variable with the name scoreArray, which is the same name as that of the formal parameter double scoreArray. Change the name of one of them.
You're almost there:
double readScores(double scoreArray[]) {
double *scorePTR;
*scorePTR = scoreArray;
for(int count = 0; count < maxStudents; count++)
{
cout<<"Please enter score for student "<<count+1<<" or -999 to end.\n";
cin>>*(scorePTR+count);
if(*(scorePTR+count) == -999)
break;
}
}
I also suggest switching to "straight" array syntax when accessing the array, rather than relying on array-as-pointer semantic, i.e. use scoreArray[count] rather than *(scoreArray+count) in your expressions:
double readScores(double scoreArray[]) {
for(int count = 0; count < maxStudents; count++)
{
cout<<"Please enter score for student "<<count+1<<" or -999 to end.\n";
cin >> scoreArray[count];
if(scoreArray[count] == -999)
break;
}
}
P.S.: I assume that you have not started learning about STL; more appropriate solutions exist with the use of standard C++ library.

using the qsort() function

I'm a student & i looked up this function in a book. It works as it should but i don't quite understand the inner workings of the sortFunction() which is passed to the qsort() function. If some one could explain it in detail, please do. Thanks in advance.
#include<iostream>
#include<stdlib.h>
using namespace std;
//form of sort function required by qsort()
int sortFunction(const void *intOne,const void *intTwo);
const int tableSize = 10;
int main()
{
int i, table[tableSize];
//fill the table with values
for(i = 0; i < tableSize; i++)
{
cout << "Enter value " << (i + 1) << " : ";
cin >> table[i];
}
cout << "\n";
//sort values
qsort((void*)table, tableSize, sizeof(table[0]), sortFunction);
//print the results
for(i = 0; i < tableSize; i++)
{
cout << "Value " << (i + 1) << " : " << table[i] << endl;
}
cout << "\nDone\n";
return 0;
}
int sortFunction(const void *a, const void *b)
{
int intOne = *((int*)a);
int intTwo = *((int*)b);
if (intOne < intTwo)
{
return -1;
}
if (intOne == intTwo)
{
return 0;
}
return 1;
}
If you look at the actual call to qsort...
qsort((void*)table, tableSize, sizeof table[0], sortFunction);
...you'll see it provides:
a void* address and the size (in bytes) of the entire data array to be sorted, then
the size of one data element in that array, then
a pointer to the comparison function "sortFunction".
There's no argument passed that allows qsort to know what the type of the element is - i.e. how the individual bits in any single data element are used to represent some data value - so there's no way qsort can meaningfully compare two such elements. When you supply...
int sortFunction(const void *a, const void *b)
{
int intOne = *((int*)a);
int intTwo = *((int*)b);
...and qsort calls it, you're getting two pointers - they're to memory addresses but when qsort calls sortFunction those void pointers still tell you nothing about the data element type, as qsort has no insight itself to pass along. The last two lines of code above are where you - the programmer coordinating the qsort call - reapply the knowledge you've had all along about what the data element type is: in this case, they're ints, so you cast each void* to an int* (using (int*)a), then dereference that int* to get the int at memory address a. Similarly for b. In doing so, you've recovered the two numbers that were there as numbers. Then, the job of sortFunction is to indicate how they should be ordered when sorting finishes. To indicate that a should be first, sortFunction can return any negative value (e.g. -1); if they're equivalent, return 0;, and if b should be first, return any positive value (e.g. 1). qsort() receives that information and uses it to work out how to shuffle the data elements around as it sorts.
FWIW, C lets you express that a bit more succinctly as...
return intOne < intTwo ? -1 :
intOne == intTwo ? 0 :
1;
...or (faster, but relying on boolean comparison results being 0 and 1, which may confuse some programmers reading your code)...
return (intOne > intTwo) - (intOne < intTwo);
...or, if you're sure the following can never be mathematically less than INT_MIN (such values wrap around to a big positive number inappropriately)...
return intOne - intTwo;
sortFunction isn't actually doing the sorting, it is being used as a comparison function to determine whether one element should precede another in the sorted list.
What you called 'sortFunction' is normally called a comparator. It basically tells the generic sort code in qsort() whether two elements in the array being sorted compare equal (0), or whether the first argument sorts before the second (<0) or the first argument sorts after the second (>0).
With that information, plus the size of each row, plus the number of rows in the array and the start of the array, the qsort() function can order the data correctly.
As you can see in documentation, qsort function takes a comparator as it's last parameter. This function is used to actually compare parameters (tell which one should go first in a sorted array).