C++ - Accessing values in dynamic arrays - c++

I have an assignment that requires the following:
-Take command line input for rows and columns and dynamically create a 2-D array filled with random numbers
-Create a function called find_greatest_product to find the largest product of four adjacent
numbers in the array. The four adjacent numbers can be any configuration of the shapes
found in the game Tetris in the array. Your function needs to return the max product, starting
position, shape, and direction of the four numbers using a struct.
Yes, it's a totally useless program purely to practice 2-D arrays.
I've got my array set up so I started with the easiest shape: the box. However, when I try to access the array full of random numbers, the product and factors all seem to be 0. Any hints as to why I'm unable to access the ints within the array of random numbers to find the product? The relevant bits of code are below. You can assume all functions not copied here work fine.
struct shape {
int highest;
int factors[4];
int startRow;
int startColumn;
} tShape, sShape, iShape, boxShape;
int main(int argc, char* argv[]) {
if(argc == 5) {
for(int i = 1; i < argc; i++) {
rows = getArg(argc, argv, i, compare1);
}
for(int i = 1; i < argc; i++) {
columns = getArg(argc, argv, i, compare2);
}
}
int ** array = new int*[rows];
int i, j;
for (i = 0; i < rows; i++) {
array[i] = new int[columns];
}
create_array(array, rows, columns);
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
cout << array[i][j];
cout << " ";
}
cout << endl;
}
boxProduct(array, rows, columns, boxShape);
cout << boxShape.highest << endl;
for (int i = 0; i < 4; i++) {
cout << boxShape.factors[i];
cout << " ";
}
cout << endl;
return 0;
}
void boxProduct(int *array[], int rows, int columns, shape boxShape) {
int highest = 0;
int product = 0;
for (int i = 0; i < rows - 1; i++) {
for (int j = 0; j < columns - 1; j++) {
product = (array[i][j]*array[i][j+1]*array[i+1][j]*array[i+1][j+1]);
if (product > highest) {
boxShape.highest = product;
boxShape.factors[0] = array[i][j];
boxShape.factors[1] = array[i][j+1];
boxShape.factors[2] = array[i+1][j];
boxShape.factors[3] = array[i+1][j+1];
}
}
}
}
Here is a sample output with a matrix 10 rows x 5 columns:
27 86 4 41 44
17 6 5 40 32
42 58 14 95 53
8 28 95 27 91
63 22 27 49 2
38 37 39 37 76
9 17 14 13 10
10 30 16 67 22
49 10 33 63 5
86 71 86 34 50
0 <- product
0 0 0 0 <- the four factors

C and C++ functions are call by value by default, not call by reference. That is, the compiler makes copies of the arguments to give to functions, and if the function modifies its arguments, it modifies a copy.
Consider this example:
void foo( int x )
{
x++; // increments foo's own local copy of 'x'
}
int main()
{
i = 42;
cout << i << endl; // prints 42
foo(i);
cout << i << endl; // ALSO prints 42!
return 0;
}
This will print 42 twice, because foo modifies a copy.
If you modify the code slightly, you tell the C++ compiler to pass the argument by reference. (Note: This is a C++ only feature; it does not work in C.) Now, any modification to the argument inside the function will modify the value the caller sees also:
void foo( int& x ) // The & means "pass this parameter by reference"
{
x++;
}
int main()
{
i = 42;
cout << i << endl; // prints 42
foo(i);
cout << i << endl; // prints 43
return 0;
}
An alternate way to modify a value held by the caller is to pass a pointer to that value, rather than the value itself. This is still call by value, but in this case the value you pass the function is a pointer. Example:
void foo( int* x ) // x is now a pointer to integer
{
(*x)++; // The (*x) dereferences the pointer. What happens if you leave off the parens?
}
int main()
{
i = 42;
cout << i << endl; // prints 42
foo(&i); // the & there takes the address of 'i' and passes that to foo()
cout << i << endl; // prints 43
return 0;
}
Because C does not support call-by-reference arguments, it requires this last scheme. Some C++ code also uses pointers in this way. Modern C++ style tends to avoid bare pointers wherever possible, but you'll still see pointers from time to time.
Punchline: You'll want to apply this knowledge to your shape boxShape structure above. You either want to pass shape boxShape by reference, or pass a pointer to shape boxShape. Both are valid approaches, although C++ tends to prefer passing a reference.

Related

Can't change a vector's element value at index i

In Stroustrup's Programming: Principles and Practice Using C++, chapter 4, exercise 13, I have to write a program to find all the prime numbers in a given range using the Sieve of Erathostenes.
So far, I have come up with this:
vector<int> values;
void initialize_values()
{
for (int i{0}; i < 100; ++i)
values.push_back(1);
}
void remove_composites(vector<int> values)
{
for(int i{2}; i * i < values.size(); ++i)
{
if (values[i] == 1)
{
for (int p{i + i}; p < values.size(); p += i)
values[p] = 0; //not working
}
}
}
int main()
{
initialize_values();
remove_composites(values);
for (int i{2}; i < values.size(); ++i)
{
if (values[i] == 1)
cout << i << " ";
}
cout << '\n';
return 0;
}
I create a vector with size 100 (in this first case) and initialize elements to 1. Then I check all indexes multiples of i while i * i < 100 and change the value at those indexes to 0 and finally print the indexes whose value is 1.
The problem is that values[p] = 0 is not assigning the value 0 to the element at index p and I don't really understad why.
EDIT So after reading comments and answers I decided to move all code under main(), because I don't know how to use references.
The goal of this exercises, according to the book, is to get used to processing user input, working with loops, iterations, etc. It's not intended to be professional nor expert at this point.
To all people with many years coding and answering questions here, remember you were once learners and beginners. Have some respect and don't turn this community into a toxic one.
Updated code:
int main()
{
vector<int> values;
for (int i{0}; i < 100; ++i)
values.push_back(1);
for(int i{2}; i * i < values.size(); ++i)
{
if (values[i] == 1)
{
for (int p{i + i}; p < values.size(); p += i)
{
//cout << p << " ";
values[p] = 0;
}
//cout << '\n';
}
}
for (int i{2}; i < values.size(); ++i)
{
if (values[i] == 1)
cout << i << " ";
}
cout << '\n';
return 0;
}
And works as expected:
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97
Thanks everyone.
The problem is that values[p] = 0 is not assigning the value 0 to the element at index p
It is assigning it.
The problem is that you are operating on a copy of the original vector, and that copy is local to remove_composites, which is why the calling code doesn’t see the changes.
Change your function signature to use a reference type parameter: std::vector<int>&.
There are also some other issues with your code (using the wrong type, i.e. int instead of bool; inconsistent signatures; mutable global variables).

Why is my code displaying a number 53 when I'm running my functions in c++

My friend created a program that prints a triforce to the console, however when he ran his code he realized that it printed weird numbers instead of what was supposed to run.
The code looks like this:
using namespace std;
#include <iostream>
void ZeldaTriangle(int Size){
for (int row = 0; row < Size; row++)
{
for (int spa = 0; spa < (Size-row-1); spa++)
{
cout << (" ");
}
for (int col = 0; col < (row +1); col++)
{
cout << ("#");
}
cout << "" << endl;
}
}
void triforce_up (int Size, int character){
for (int row = 0; row < (Size); row++)
{
for (int spa = 0; spa < (Size*2-row-1); spa++)
{
cout << (" ") << flush;
}
for (int col = 0; col < (row +1); col++)
{
cout << character << flush;
}
cout << "" << endl;
}
}
void triforce_down (int Size, int character){
for (int row = 0; row < (Size); row++)
{
for (int spa = 0; spa < (Size-row-1); spa++)
{
cout << (" ");
}
for (int col = 0; col < (row +1); col++)
{
cout << character;
}
for (int spa = 0; spa < ((Size-row-1)*2); spa++)
{
cout << (" ");
}
for (int col = 0; col < (row +1); col++)
{
cout << character;
}
cout << "" << endl;
}
}
void print_ZeldaTriangle (int Size, int character){
triforce_up (Size, character);
triforce_down (Size, character);
}
int main() {
int Size = 6;
print_ZeldaTriangle(Size, '5');
}
It should display a triforce created with the number "5", but instead it shows this with the number 53.
53
5353
535353
53535353
5353535353
535353535353
53 53
5353 5353
535353 535353
53535353 53535353
5353535353 5353535353
535353535353535353535353
I have attempted to change the "int character" to "string character" in order to prevent the error from happening but that displays a broken triforce that looks nothing like it should look like.
5
55
555
5555
55555
555555
5 5
55 55
555 555
5555 5555
55555 55555
555555555555
"void ZeldaTriangle(int Size)"
You don't need this function
when you convert char to int
your output is somewhat like this:
5 5
55 or 55
555 555
5555 5555
55555 55555
555555 555555
then
your code is correct Syntactically it is printing what it is meant to print.
but logically you yourself is lacking basic imagination.
either you can insert spaces in between or insert extra value to it
if you want output either like this or that...
5 5
5 5 555
5 5 5 55555
5 5 5 5 5555555
5 5 5 5 5 555555555
5 5 5 5 5 5 55555555555
your code is good the only thing you need is some result imagination :)
i have simplified the code: https://repl.it/repls/FluffyMildMenu
And
about the "53" error i don't know for sure but I think it is related to some charcater converted to int inside the code..
You are passing 5 as char but your functions accept integer value. When you pass a char value your functions will use ASCII value as int value. If you look at ASCII table '5' represents 53. Please refer link below:
https://www.ascii-code.com/
53 is the ASCII value of character '5', change function signature to
void triforce_up (int Size, char character)
void triforce_up (int Size, char character)
I guess, as you are expecting in in the
print_ZeldaTriangle (int Size, int character) {
}
and inputing this
print_ZeldaTriangle(Size, '5');
The char is converted to int, which is bad as
Char 5 when converted to int is 53
See this table for reference https://www.cs.cmu.edu/~pattis/15-1XX/common/handouts/ascii.html
So, to fix this, do this
int main() {
int Size = 6;
print_ZeldaTriangle(Size, 55);
}
EDIT:- Do 55, instead of 5
https://repl.it/repls/NoteworthyEnviousFactor

Array of Pointers getting garbage value in c++

I'm trying to create an array of pointers to a 2D (5 X 12) array in C++.
The ptr array has 5 elements. Each element should hold the address of the 1st element of the respective row of the 2D array. So 1st element should point to 1st element of 1st row, 2nd element should point to 1st element of 2nd row, and so on.
The 5th element of my array of pointers seems to point to a garbage value.
Code and output shown below. Can anyone please let me know why?
#include <iostream>
#include <cstdlib>
#include <iomanip>
using namespace std;
int main( )
{
int rainMatrix[5][12] = {{0}}; //declare and initialize rain matrix
int *matrix_ptr[5] = {NULL};//declare and initialize array of pointers
int **matrix_ptr_ptr = matrix_ptr;
for (int i = 0; i < 5; ++i)
matrix_ptr[i] = &rainMatrix[i][0];
rainGen(matrix_ptr_ptr, 5, 12); //generate a random matrix
//display the matrix
for (int i = 0; i < 5; ++i) {
for (int j = 0; j < 12; ++j) {
cout << setw(2) << rainMatrix[i][j] << " ";
}
cout << endl;
}
for (int i = 0; i < 5; ++i)
cout << setw(2) << *matrix_ptr[i] << " " << rainMatrix[i][0] << endl;
return 0;
}
void rainGen (int **pptr, int row, int col)
{
unsigned int seed = 43;
unsigned int rv;
srand(seed);
for (int i = 0; i < row; ++i) {
for (int j = 0; j < col; ++j) {
rv = rand() % 100;
**pptr = rv;
*pptr += 1;
}
pptr++;
}
}
OUTPUT
11 1
88 11
28 88
25 28
1477892712 25
You're manipulating the wrong pointer in the innermost loop. Consider the pointer arithmetic carefully:
pptr essentially points to matrix_ptr[0];
on the first iteration, the double indirection means **pptr will set what you want, but then
*pptr += 1 will modify the contents of matrix_ptr[0], which means it no longer points to the beginning of the matrix.
Subsequent passes through the loop compound the situation drastically.
Modifying pptr won't help because it actually points to the wrong thing: it points to matrix_ptr, so incrementing it merely once moves its address from that of matrix_ptr[0], which points to rainMatrix[0][0], to that of matrix_ptr[1], which points to rainMatrix[1][0]. That is the wrong address for the next entry of the matrix, which is rainMatrix[0][1]. In essence, you've moved to the next row, instead of to the next column.
Try this for the innermost loop instead:
for (int i = 0; i < row; ++i)
{
auto qptr = *pptr;
for (int j = 0; j < col; ++j)
{
rv = rand() % 100;
*qptr = rv;
qptr += 1;
}
pptr++;
}
}
In this case, qptr is given the address of the first entry in the matrix. *qptr = rv sets the value. qptr += 1 increments the position of qptr while leaving *pptr alone - and, by extension, it leaves matrix_ptr[0] alone.
John Perry correctly identified the problem, but you have several option to deal with it. You are incorrectly incrementing *pptr += 1 Beyond using auto, you can simply index the pointer with the offset of j, e.g.
*(*pptr + j) = rv;
or
(*pptr)[j] = rv;
Either will work. Putting it together in your rainGen function, you could do:
void rainGen (int **pptr, int row, int col)
{
unsigned int seed = 43;
unsigned int rv;
srand(seed);
for (int i = 0; i < row; ++i) {
for (int j = 0; j < col; ++j) {
rv = rand() % 100;
// *(*pptr + j) = rv; /* or */
(*pptr)[j] = rv;
}
pptr++;
}
}
(note: seed and srand(seed) should be moved to main() if there is the potential that rainGen could be called more than once -- srand should only be called once)
Example Use/Output
Both will produce the desired output:
$ ./bin/raingen
72 71 65 94 0 13 49 17 36 49 67 51
87 68 45 15 91 72 16 80 77 35 9 81
11 88 73 59 24 22 37 48 45 54 94 45
19 44 62 56 45 81 59 32 49 4 99 92
28 16 24 5 3 34 38 14 22 12 26 98
72 72
87 87
11 11
19 19
28 28
You are modifying the pointers in the pointer-array matrix_ptr within your rainGen function, so that all of them point past the end and further accesses go to "random" memory locations, which is undefined behavior. Tools like valgrind can find such errors.

i want to show the sequence ftom 16 to 31 decimal number but its not showing :\ could anyone help me out here

#include <iostream>
using namespace std;
void bi(int a);
int main()
{
// here is the issue how do start a loop, where i want the answer from 16 to 31 numbers
int a=0;
cout<<"Baum-Sweet Sequence From 16 to 31 \n";
for(int j=a;j>16 && j<31;j++)
{
cout<<j;
}
bi(a);
system("Pause");
}
// Rest is working properly
void bi(int a)
{
int myArr[15],i=0,f=0,n=0;
for (int h = 0 ; h <= a; h++)
{
int num = h;
for (i = 0 ; i < 4 ; i++)
{
myArr[i] = num%2;
num = num/2;
}
for (int t = 0 ; t < 4 ; t++)
{
if (myArr[t]%2==0)
f++;
}
if (f%2==0)
cout << " = " << 1;
else
cout << " = " << 0;
cout <<endl;
}
}
i want to show the sequence from 16 to 31 decimal number but its not showing :\ could anyone help me out here
There is an error in the for loop.
The for loop has three parts separated by a semicolon.
for (INITIALIZATION; CONDITION; AFTERTHOUGHT)
{
// Source code for the for-loop's body
}
The first part initializes the variable (e.g. "int j = 16;" means that through the variable j you begin counting by 16);
The second part checks a condition and it quits the loop when false (e.g. j <=31 means that it quits the loop when j will have value 31);
The third one is performed once each time the loop ends and then repeats (e.g. j++ means that at each iteration of the loop j will be incremented by 1).
Each iteration will execute the code in the body of the for loop.
Considering that you want to call the bi function for each value from 16 to 31 your for loop body should include bi(j). Your main should be modified like the code below:
int main()
{
cout<<"Baum-Sweet Sequence From 16 to 31 \n";
for(int j=16;j<=31;j++)
{
cout<<j;
bi(j);
}
system("Pause");
return 0;
}
Your problem is that you set j to 0, but then make a condition for the loop that it will only execute if j (which is set to a), is bigger than 16.
Your first thing to do is to make the loop conditions this:
for (int j = 16; j <= 32; j++)

Strange output after reading from a file

Using this code, the following execution yields strange results:
C 100
R
W
The text file's first line defines the number of elements to read from it, and it contains a few values under 15, but every time I run this, the first value in my array is always printed out as 87 (the ASCII value for 'W'). If I change the 'W' functionality to 'X', then the first result in the array is 88.
#include <iostream>
#include <fstream>
using namespace std;
int arrayLength;
class ELEMENT
{
public:
int key;
};
class HEAP
{
public:
int capacity;
int size;
ELEMENT H [];
};
HEAP initialize(int n)
{
HEAP h;
h.capacity = n;
h.size = 0;
return h;
}
void buildHeap(HEAP &h, ELEMENT *a)
{
h.size = arrayLength;
for (int i = 1; i <= arrayLength; i++)
{
h.H[i] = a[i];
}
for (int i = h.size/2; i >= 1; i--)
{
// HEAPIFY HERE
}
}
void printHeap(HEAP &h)
{
cout << "Capacity:\t" << h.capacity << endl;
cout << "Size:\t\t" << h.size << endl;
cout << "|";
for (int i = 1; i <= h.size; i++)
{
cout << " ";
cout << h.H[i].key << " |";
}
cout << endl;
}
int main()
{
char c;
int val;
HEAP h;
while (c != 'S')
{
cin >> c;
switch (c)
{
case 'S':
break;
case 'C':
cin >> val;
h = initialize(val);
break;
case 'W':
printHeap(h);
break;
case 'R':
{
ifstream infile;
infile.open("HEAPinput.txt");
infile >> arrayLength;
ELEMENT* a = new ELEMENT[arrayLength];
for (int i = 1; i <= arrayLength; i++)
infile >> a[i].key;
infile.close();
buildHeap(h, a);
}
break;
}
}
return 0;
}
It is being compiled using g++ on a Unix server.
EDIT:
To clarify:
With a text file with the following contents (space = new line):
12 9 10 11 12 8 7 6 5 4 3 2 1
The output is:
Capacity: 100
Size: 12
| 87 | 10 | 11 | 12 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 |
So it's working except for that first element.
Whatever you think
ELEMENT H [];
is doing, it probably isn't. C++ does not support dynamic arrays - you need to use the std::vector class.
And BTW, C++ by convention uses UPPERCASE to name pre-processor macros and constants. You should use mixed case to name your classes.
In addition to the wrong use of arrays: it would not be a bad idea to make initialize(), buildHeap(), and printHeap() member functions of heap.
It might be because when you say
cout << h.H[i].key <<
H[] is an array of ELEMENTs and the key is an int. If key was a char or cast to char in the cout statement, you'll see the char representation of the int.
What Neil said. Also, arrays in C++ are zero-based. So for example your loop in main():
for (int i = 1; i <= arrayLength; i++)
Should probably be:
for (int i = 0; i < arrayLength; i++)
It could be that the algorithm for binary heap construction just happens to be simpler to implement if you use one-based arrays -- in that case, you'll need to allocate enough space:
ELEMENT* a = new ELEMENT[arrayLength + 1]; // Note the "+ 1"
Currently, the last loop iteration is writing past the end of the array.