Using arrays and structures within functions in c++ - c++

I am trying to create a program that randomly generates the position of "ships". I'd like a structure to keep track of multiple aspects of the ships including their positions and an array to keep track of multiple ships.
The error I'm getting seems to be occurring in the first for loop within "main" at the line fleet[i] = ship_position (fleet[i], i); The error reads:
error: cannot convert 'ship_stats' to 'ship_stats*' for argument '1' to 'ship_stats ship_position(ship_stats*, int)'
Also, previously, I did not think the second "i" within the brackets of that line was necessary, but when I tried compiling without it the error I received was:
error: expected primary-expression before ']' token
#include <string>
#include <cstdlib>
#include <ctime>
using namespace std;
int rand_range (int low, int high) {
return rand() % (high - low + 1) + low;
}
struct ship_stats {
int x_coordinate;
int y_coordinate;
int weapon_power;
};
ship_stats fleet[5]; // Create fleet of 5 ships linked to the structure
ship_stats ship_position (ship_stats fleet[], int ship_num) {
//Randomly generate a starting position for each ship
int low_x = 0; //Set max and min ranges for ship position
int high_x = 1024;
int low_y = 0;
int high_y = 768;
fleet[ship_num].x_coordinate = rand_range (low_x, high_x);
fleet[ship_num].y_coordinate = rand_range (low_y, high_y);
return fleet[ship_num];
}
int main () {
int num_ships = 5;
for (int i = 0; i < num_ships; i++)
fleet[i] = ship_position (fleet[i], i); // <-- error is here
}

The mechanical point you have been given is that if you want to pass "raw" arrays as parameters in C++ (or C), you can't say fleet[]. That will not compile, as you noted. But don't just put a random index value in the brackets--that gets you an array element, not the array itself.
It's a somewhat gross oversimplification to say you pass the "whole raw array" just by saying fleet. You're really passing the address of the first element, e.g. fleet ends up being equivalent to &fleet[0]. Crude though that is, it comes from C's heritage...and it means that if the function you're calling knows the size of the "raw" array, then that address can be meaningfully used as a means of accessing any subsequent value in it.
But in "idiomatic" C++, one rarely wants to use a "raw" C-style array. The std::vector solves several weak points of raw arrays, and is a good choice for beginners.
You can choose to pass vectors "by value" (which makes a copy) or "by reference" (which is a bit like passing by pointer, the only choice for a raw array). Vectors don't have to know their size in advance, and their size can change over the course of your program. Not only that, the size comes along with the vector when it's passed as a parameter. And very importantly, vectors speak an abstract "collection protocol", which means they're usable with #include <algorithm>.
But there are several other points. You have made a ship_position() function that "constructs" a ship. This oddly shaped function returns a value (the instance of a constructed ship), yet also mutates your "fleet" so that the ship is in that position. Why would you need to return the value and assign it to the location in the fleet...if that mutation of the fleet was already part of the function?
And in C++, the best mechanism for "constructing" something is...a constructor. ship_position() is what we would call a "free function"--it doesn't live within ship_stat's definition, yet it seems to have an eerie knowledge of how to manipulate ships.
(Supporting Note: Where does weapon_power fit into all this? Whose job is it to initialize it, or not? This is where a single point of responsibility of a "constructor" comes into place, to say that a constructed ship has all its fields covered.)
If this is to be a proper C++ program, you shouldn't think of ship_stats as a struct that is operated on by "free functions". Instead, you need to think of Ship as a class with some data, and some code. The randomization of a ship should be inside your class... the act of putting a random ship into a collection should be using push_back into a vector (or emplace_back, but that's very much skipping ahead).
Try not to use raw C arrays in C++ programs unless you really know what you're doing. (Or don't use C++ features and instead tag your question C, the answers will be very different.)

Like already stated in the comments you are trying to pass one ship_stats to function thats waiting for an array of them , so for the function to work it should look like this
ship_stats ship_position (ship_stats fleet, int ship_num) {
//Randomly generate a starting position for each ship
int low_x = 0; //Set max and min ranges for ship position
int high_x = 1024;
int low_y = 0;
int high_y = 768;
fleet.x_coordinate = rand_range (low_x, high_x);
fleet.y_coordinate = rand_range (low_y, high_y);
return fleet;
}

Try
#include <string>
#include <cstdlib>
#include <ctime>
#include <iostream>
using namespace std;
int rand_range(int low, int high) {
return rand() % (high - low + 1) + low;
}
struct ship_stats {
int x_coordinate;
int y_coordinate;
int weapon_power;
};
ship_stats fleet[5]; // Create fleet of 5 ships linked to the structure
ship_stats ship_position(ship_stats IndividualShip, int ship_num) {
//Randomly generate a starting position for each ship
int low_x = 0; //Set max and min ranges for ship position
int high_x = 1024;
int low_y = 0;
int high_y = 768;
IndividualShip.x_coordinate = rand_range(low_x, high_x);
IndividualShip.y_coordinate = rand_range(low_y, high_y);
return IndividualShip;
}
int main() {
int num_ships = 5;
for (int i = 0; i < num_ships; i++) {
fleet[i] = ship_position(fleet[i], i); // <-- error is here
}
}
In the above code, I've changed the function parameters of ship_position to accept an individual ship rather than the array as a whole. Your code should compile. Also, if this is C++ rather than C, consider using the for loop
for (ship_stats& j : fleet)
std::cout << j.x_coordinate << " " << j.y_coordinate << endl;
to output the results of your program, using < iostream > of course.

Related

Vector in c++ using for loop

I am new to c++ in general. So I have been trying to learn about using vectors after someone recently helped with using an Arduino type project to read RFID tags. It really got me thinking I have no clue how to program. So I hit the books!
So here is the question: When I do the following code:
#include <iostream>
#include <vector>
struct Runner{
char runnerTag[32];
uint32_t ts;
};
std::vector<Runner > runners;
int main() {
std::cout << "Hello, Runners!\n";
for (int i = 0; i < 100; i++) {
std::string runnertg = "testTrackTag01";
uint32_t timeStamp = rand() % 100 + 1;
runners[i] = new Runner({runnertg, timeStamp});
}
return 0;
}
I get this annoying little message from xcode:
No matching constructor for initialization of 'Runner'
on line 16 of the above snippet. What in the world am I doing wrong?
The expression new Runner({runnertg, timeStamp}) has a type mismatch. runnertg is of type std::string, while the element Runner::runnerTag is of type char[32].
The expression runners[i] = new Runner({runnertg, timeStamp}); has another type mismatch. The element type of runners is Runner, while the expression new Runner({runnertg, timeStamp}) is of type Runner*.
runners[i] is out-of-bound access. The size of runners is 0. The elements runners[i] for all values of i does not exist.
There is memory leak since there is no matching delete for each new for all code path.
Don't use rand().
A lot of the code you're using is old style C with some C++ STL code mixed in. I will try and tackle a few issues one at at time.
struct is an abstract data type used (in general) to organise primitive data types. While the only difference between a struct and a class is that the latter defaults all members to private and in this case is not functional, it's a good to cut these things of at the pass.
Secondly, an array of chars is cumbersome, messy and prone to error. Try an std::string instead.
Finally, let's create a constructor taking our two parameters.
Thus:
#include <string>
class Runner {
public:
std::string runnerTag;
uint32_t ts;
Runner(std::string, uint32_t);
};
Next thing. Using an array index operator [] to access or modify an std::vector is dangerous and defeats the purpose of using a container and all the wonderful functionality that comes along with it.
Since you know for loops, let's try this:
for (int i = 0; i < 100; i++) {
std::string runnertg = "testTrackTag01";
uint32_t timeStamp = rand() % 100 + 1;
Runner Runner(runnertg, timeStamp);
runners.push_back(Runner);
}
At the end of your code, outside the scope of the main function, define the constructor as follows:
Runner::Runner(std::string rt, uint32_t ts) {
runnerTag = rt;
ts = ts;
}
This should get you started.
You cannot convert std::string to a char array like that. Change the type of the member variable runnerTag to std::string. Also, you are accessing vector elements that don't exist. Use resize to create them. Or better yet, use emplace_back to do both at once. Also, don't use int to iterate containers, but std::size_t. Also, don't use rand(), but the classes from the <random> header. That trick using % creates a non-uniform distribution.

Why does my array say write access violation partially through?

Updated to be copy/pasted and run. My bad.
I know I'm probably going to get the whole "this question was asked already" but I spent sometime looking and couldn't find a matching problem. It's very possible I just don't know enough to look in the right place.
When I call InitSortedArray() it runs through a seemingly random number of elements before throwing exception: write access violation. Everytime I run it it stops at a different element number. Any ideas?
#include <array>
#include <iostream>
using namespace std;
int * toSort;
const int SIZE = 100000;
void InitSortedArray()
{
srand(0);
toSort[0] = rand() % 5;
cout << toSort[0];
for (int i = 1; i < SIZE - 1; i++)
{
srand(0);
toSort[i] = toSort[i - 1] + rand() % 5;
cout << toSort[i] << endl;
}
}
void Search()
{
toSort[SIZE];
InitSortedArray();
}
int main()
{
Search();
}
int * toSort;
allocates a pointer to some data yet to be assigned to it. No data is ever assigned. You could
int * toSort = new int[100000];
but that picks up some memory management work you don't need. Any time you use new[] sooner or later you must delete[]. Instead use
const int SIZE = 100000; // place first so we can use it below
int toSort[SIZE];
or the more modern
const int SIZE = 100000; // place first so we can use it below
std::array<int, SIZE> toSort;
to declare an array.
toSort[100000];
in Search does nothing helpful (and is in fact harmful as it invokes Undefined Behaviour by accessing outside the bounds of toSort) and should be removed.
Extra stuff:
srand reseeds and restarts the random number generator. It is only in truly rare circumstances that you want to call it more than once, and in those cases there are many better options than srand and rand.
Place a single call to srand at the top of main and make absolutely certain you want srand(0) as this will always generate the exact same numbers on a given computer. It's great for testing, but not so good if you want a different sequence every time. Typical use is srand(time(NULL)) to seed the generator based on the ever-changing flow of time. That's still not all that good, but good enough for most cases where rand is in use.
It looks like you're using an uninitialized pointer that points to random space, and trying to store elements and access elements in it. Also, your inclusion of "array" doesn't make any sense here. I believe what you want to do here is initialize your toSort array to actually point to a section of memory that you intend to point it to:
int toSort[SIZE];
instead of
int * toSort;
If you're looking to use the STL array (which is likely highly recommendable) then you need to explicitly use it:
std::array<int, SIZE> toSort;
The nice thing about using the STL is it takes care of a lot of the memory access issues you can run into like memory access violation. Another helpful thing from the STL would be vector:
#include <vector>
std::vector<int> toSort;
then later: (this adds an item to the back of the vector)
toSort.push_back(<some number>);
and to access:
int somethingElse = toSort[<index number>];
Arrays: http://en.cppreference.com/w/cpp/container/array
Vectors: http://en.cppreference.com/w/cpp/container/vector

Trouble Finding lowest value in array in C++

help me to find out minimum value from the array in function4. I am getting 0 every time. Sometimes I get the value present at first index of the array as minimum value. Kindly review my code and help me to solve the problem.
#include <iostream>
using namespace std;
int count=0;
void function1(int a[]) {
for (count=0;count<100;count++) {
cin >> a[count];
if (a[count]==0)
break; }
}
int function2 (int a[]) {
int sum=0,avg=0;
for (int n=0;n<count;n++) {
sum=sum+a[n]; }
avg=sum/count;
return avg;
}
//maximum value
int function3 (int a[]) {
int max1=a[0];
for (int count=0;count<100;count++) {
if (a[count]>max1)
max1=a[count];
}
return max1;
}
//minimum value
int function4 (int a[]) {
int min1=a[0];
for (int count=0;count<100;count++) {
if (a[count]<min1){
min1=a[count];}
}
return min1;
}
int main () {
int a[100]={0};
function1(a);
cout <<"Average is : "<<function2(a)<<'\n';
cout <<"Maximum Value is : "<<function3(a) <<'\n';
cout <<"Minimum value is : "<<function4(a) << '\n';
}
It looks like you are trying to learn programming itself, and not only C++.
If you were to look how C++ gets the smaller element in a container, I'd advise you to look into STL documentation std::min_element().
This has been asked here before: How to find minimum value from vector?
But surely you still need a few hints before:
Name your functions intuitively. function4 is a terrible name for a function whose meaning is to find the lowest/smallest/minimum value in a container. How about calling it minimum?
Allways search before posting. StackOverflow is smart enough to search for you while you type.
The way you pass your array to your functions is a problem. You have a function that makes assumptions on array size with no guaranties. If you simply change your declaration from a[100] to a[10] your program will be accessing data outside array bounds.There are many solutions for it. Include an extra parameter telling the array size or use std::vector, for example.
1.Please study how parameters (specially arrays) can be passed in C++. Take a look at Passing arrays to and from functions safely and securely to begin.
IMPORTANT: Your data is being populated by function1() through console input. ** are you sure you are filling in 100 values in your array and none is ZERO? ** If you have any 0 in your array and no negative inputs, obviously the minimum value will be 0!
Maybe you can be confused with this line:
int a[100]={0}; // This initlizes the whole array to zero.
int a[100]={SOME_VAL}; // This initlizes the first element to SOME_VAL, and the rest of the array to zero.
So, probably the array has a lot of zeros, so you are getting the minimum.
But, you don't need to make this functions yourself, just use std::min_element
Example:
std::cout << "Minimum value is : " << *std::min_element(a,a+99) << std::endl;

C++ Storing Array in Separate File

I am working on a c++ program in which I have to pass an array to multiple sorting functions and compare the running times of the functions. For example, I have an array with 100 elements containing random numbers from 1 to 10. I have a bubble sort, merge sort, and quick sort function, and I have to pass the array to each function. However when I pass the array, the first sorting function changes the original array so that when it is passed to the next function it is already sorted. This is expected, but I was wondering how I would store this array in a separate file, perhaps a header file, to keep the original array unsorted for each function call.
Here is a layout of my code:
#include <iostream>
using namespace std;
//void bubblesort, mergesort, quicksort function prototypes
int main()
{
int a[100];
for (int i = 0; i < 100; i++)
a[i] = rand() % 10 + 1;
bubblesort(a);
mergesort(a);
quicksort(a);
return 0;
}
//void bubblesort, mergesort, quicksort function definitions
This code is obviously just a layout and the sorting functions aren't relevant for this question other than the fact that a call to a sorting function changes the original array. Thanks for your help.
You do not need files for this. Even though usual file systems on operating systems these days are rather nicely mapped to memory (in many cases this will be their cache) with delayed swapping to disk, interacting with the file system may make your code much more inefficient since you are writing to the disk.
Since you tagged this question with C++ I will answer this question the C++ way (or at least the C++ standard library way). What you want is to make a copy of the array when you pass it to the functions. At the moment you are passing in the raw address of the array so you are not making any copies (only possibly a copy of the pointer). This process is made easy if you use vectors. So the program could be
#include <iostream>
#include <vector>
using namespace std;
// The declarations would just need to change to this, I am assuming
// they print to stdout
void bubblesort(vector<int> vec);
void mergesort(vector<int> vec);
void quicksort(vector<int> vec);
int main()
{
vector<int> a;
for (int i = 0; i < 100; i++)
a.push_back(rand() % 10 + 1);
bubblesort(a);
mergesort(a);
quicksort(a);
return 0;
}
Here the vectors will be passed in by value so the vector that the function accesses is a copy of the original. The thing with vectors is that they are much more flexible and should usually be preferred over arrays in most high level programming scenarios.
If however your application demanded a use of low level arrays you could use memcpy to achieve this copying effect.
#include <iostream>
#include <vector>
using namespace std;
//void bubblesort, mergesort, quicksort function prototypes
int main()
{
int a[100];
for (int i = 0; i < 100; i++)
a[i] = rand() % 10 + 1);
int for_bubble_sort[100];
memcpy(for_bubble_sort, a, 100);
bubblesort(for_bubble_sort);
int for_merge_sort[100];
memcpy(for_merge_sort, a, 100);
mergesort(for_merge_sort);
int for_quick_sort[100];
memcpy(for_quick_sort, a, 100);
quicksort(for_quick_sort);
return 0;
}
Well, you should make an another array. Copy the contents of original array to this one using memcpy() or use a loop.
You can declare your array as const so it preserves it initial value and the functions don't change it.

Nested Struct and Array C++

Hello I am dealing with nested structs and arrays in C++, here is some background info:
struct Cells // a collection of data cells lines
cells :: [Cell] // the cells: a location and a value
nCells :: Integer // number of cells in the array
capacity :: Integer // maximum size of the array end
struct Cell
location :: int // a location of data cells lines
value :: int // the value end Cells
The code I have which won't compile (3 files, header, ADT implementation, main)
How am I declaring the nested struct in struct array wrong?
// Defines the cell.h ADT interface
struct Cell;
struct Cells;
struct Cells {
Cell cells[];
int nCells;
int capacity;
};
struct Cell {
int location;
int value;
};
//fill cells with random numbers
void initialize(Cells *rcells);
ADT Implementation
using namespace std;
#include <iostream>
#include <cstdlib>
#include "cell.h"
void initialize(Cells *rcells){
for(int i = 0 ; i < rcells->nCells; i++)
{
rcells->cells[i].location = rand() % 100;
rcells->cells[i].value = rand() % 1000;
}
}
main
using namespace std;
#include <iostream>
#include <cstdlib>
#include "cell.h"
int main(){
Cells *c;
c->cells[0].location=0;
c->cells[0].value=0;
c->cells[1].location=0;
c->cells[1].value=0;
c->nCells = 2;
c->capacity = 2;
initialize(c);
}
Your original declaration fails because in
struct Cells {
Cell cells[];
int nCells;
int capacity;
};
"cells" defined in this way is an array, which should have fixed size (unless it is the last member and you're using C99 standard). You may think it is the same as
Cell* cells
but it won't be converted to pointer type automatically in struct definition.
The C++ way to do such things is
typedef std::vector<Cell> Cells;
Your initialize function could be
void initialize(int ncell, Cells& cells) {
cells.resize(ncell);
for (Cell& cell : cells)
{
cell.location = rand() % 100;
cell.value = rand() % 1000;
}
}
Your main program should change a little bit
int main(){
Cells c;
initialize(2, c);
c[0].location=0;
c[0].value=0;
c[1].location=0;
c[1].value=0;
}
If you want cell count information, you can call
c.size()
There is no need for capacity variable because there is no upper limit on total number of cells.
By the way, this is not the nested struct people usually talk about. When one say nested struct, he often means nested struct definition. There is nothing special about an object containing other objects.
Unlike some other programming languages, when you declare an array in C or C++, it is created where you declare it. For example if you declare one as a function local variable, it will be created on the stack.
In you case Cell cells[]; declares an array that must be created within your class. Thus if you class have an array of four elements, the compiler needs to allocate to each instance 4*sizeof(Cell) bytes for the field so it can fit the array in the instance. If your array have 524 elements, it needs 524*sizeof(Cell) bytes.
You see the problem here : the compiler cannot guess what is the size of your object. Which is problematic to obtain the location of each field in an instance, especially if you declare two array without size. Note that this issue is not restricted to object fields : you cannot declare an array as a local variable in a function without giving a size either, for example. This because array have a fixed size determined upon creation. Thus wherever you create the array, you must provide its size.
When you write Cell array[] as a function argument, you are not creating an array, but only obtaining a pointer to it, so not giving its size is okay.
To solve your issue you must somehow make classes with a constant size. For example you can allocate you array dynamically with new[some_variable] and use pointer Cell *cells; in your class. A pointer has a fixed size, and you array is to be declared on the heap (don't forget to delete[] it).
Remark: instead of a size, giving an array initializer only is valid :
int x[] = {1, 2, 4}; //creates an array of three elements