I'm a little stuck with my school project.
So I need to make a dynamic 2-dimensional array.
It has to be created in a function with 3 parameters: 2-dimensional char array, length and width.
This is what I have so far. Length and width come from another function and there are no problems with that. I feel like I am very close but I don't know how do I save the array to theArray[][] and do I need to create a new variable for where i put /*what here?*/ .
Didn't find anything this specific from the web(maybe I just don't know what to search exactly)
Thanks in advance!
void doArray(char theArray[][], unsigned int length, unsigned int width) {
char** /*what here?*/ = new char*[lenght];
for(unsigned int i = 0; i < length; i++){
/*what here?*/[i] = new char[width];
}}
int main() {
unsigned int lenght = 0;
unsigned int width = 0;
char theArray[][];
size(lenght, width);
doArray(theArray, lenght, width);}
A 2-dimensional dynamic array in C++ is: std::vector<std::vector<TYPE>> a(SIZE_M, std::vector<TYPE>(SIZE_N));
#include <vector>
void doArray(auto &theArray, std::size_t length, std::size_t width) {
theArray = std::vector<std::vector<char>>(length, std::vector<char>(width));
}
int main() {
std::size_t lenght = 0;
std::size_t width = 0;
std::vector<std::vector<char>> theArray;
size(lenght, width);
doArray(theArray, lenght, width);
}
Another way would be to use malloc.
char **arr;
arr = (char**)malloc(length * sizeof(char*));
for(i=0;i<length;i++){
arr[i]=(char*)malloc(width * sizeof(char));
}
It's duplicated. See here for a better explanation.
Whatever, this is what you want:
void doArray(char **theArray, unsigned int length, unsigned int width) {
theArray = new char*[length];
for(unsigned int i = 0; i < length; ++i)
theArray[i] = new char[width];
}
Please don't comment I should use size_t instead of unsigned int.
When you want a function to create something, the normal way to to return the created object, not to pass it in as a parameter. I think maybe that is what is confusing you. For some reason beginners have often have trouble with the idea of functions returning things.
So rewriting your code to use a return instead of a parameter, you get this
char** doArray(unsigned int length, unsigned int width) {
char** arr = new char*[length];
for(unsigned int i = 0; i < length; i++) {
arr[i] = new char[width];
}
return arr;
}
Then in main you call the function like this
int main() {
char** theArray;
...
theArray = doArray(length, width);
As others have pointed out, the correct way in C++ to do this is to use a vector. But either way the lesson about writing functions to return values applies.
Related
I want to use a function made for dynamic arrys for an pre-initialised array too.
int MinInRow(int** fieldArray, int value, int currentColumn, int maxNumColumns)
{
int minVal = 0;
for (int inkrCol = 0; inkrCol < maxNumColumns; inkrCol++)
{
if (feldArray[currentColumn][inkrSpalte] < value)
{
minVal = feldArray[currentColumn][inkrCol];
}
}
return minVal;
}
So if I try
int testArray[3][4] =
{ {4,5,6,7},
{0,1,2,3},
{9,8,10,11}, };
int (*bufferArray)[4] = testArray;
or...
int** bufferArray = testArray;
or...
...
int main()
{
/*
read in other needed parameters
....
*/
std::cout << MinInRow((*bufferArray)[4], int value, int currentColumn, int maxNumColumns);
retrun 0;
}
I cant compile. But shouldnt int** bufferArray = testarray; just work fine? I mean there is always an double pointer to the first address of an 2D-Array.
how can I hand it over to the MinInRow-function? Thanks!
There is a little problem. "*" That one tell you that you want to make a pointer, but a pointer doesn't want a variable, he want the address. And then you've written
int** bufferArray = testarray.
You should write
int* bufferArray = new int [size of array] It's for 1D array
and ....
int** bufferArray = new int* [rows];
for (size_t = 0 ; i != rows ; ++i){
bufferArray[i] = new int [colons];
}
for 2D array
"I cant compile. But shouldnt int** bufferArray = testarray; just work fine? I mean there is alway an double pointer to the first address of an 2D-Array."
And Yes, it will be work nice. If testarray already 2D array
So basically I have an array which looks like this:
char array[25];
I have an 'X' put in there, and 24 'O's. I am trying to create a function where I can find the location of 'X' in the array, so then I can move it whenever a control is typed in. Here is some code to get an idea on what I am thinking, I just can't put it together.
int findX(){
//make this find the location of X out of the 25 char array.
//then return the slot of X as a number, like if it's in the 20th slot, then it will return 20 ?
//return(locationOfX);
}
for(int i = 0; i <= array.Length; i++)
{
if(array[i] == 'X')
{
return i;
}
}
This should do it, I had no chance testing it, but it should work
I think Ron's answer is more correct because actually I think in C there isn't a function like "XXX.length()", so you need to pass the length of the array to the function.
Pass in the array and the number of elements.
1. The manual approach:
int findX(char arr[], int count){
for (int i = 0; i < count; i++){
if (arr[i] == 'X'){
return i;
}
}
return -1;
}
2. Use std::find function:
int findX2(char arr[], int count){
return std::find(arr, arr + count, 'X') - arr;
}
Slight twist with the std::distance function:
int findX2(char arr[], int count){
return std::distance(arr, std::find(arr, arr + count, 'X'));
}
3. Pass in the beginning and the end of the array:
int findX3(char* arrbegin, char* arrend){
return std::distance(arrbegin, std::find(arrbegin, arrend, 'X'));
}
and use like:
std::cout << findX3(std::begin(arr), std::end(arr));
4. Template function left as an exercise.
That being said, prefer std::vector or std::array to raw arrays.
In language C you can use strstr function.
#include "string.h"
int findX(char array[])
{
char *result = strstr(array, "s");
return result - array;
}
int main()
{
char array[25];
int index = findX(array);
}
in C++ use std::find() or just change array to std::string and use string::find
here is the code:
#include <string>
int main()
{
std::string array = "oooooooooosoooooooooooooo";
int index = array.find("s");
return 0;
}
I am trying to do the following:
in main.cpp:
// Create an array of pointers to Block objects
Block *blk[64];
for (i=0; i<8; i++) {
for (j=0; j<8; j++) {
int x_low = i*80;
int y_low = j*45;
blk[j*8+i] = new Block(30, x_low+40.0f, y_low+7.5f, &b);
}
}
And then I am trying to pass it to the graphics object I have created:
Graphics g(640, 480, &b, &p, blk[0], number_of_blocks);
the graphics constructor looks like:
Graphics::Graphics(int width, int height, Ball *b, Paddle *p, Block *blk, int number_of_blocks) {
if I look at what is contained in the array from the graphics object, only the first item exists and then all the other items are in hyperspace:
for (int i=0; i<64; i++) {
printf("for block %d, %f, %f ", i, (_blk+(sizeof(_blk)*i))->_x_low, (_blk+(sizeof(_blk)*i))->_y_low);
printf("blah %d\n", (_blk+(sizeof(_blk)*i)));
}
and if I look at the addresses, they are different (6956552 rather than 2280520 when I examine the addresses in the main class using:
printf(" blah %d\n", &blk[j*8*i]);
I am sure there must be something subtle I am doing wrong as its like I have copied the first item from the blk array to a new address when passed to the graphics object.
Does this make sense? Any ideas?
Cheers,
Scott
If you want to pass the whole array, the constructor should look like this:
Graphics::Graphics(int width, int height, Ball *b, Paddle *p,
Block **blk, int number_of_blocks)
and you should pass the array like this:
Graphics g(640, 480, &b, &p, blk, number_of_blocks);
It looks like:
Graphics::Graphics(int width, int height, Ball *b, Paddle *p, Block *blk, int number_of_blocks) {
is expecting an array of Blocks, not an array of pointers to Blocks. Passing the first element would probably work if you made_number_of blocks 1, but it can't work for anything else using your current data structure. If I were you, I would give up on using arrays and use std::vector instead - it will greatly simplify your code.
The Graphics function is expecting a contiguous array of Block objects in memory and you are creating each new Block independently. Try
Block* blk = new Block[64];
then loop through and initialize each Block's values. This will only work if you can initialize the block objects in another way from using the constructor with arguments since new in this case can only call the default constructor. If the only way to initialize a Block is using the constructor with arguments, you'll have to do something else like passing Block** to the function.
From what I can see, you are passing the first element of the array to the contructor, not the whole array. This is what you are doing:
#include <iostream>
#include <cstdlib>
void foo(int* item, const int length);
int main() {
const int length = 10;
int* array[length];
for (int i = 0; i < length; ++i) {
array[i] = new int(i + 100);
}
foo(array[0], length);
return (EXIT_SUCCESS);
}
void foo(int* item, const int length) {
for (int i = 0; i < length; ++i) {
std::cout << item[i] << std::endl;
}
}
I believe this is what you wanted to do:
#include <iostream>
#include <cstdlib>
void foo(int** array, const int length);
int main() {
const int length = 10;
int* array[length];
for (int i = 0; i < length; ++i) {
int* item = new int(i + 100);
array[i] = item;
}
foo(array, length);
return (EXIT_SUCCESS);
}
void foo(int** array, const int length) {
for (int i = 0; i < length; ++i) {
int* item = array[i];
std::cout << *item << std::endl;
}
}
Regards,
Rafael.
I'm trying to create a function that would dynamically allocate an array, sets the values of the elements, and returns the size of the array. The array variable is a pointer that is declared outside the function and passed as a parameter. Here is the code:
#include <cstdlib>
#include <iostream>
using namespace std;
int doArray(int *arr) {
int sz = 10;
arr = (int*) malloc(sizeof(int) * sz);
for (int i=0; i<sz; i++) {
arr[i] = i * 5;
}
return sz;
}
int main(int argc, char *argv[]) {
int *arr = NULL;
int size = doArray(arr);
for (int i=0; i<size; i++) {
cout << arr[i] << endl;
}
return 0;
}
For some reason, the program terminates on the first iteration of the for loop in main()! Am I doing something wrong?
If you want to allocate memory that way you have to use:
int doArray(int*& arr)
else the pointer will only be changed inside the function scope.
You're passing in the array pointer by value; this means that when your doArray function returns, the value in arr in main is still NULL - the assignment inside doArray doesn't change it.
If you want to change the value of arr (which is an int *), you need to pass in either a pointer or a reference to it; hence, your function signature will contain either (int *&arr) or (int **arr). If you pass it in as a ** you'll also have to change the syntax inside the function from using arr to *arr (pointer-dereferencing), and you'll call it like so: doArray(&arr).
Also, in C++ you should really be using new int[sz] instead of malloc.
You need to add an extra level of indirection to doArray. As written it allocates the array properly but it doesn't communicate the pointer value back to the caller correctly. The pointer from malloc is lost once you return.
If you wrote a function to take a float and change the value, passing the changed value back to the caller, it would need to take a pointer: foo(float *f). Similarly, here you want to pass back an int* value to the caller so your function must be declared as doArray(int **arr) with a second asterisk.
int doArray(int **arr) {
int sz = 10;
*arr = (int*) malloc(sizeof(int) * sz);
for (int i=0; i<sz; i++) {
(*arr)[i] = i * 5;
}
return sz;
}
int main(int argc, char *argv[]) {
int *arr = NULL;
int size = doArray(&arr);
for (int i=0; i<size; i++) {
cout << arr[i] << endl;
}
return 0;
}
Notice how it now dereferences *arr inside of doArray, and how the call is now written as doArray(&arr).
The arr variable in your function is a local copy of the arr pointer in the main function, and the original is not updated. You need to pass a pointer-to-pointer or pointer reference (the former will also work in plain c, the later only in c++).
int doArray(int **arr)
or
int doArray(int*& arr)
Change signature to (specific for c++):
int doArray(int *&arr)
so pointer would be changed at exit from doArray.
You need a pointer to a pointer in your doArray() parameter. If you've never done any programming with pointers before, this can be confusing. I find that it can be easier to see the right types if you annotate your code abundantly with typedefs.
You have the right idea that (int*) can be used to represent an array. But if you want to change the value of your variable arr in main(), you need a pointer to that, and so you will end up with (untested code) something like the following
typedef int *IntArray;
int doArray(IntArray *arr) {
int sz = 10;
*arr = (IntArray) malloc(sizeof(int) * sz);
IntArray theArray = *arr;
for (int i=0; i<sz; i++) {
theArray[i] = i * 5;
}
return sz;
}
when calling doArray, you will need to pass the address of your variable (so doArray knows where to write to):
int main(int argc, char *argv[]) {
int *arr = NULL;
int size = doArray(&arr);
for (int i=0; i<size; i++) {
cout << arr[i] << endl;
}
return 0;
}
This should work.
As others have pointed out, you're passing your array (the int *) by value, so when you say arr=... you're not actually changing the array you passed in.
You're also got a memory leak, as you've written it. It's not a big deal when you only call doArray once in the body of your program, but if it gets called repeatedly and the array is never freed (or deleted, if you made it with new) then it can cause problems. Typically the best way to deal with this is by using the STL. You'd then write
#include <vector>
#include <iostream>
int doArray(std::vector<int> &arr) {
int sz = 10;
arr.resize(sz);
for (int i=0; i<sz; i++) {
arr[i] = i * 5;
}
return sz;
}
int main(int argc, char *argv[]) {
std::vector<int> arr;
int size = doArray(arr);
for (int i=0; i<size; i++) {
std::cout << arr[i] << std::endl;
}
return 0;
}
However, with the STL there are more idomatic ways than returning the size, since you can just ask for arr.size(), and if you get really fancy, can use functions like for_each or the ostream_iterator to print all your elements.
This question builds off of a previously asked question:
Pass by reference multidimensional array with known size
I have been trying to figure out how to get my functions to play nicely with 2d array references. A simplified version of my code is:
unsigned int ** initialize_BMP_array(int height, int width)
{
unsigned int ** bmparray;
bmparray = (unsigned int **)malloc(height * sizeof(unsigned int *));
for (int i = 0; i < height; i++)
{
bmparray[i] = (unsigned int *)malloc(width * sizeof(unsigned int));
}
for(int i = 0; i < height; i++)
for(int j = 0; j < width; j++)
{
bmparray[i][j] = 0;
}
return bmparray;
}
I don't know how I can re-write this function so that it will work where I pass bmparray in as an empty unsigned int ** by reference so that I could allocate the space for the array in one function, and set the values in another.
Use a class to wrap it, then pass objects by reference
class BMP_array
{
public:
BMP_array(int height, int width)
: buffer(NULL)
{
buffer = (unsigned int **)malloc(height * sizeof(unsigned int *));
for (int i = 0; i < height; i++)
{
buffer[i] = (unsigned int *)malloc(width * sizeof(unsigned int));
}
}
~BMP_array()
{
// TODO: free() each buffer
}
unsigned int ** data()
{
return buffer;
}
private:
// TODO: Hide or implement copy constructor and operator=
unsigned int ** buffer
};
typedef array_type unsigned int **;
initialize_BMP_array(array_type& bmparray, int height, int width)
Mmm... maybe I don't understand well your question, but in C you can pass "by reference" by passing another pointer indirection level. That is, a pointer to the double pointer bmparray itself:
unsigned int ** initialize_BMP_array(int height, int width, unsigned int *** bmparray)
{
/* Note the first asterisk */
*bmparray = (unsigned int **)malloc(height * sizeof(unsigned int *));
...
the rest is the same but with a level of indirection
return *bmparray;
}
So the memory for the bmparray is reserved inside the function (and then, passed by reference).
Hope this helps.
To use the safer and more modern C++ idiom, you should be using vectors rather than dynamically allocated arrays.
void initialize_BMP_array(vector<vector<unsigned int> > &bmparray, int height, int width);