I'm teaching myself C++ and doing a problem from a textbook. So far I have covered the basics such as data types, declarations, displays, assignment, interactive input, selection (if-else), and repetition (for/while loops...), functions and arrays. I have NOT done anything with pointers, but I know what they are...
I came across this problem:
The answers to a true-false test are as follows: T T F F T. Given a two-dimensional answer array, in which each row corresponds to the answers provided on one test, write a function that accepts the two-dimensional array and number of tests as parameters and returns a one-dimensional array containing the grades for each test. (Each question is worth 5 points so that the maximum possible grade is 25.) Test your function with the following data:
My understanding is that C++ functions cannot return arrays--At least this is what I read on other posts on this forum. Is this correct? If so, how are they expecting you to do this problems because I haven't covered pointers yet. The only other way I thought MIGHT be possible is by passing in the array by reference.... but the question stem only says there are 2 arguments to the function so I thought maybe that method was ruled out. That method would require a third argument which is the array your modifying so its implicitly returned.
I have some code, but its not correct (only my calcgrade function needs work) and I'm not sure how to move forward.Could someone please advise? Thank you!!
#include<iostream>
// Globals
const int NROW = 6, NCOL = 5;
bool answers[NCOL] = {1, 1, 0, 0, 1};
bool tests[][NCOL] = {1, 0, 1, 1, 1,
1, 1, 1, 1, 1,
1, 1, 0, 0, 1,
0, 1, 0, 0, 0,
0, 0, 0, 0, 0,
1, 1, 0, 1, 0};
int grade[NROW] = {0};
// Function Proto-Types
void display1(bool []);
void display2(bool [][NCOL]);
int calcgrade(bool [][NCOL], int NROW);
int main()
{
calcgrade(tests, NROW);
display2(tests);
return 0;
}
// Prints a 1D array
void display1(bool answers[])
{
// Display array of NCOL
for(int i = 0; i < NCOL; i++)
std::cout << std::boolalpha << answers[i] << std::endl;
return;
}
// Print 2d Array
void display2(bool answers[][NCOL])
{
// Display matrix: 6x5
for(int i = 0; i < NROW; i++)
{
for(int j= 0; j < NCOL; j++)
{
std::cout << std::boolalpha << answers[i][j] << std::endl;
}
std::cout << std::endl;
}
return;
}
int calcgrade(bool tests[][NCOL], int NROW)
{
for(int i = 0; i < NROW; i++)
{
for(int j = 0; j < NROW; j++)
{
if(tests[i][j]==answers[j])
grade[i] += 5;
}
printf("grade[%i] = %i", i, grade[i]);
}
return grade;
}
Try to use std::vector.
Vectors are sequence containers representing arrays that can change in size.
You can do so:
vector<bool> function()
{
vector<bool> vec;
vec.push_back(true);
vec.push_back(false);
vec.push_back(true);
return vec;
}
If you're passing the number of tests as the second parameter, it means you actually know the number of tests, so you don't need to use a vector. You can return an dynamically allocated array (either using new or malloc).
The code would look like this:
int* calcgrade(bool tests[][NCOL], int NROW){
int* array = new int[NROW];
for(int i=0;i<NROW;i++)
array[i] = calculatedGrade;
return array;
}
You can:
as you said, return pointer to dynamically allocated array,
you can make structure type with word struct that includes static array, read more on C++ Reference and return/take as argument structure of your type.
Another way of doing this would be to create the Answer array in your main function, then pass it along with the T/F array to your grading function. Then, your grading function could operate on the Answer array, and wouldn't even need to return anything.
Essentially, when you pass arrays in functions, you're actually passing pointers to the arrays, and thus you can operate on them as if they were passed by reference (which they were).
semi-pseudocode ex:
void getGrades( const int answerVector, int gradeVector ) {
// code that computes grades and stores them in gradeVector
}
Related
This question already has answers here:
How do I define variable of type int[][26]?
(2 answers)
Closed 2 years ago.
I have written a small program that passes a 2D array to 2 separate functions that store and display the pattern of a chessboard. While the program works perfectly fine, I would like to ask a more technical question that I have not been able to answer myself through my searches.
I am wondering how it is possible that my program compiles and runs when passing the 2D array with ONLY the columns variable specified, but not the rows. For instance void setBoard(char chessboard[][cols]);
Here is the link to the program: https://codecatch.net/post/54969994-76d7-414b-aab6-997d3fef895c
Here is the same code for those of you that don't want to click the link:
#include<iostream>
using namespace std;
const int rows = 8;
const int cols = 8;
char chessboard[rows][cols];
void setBoard(char chessboard[][cols]);
void printBoard(char chessboard[][cols]);
void setBoard(char chessboard[][cols]) {
for(int i = 0; i < rows; i++) {
for(int j = 0; j < cols; j++) {
if(i % 2 == 0 && j % 2 == 0) {
chessboard[i][j] = 'x';
} else {
if(i % 2 != 0 && j % 2 == 1) {
chessboard[i][j] = 'x';
} else {
chessboard[i][j] = '-';
}
}
}
}
return;
}
void printBoard(char chessboard[][cols]) {
for(int i = 0; i < rows; i++) {
for(int j = 0; j < cols; j++) {
cout << chessboard[i][j] << " ";
}
cout << endl;
}
return;
}
int main(int argc, char const *argv[])
{
setBoard(chessboard);
printBoard(chessboard);
return 0;
}
To answer the question directly: in C and C++ passing static array as an argument needs all dimensions except the outermost. So, if you have N-dimensional array, you need to specify the sizes of N-1 dimensions, except the leftmost one: int array[][4][7][2]...[3].
Now, to the gory details.
So, let's say you have int a[3];. What is the type of a? It is int [3]. Now, you want to pass it into function. How do you do this? There are two ways: you can either pass the array by pointer to the first element (works in C and C++), or you can pass the array by reference (references are a C++ thing). Let's consider these examples:
#include <iostream>
void foo(int* array, std::size_t len) { // same as foo(int array[],...)
for (std::size_t i = 0; i < len; i++)
std::cout << array[i] << ' ';
std::cout << '\n';
}
void bar(int (&array)[3]) {
for (int n : array)
std::cout << n << ' ';
std::cout << '\n';
}
template <std::size_t N>
void baz(int (&array)[N]) {
for (int n : array)
std::cout << n << ' ';
std::cout << '\n';
}
int main () {
int a[3] = {1, 2, 3};
int b[4] = {1, 2, 3, 4};
foo(a, 3); // BAD: works, but have to specify size manually
foo(b, 4); // BAD: works, but have to specify size manually
bar(a); // BAD: works, but bar() only accepts arrays of size 3
bar(b); // DOESN'T COMPILE: bar() only accepts arrays of size 3
baz(a); // OK: size is part of type, baz() accepts any size
baz(b); // OK: size is part of type, baz() accepts any size
}
Let's consider foo().
foo()'s signature could also be written as void foo(int array[], ...). This is purely syntactic sugar and int array[] means the same as int* array. Note, however, that this only applies to function signatures, everywhere else these syntaxes are not equivalent.
When you call it as foo(a, 3), it's signature is set to accept a pointer to int as first parameter: int* array. But you know that a is of type int [3], so how does it work? What happens is, the pointer to the first element of the array is passed by value. Which means, it is the same as writing foo(&a[0],...). We take the address of the first element, which is then copied into int* array. As you might notice, having a pointer to the first array doesn't tell us anything about the size of the array, we lost this information during conversion from array type int [3] to int *. Which is why we have to supply the second argument that specifies the length of a. We call this implicit conversion an "array to pointer decay". Decay specifically because we were forced to lose important information -- we had it right there in the type, but now we have to have another argument that describes how many elements the array has. A bit stupid and inconvenient, isn't it?
Now consider bar().
In bar() we pass the array type by reference. This is something that C++ has improved upon C. I will not explain what references are, but in general, you can think of them as something that allows you to get the object the way it is defined, without using any convertions to pointers. In this case, the type of array remains int [3], so we have passed in an array and haven't lost any type information. Great! This means, we can use idiomatic C++ syntax to further improve our code. I have replaced the normal for loop, as found in foo(), with a for-each loop, where we just need to supply a variable to store the element (n) and the array (array). Note that this is possible only because array preserves type information! Trying to do this in foo() would result in a compilation error.
However, there is still a problem with this. bar() has to have the array size as part of its signature! This means that if a was any different size, let's say 4 elements, trying to use bar() would result in a compilation error because int [3] and int [4] are incompatible types.
Consider baz(), which solves the above problem.
Just a little bit of templates will make baz() usable on arrays of any size, while the usage stays the same as in bar().
Now, let's take it to multiple dimensions:
#include <iostream>
void foo2d(int (*array)[3], std::size_t rows, std::size_t cols) {
for (std::size_t i = 0; i < rows; i++)
for (std::size_t j = 0; j < cols; j++)
std::cout << array[i][j] << ' ';
std::cout << '\n';
}
void bar2d(int (&array)[2][3]) {
for (std::size_t i = 0; i < 2; i++)
for (std::size_t j = 0; j < 3; j++)
std::cout << array[i][j] << ' ';
std::cout << '\n';
}
template <std::size_t N, std::size_t M>
void baz2d(int (&array)[N][M]) {
for (std::size_t i = 0; i < N; i++)
for (std::size_t j = 0; j < M; j++)
std::cout << array[i][j] << ' ';
std::cout << '\n';
}
int main () {
int c[2][3] = { {1, 2, 3}, {4, 5, 6} };
foo2d(c, 2, 3);
bar2d(c);
baz2d(c);
}
And again, only baz2d() doesn't require hardcoded size information.
One more example, of foo3d(), just to demonstrate what I mean when I say only the outermost dimension doesn't need to be specified:
void foo3d(int (*array)[2][1], std::size_t rows, std::size_t cols, std::size_t K) {
for (std::size_t i = 0; i < rows; i++)
for (std::size_t j = 0; j < cols; j++)
for (std::size_t k = 0; k < K; k++)
std::cout << array[i][j][k] << ' ';
std::cout << '\n';
}
int main () {
int d[3][2][1] = { {{1}, {2}}, {{3}, {4}}, {{5}, {6}} };
foo3d(d, 3, 2, 1);
}
Pay attention to how it's called vs. how it's declared in the signature. So, why do you not need to declare the outermost size? Because only the first pointer decays, due to passing it to the function. d[0][0][0] stores element of type int, d[0][0] stores element of type int [1], d[0] stores element of type int [2][1]. Which are all themselves are arrays! Well, except d[0][0][0], obviously. So, what is the type of the array in foo3d()? It's int (*)[2][1]: pointer to array of size 2, each element of which is an array of size 1.
Parameter of a function is never an array type in C++ (nor in C).
You can declare a function that has an array parameter (as is done in the example program), but that declaration is adjusted so that the parameter is not an array as was written, but it is instead a pointer to element of such array. Example:
void f(int[]); // will be adjusted
void f(int[42]); // will be adjusted
void f(int*); // declarations above are adjusted to this
All of the above three declarations declare the same function. If the type of parameter is "array of int", then the type of the element of such array is "int" and pointer to such element is "pointer to int". Notice that the size of the array has no effect on the type of the element. As such, the size has no effect on the declaration in any way, and indeed arrays of unknown bound are allowed in parameter declaration.
Note that this adjustment occurs only in function parameters, and nowhere else. An array is not a pointer.
So, when you declare a function void setBoard(char chessboard[][cols], the parameter chessboard is not an array, because a parameter is never an array. It has been adjusted to be a pointer to element of char [][cols]. Element of such array is char[cols] i.e. array of cols number of char, therefore the adjustead parameter type is pointer to array of cols number of char i.e. char(*)[cols].
You cannot have pointer type to an array of unknown bound, so you cannot leave out cols. But you can leave out rows because as noted above, the size of the declared array parameter is ignored when the type is adjusted to be a pointer to the element of that array.
You may be wondering "if the parameter is actually not an array, then why can an array be passed as argument?". The answer is that there is another rule complementing the parameter adjustment (in simple words): Arrays implicitly convert to the pointer to element type. The result of the conversion is pointer to the first element of that array. Such conversion is called "decaying". This conversion happens automatically whenever the value of an array is used. Example:
printBoard(&chessboard[0]);
printBoard(chessboard);
The above function calls do exactly the same thing. The former explicitly passes pointer to first element, while the latter does the same thing by implicit "decay".
I'm writing class that manages dynamic array of objects. Right now I got stuck on method that should insert element at given index, but before it checks if that index isnt bigger than array capacity. Then it should resize array first.
template <class T>
void MyVector<T>::insertAt(int index, const T &m_element) {
if(p_size == p_capacity) extendArray();
if(index >= p_capacity) extendArray(index);
p_size++;
p_array[index] = m_element;
}
template <class T>
void MyVector<T>::extendArray(int new_capacity) {
std::unique_ptr<T[]> temp_array = std::make_unique<T[]>(new_capacity);
for (int i = 0; i <= p_size; i++) {
temp_array[i] = p_array[i];
}
p_array.reset();
p_array = std::make_unique<T[]>(new_capacity);
for (int i = 0; i <= p_size; i++) {
p_array[i] = temp_array[i];
}
}
extendArray()just extends array capacity 2 times, extendArray(int) extends array capacity to the number given by the index. First method works fine, second not so really.
int main(){
MyVector<int> test;
test.insertAt(0, 5);
test.insertAt(1, 3);
test.insertAt(2, 1);
test.insertAt(6, 11);
cout <<"Size " << test.getSize() << "\n";
for(int i = 0; i < test.getCapacity(); i++) {
cout << test.get(i) << ", ";
}
}
Id expect something like 5, 3, 1, 0, 0, 0, 11, 0
But I get just 5, 3, 1, 0 so it never extends array but it increases size (number of elements).
You did not post your extendArray() function but even though you say it's a copy of extendArray(int) first seems to be updating p_capacity when the latter you provided doesn't.
Fixing that would gain you couple of extra zeros in the output 5, 3, 1, 0, 0, 0 since you extending only to the index, not to the index+1. Furthermore, in insertAt(int index, const T &m_element) you are incrementing the p_size, instead of assigning it to index+1
Extending to p_size+1 and fixing the p_size assignment, prints 5, 3, 1, 0, 0, 0, 11 and I am not quite sure how you came to the conclusion that it should have an extra trailing 0 as p_capacity ends up being 7, regardless if the initial value is 1, 2 or 4 as in the code snippet I put a link to.
I also noticed couple of bugs I without looking too close: your loops shouldn't go to the p_size, but rather to p_size-1, so instead for (size_t i = 0; i <= p_size; i++) it should be for (size_t i = 0; i < p_size; i++)
I would also suggest using unsigned int (or size_t) instead of int for indexing as that allows to get compiler warnings when you do something which potentially can result in a negative index.
Lastly, you should be able to use unique_ptr::swap to avoid two allocations in extendArray(..).
Good luck with learning!
This question already has answers here:
Find the count of elements in array in C++
(3 answers)
Closed 5 years ago.
I have a simple array here:
int someNumbers[10] = { 16, 2, 77, 40, 12071 };
How can I get the number of data inside the array? As the array was set to 10, but there is only 5 data inside.
My desired outcome should be something like this:
int icount = sizeof(someNumbers); // This is wrong, but I have no idea how..
cout << icount << endl;
I need icount to return 5 instead of 10. How can I do that?
This will do:
#include<iostream>
using namespace std;
int main(){
int someNumbers[10] = { 16, 2, 77, 40, 12071 };
int count = 0;
int i = 0;
for(i = 0; i < sizeof(someNumbers) / sizeof(int); i++){
if(someNumbers[i]){
count = count + 1;
}
}
cout << count << endl;
return 0;
}
I am using if(someNumber[i]) alone because this will return true as long as someNumber[i] is not undefined. Therefore, this works.
This is the output:
5
You can always make this a separate function like this:
#include<iostream>
using namespace std;
int dataInArray(int someNumbers[], int size);
int main(){
int someNumbers[10] = { 16, 2, 77, 40, 12071, 2};
int count = dataInArray(someNumbers, 10);
cout << count << endl;
return 0;
}
int dataInArray(int someNumbers[], int size){
int count = 0;
int i = 0;
for(i = 0; i < size; i++){
if(someNumbers[i]){
count = count + 1;
}
}
return count;
}
Since you are using a static array where the size is predefined, you would have to use a for loop to run through your array. See example here:
int someNumbers[10] = { 16, 2, 77, 40, 12071 };
int icount = 0;
for (int i = 0; i < 10; i++)
{
if (someNumbers[i])
icount++;
}
cout << icount << endl;
A bit of background information. If one of the memory blocks assigned to this array is not set by the user, it will store an empty value. Therefore, if we do if(isNumber[i]) then it will return true if someNumber at iis filled with a value, and it will return false if not filled with a value.
That is how the for-loop works in the code I posted. For every run of the loop, when the if statement is true, (if someNumber[i] has a value), then the counter is incremented.
EDIT: This solution works fine; for your array, it will output 5. It also works for any int array; just change the counter to run while it less than the static size you assign for the array.
EDIT 2: this solution works as long as there is no zero in your array, because a zero will falsify the if-condition. See more in this stackoverflow post: Find the count of elements in array in C++. To overcome this obstacle, it is recommended that you use std::vector, or use a counter variable and update the exact number of memory locations in the array that are filled in this variable manually.
What you are asking for just is not possible, because according to the language rules, there is no difference at all between:
int someNumbers[10] = { 16, 2, 77, 40, 12071 };
and
int someNumbers[10] = { 16, 2, 77, 40, 12071, 0, 0, 0, 0, 0 };
Both of them definitely initialize all ten elements.
If you're interested in finding the first zero (whether it was typed by the programmer or implied by the language rules) then #ABusyProgrammer's answer will help.
If you need to count zeros which the programmer typed, then you have to let the compiler infer the array (or initializer_list, as mentioned in comments) length from the initializer as #Kelm's answer shows.
There's no way to both detect zeros typed by the programmer and also specify the array size.
Use this:
int someNumbers[] = { 16, 2, 77, 40, 12071 };
cout << sizeof(someNumbers)/sizeof(int) <<endl;
This is because sizeof(someNumbers) does not give you the count of the array but rather the total number of bytes it is taking. So divide it by sizeof(int) and it will give you the number of integers in the array.
Also, if you specify [10] while declaring the array then the count of the array will be 10, regardless of whether it is initialized with fewer values. The way shown above, with an empty [], it will automatic set the count according to the number of elements specified.
ideone link
This should do it:
int someNumbers[] = {1,2,3,4,5,6};
int icount = sizeof(someNumbers) / sizeof(int);
How to return a pointer to array and get values from that?
int * getChange(int first[], int second[], int SIZE) {
int i = 0;
int * change = new int[2];
for (i = 0; i < SIZE; i++) {
if (first[i] != second[i]) {
change[0] = first[i];
change[1] = second[i];
}
break;
}
return change;
}
function main() {
int myNumbers[] = {1, 0, 2, 3};
int possibilities[] = {0, 1, 2, 3};
int * change;
change = getChange(possibilities, myNumbers, 4);
printf("%i / %i\n", (change), (change+1));
}
Unfortunately the function seems to return addresses, not values...
Try to change
printf("%i / %i\n", (change), (change+1));
to
printf("%i / %i\n", *(change), *(change+1));
In the printf function you need to use an int as parameters, not an int*. the change variable is a pointer. You must use *change and, using pointers arithmetics, *(change + 1)
Obviously, don't forget to free the allocated memory.
In C++, you would not be using arrays (int[] or int*), because they are annoying in several ways: you have to pass around the SIZE, they're usually exception-unsafe (you have to catch the exception, delete the array, then re-throw the exception), and they're hard to use as class members properly. Either use a standard library container, or an iterator range.
The idiomatic way to do what you're trying to do would be to use iterators and pairs:
template <typename IT_1, typename IT_2>
std::pair<int,int> getChange(IT1 begin, IT1 end, IT2 begin2)
{
for (; begin != end; ++begin, ++begin2)
{
if (*begin != *begin2) return std::make_pair(*begin,*begin2);
}
return std::make_pair(0,0);
}
void main() {
int myNumbers[] = {1, 0, 2, 3};
int possibilities[] = {0, 1, 2, 3};
std::pair<int,int> change = getChange(possibilities, possibilities + 4,
myNumbers);
printf("%i / %i\n", change.first, change.second);
}
Note that the second sequence (myNumbers) is expected to be as least as long as the first sequence. If you're not comfortable with iterators and function templates yet, you can always use vectors instead:
std::pair<int,int> getChange(std::vector<int> a, std::vector<int> b) {
for (int i = 0; i < a.size() && i < b.size(); ++i)
{
if (a[i] != b[i]) return std::make_pair(a[i],b[i]);
}
return std::make_pair(0,0);
}
void main() {
int _myNumbers[] = {1, 0, 2, 3};
int _possibilities[] = {0, 1, 2, 3};
std::vector<int> myNumbers(_myNumbers,_myNuymbers+4),
possibilities(_possibilities,_possibilities+4);
std::pair<int,int> change = getChange(possibilities, myNumbers);
printf("%i / %i\n", change.first, change.second);
}
While the latter may seem rather more verbose than the array version (after all, it's creating two arrays and then copying their values into the vectors), keep in mind that initializing an array from a constant is a fairly rare occurence: most of the time, arrays (and vectors) are initialized dynamically by a piece of code dedicated to just that. Such code can usually be used for both arrays and vectors with only minimal changes.
And, of course, you can typedef both std::pair<int,int> and std::vector<int> to shorter names if you end up using them a lot.
As it has been said, your code is very wrong in very many levels. I'll try to explain.
First of all, if you want to return the same array, why are you creating a new one? What is it you want to do, exactly?
Second, that new you make is never getting free'd. After main() exits, all the memory of your application is going to be claimed by the OS, but you shouldn't rely on that.
The code that Chowlett wrote is correct (+1 for being nice and pointing out the allocation problem ;), so I'll just go through your code and point out stuff
for(int i = 0 ; i < size i++)
{
if(first[i] != second[i])
{
change[0] = first[i];
change[1] = second[i];
}
break;
}
that doesn't do what you want. It checks if first[0] is different from second[0], then hits the break whether this holds true or not. You want the break inside the if statement block.
then if you want to use an array's content, you have to index it with [], otherwise you refer to the memory address of the array and it's indexes. This means which's been said, that you want to do
printf("%d / %d", changed[0], change[1])
While what's been said above that using C++ vectors is "better" for this case than arrays, I don't think this is the right answer to your question. You seem to be learning how to use arrays, and arrays are a most important part of C and even C++ real life coding. You'll use them a lot, they are WAY faster than vectors, and many many many libraries that you'll deal with are written in plain C, so you'll have to use them.
Learn yourself a little bit of pointer arithmetics, and you'll be fine. Remember to free the memory you allocate, this isn't Java. remember that a in
int a[3];
is more like a
int *a;
than like a
int a;
which explains why you can also do
printf("%d / %d", *changed, *(changed + 1));
Read the kernighan and ritchie.
Happy hacking
I think I'd write it a bit differently (and note that I'm sticking to C-only concepts here - in C++ I would almost certainly do things a bit differently):
void getChange(int *first, int *second, int SIZE, int *change) {
int i = 0;
for (i = 0; i < SIZE; i++) {
if (first[i] != second[i]) {
change[0] = first[i];
change[1] = second[i];
break;
}
}
return;
}
function main() {
int myNumbers[] = {1, 0, 2, 3};
int possibilities[] = {0, 1, 2, 3};
int change[2];
getChange(possibilities, myNumbers, 4, change);
printf("%i / %i\n", change[0], change[1]);
}
If you allocate change outside of getChange you solve potential memory leak problems.
printf("%i / %i\n", (change), (change+1));
This should be:
printf("%d / %d\n", *change, *(change + 1));
int* functionReturningArray( int *inputArray, int size)
{
int*outputArray = new int[20];
return outputArray;
}
But it is much better to use vector in c++ then c style arrays. Because it protect you from a lot of errors and it is faster to write code using vector.
Also such functionReturningArray is not very good because it returns just a pointer t othe first element of array but don't return size. You can return size and a pointer (two arguments) by predefining them and passing pointers to them to your function like this:
void f(int**outputArray, int *size)
{
*outPutArray = new int[20];
*size = 20;
}
And how it looks with a vector:
std::vector<int> func(const std::vector<int> &input)
{
std::vector<int> output;
output.push_back(5);
return output;
}
You can also create the vector on a heap and return a pointer to it.
But avoid using std::vector - use std::string instead
What is the accepted/most commonly used way to manipulate dynamic (with all dimensions not known until runtime) multi-dimensional arrays in C and/or C++.
I'm trying to find the cleanest way to accomplish what this Java code does:
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
int rows=sc.nextInt();
int cols=sc.nextInt();
int[][] data=new int[rows][cols];
manipulate(data);
}
public static void manipulate(int[][] data){
for(int i=0;i<data.length;i++)
for(int j=0;j<data[0].length.j++){
System.out.print(data[i][j]);
}
}
(reads from std_in just to clarify that dimensions aren't known until runtime).
Edit:I noticed that this question is pretty popular even though it's pretty old. I don't actually agree with the top voted answer. I think the best choice for C is to use a single-dimensional array as Guge said below "You can alloc rowscolssizeof(int) and access it by table[row*cols+col].".
There is a number of choices with C++, if you really like boost or stl then the answers below might be preferable, but the simplest and probably fastest choice is to use a single dimensional array as in C.
Another viable choice in C and C++ if you want the [][] syntax is lillq's answer down at the bottom is manually building the array with lots of malloc's.
Use boost::multi_array.
As in your example, the only thing you need to know at compile time is the number of dimensions. Here is the first example in the documentation :
#include "boost/multi_array.hpp"
#include <cassert>
int
main () {
// Create a 3D array that is 3 x 4 x 2
typedef boost::multi_array<double, 3> array_type;
typedef array_type::index index;
array_type A(boost::extents[3][4][2]);
// Assign values to the elements
int values = 0;
for(index i = 0; i != 3; ++i)
for(index j = 0; j != 4; ++j)
for(index k = 0; k != 2; ++k)
A[i][j][k] = values++;
// Verify values
int verify = 0;
for(index i = 0; i != 3; ++i)
for(index j = 0; j != 4; ++j)
for(index k = 0; k != 2; ++k)
assert(A[i][j][k] == verify++);
return 0;
}
Edit: As suggested in the comments, here is a "simple" example application that let you define the multi-dimensional array size at runtime, asking from the console input.
Here is an example output of this example application (compiled with the constant saying it's 3 dimensions) :
Multi-Array test!
Please enter the size of the dimension 0 : 4
Please enter the size of the dimension 1 : 6
Please enter the size of the dimension 2 : 2
Text matrix with 3 dimensions of size (4,6,2) have been created.
Ready!
Type 'help' for the command list.
>read 0.0.0
Text at (0,0,0) :
""
>write 0.0.0 "This is a nice test!"
Text "This is a nice test!" written at position (0,0,0)
>read 0.0.0
Text at (0,0,0) :
"This is a nice test!"
>write 0,0,1 "What a nice day!"
Text "What a nice day!" written at position (0,0,1)
>read 0.0.0
Text at (0,0,0) :
"This is a nice test!"
>read 0.0.1
Text at (0,0,1) :
"What a nice day!"
>write 3,5,1 "This is the last text!"
Text "This is the last text!" written at position (3,5,1)
>read 3,5,1
Text at (3,5,1) :
"This is the last text!"
>exit
The important parts in the code are the main function where we get the dimensions from the user and create the array with :
const unsigned int DIMENSION_COUNT = 3; // dimension count for this test application, change it at will :)
// here is the type of the multi-dimensional (DIMENSION_COUNT dimensions here) array we want to use
// for this example, it own texts
typedef boost::multi_array< std::string , DIMENSION_COUNT > TextMatrix;
// this provide size/index based position for a TextMatrix entry.
typedef std::tr1::array<TextMatrix::index, DIMENSION_COUNT> Position; // note that it can be a boost::array or a simple array
/* This function will allow the user to manipulate the created array
by managing it's commands.
Returns true if the exit command have been called.
*/
bool process_command( const std::string& entry, TextMatrix& text_matrix );
/* Print the position values in the standard output. */
void display_position( const Position& position );
int main()
{
std::cout << "Multi-Array test!" << std::endl;
// get the dimension informations from the user
Position dimensions; // this array will hold the size of each dimension
for( int dimension_idx = 0; dimension_idx < DIMENSION_COUNT; ++dimension_idx )
{
std::cout << "Please enter the size of the dimension "<< dimension_idx <<" : ";
// note that here we should check the type of the entry, but it's a simple example so lets assume we take good numbers
std::cin >> dimensions[dimension_idx];
std::cout << std::endl;
}
// now create the multi-dimensional array with the previously collected informations
TextMatrix text_matrix( dimensions );
std::cout << "Text matrix with " << DIMENSION_COUNT << " dimensions of size ";
display_position( dimensions );
std::cout << " have been created."<< std::endl;
std::cout << std::endl;
std::cout << "Ready!" << std::endl;
std::cout << "Type 'help' for the command list." << std::endl;
std::cin.sync();
// we can now play with it as long as we want
bool wants_to_exit = false;
while( !wants_to_exit )
{
std::cout << std::endl << ">" ;
std::tr1::array< char, 256 > entry_buffer;
std::cin.getline(entry_buffer.data(), entry_buffer.size());
const std::string entry( entry_buffer.data() );
wants_to_exit = process_command( entry, text_matrix );
}
return 0;
}
And you can see that to accede an element in the array, it's really easy : you just use the operator() as in the following functions :
void write_in_text_matrix( TextMatrix& text_matrix, const Position& position, const std::string& text )
{
text_matrix( position ) = text;
std::cout << "Text \"" << text << "\" written at position ";
display_position( position );
std::cout << std::endl;
}
void read_from_text_matrix( const TextMatrix& text_matrix, const Position& position )
{
const std::string& text = text_matrix( position );
std::cout << "Text at ";
display_position(position);
std::cout << " : "<< std::endl;
std::cout << " \"" << text << "\"" << std::endl;
}
Note : I compiled this application in VC9 + SP1 - got just some forgettable warnings.
There are two ways to represent a 2-dimension array in C++. One being more flexible than the other.
Array of arrays
First make an array of pointers, then initialize each pointer with another array.
// First dimension
int** array = new int*[3];
for( int i = 0; i < 3; ++i )
{
// Second dimension
array[i] = new int[4];
}
// You can then access your array data with
for( int i = 0; i < 3; ++i )
{
for( int j = 0; j < 4; ++j )
{
std::cout << array[i][j];
}
}
THe problem with this method is that your second dimension is allocated as many arrays, so does not ease the work of the memory allocator. Your memory is likely to be fragmented resulting in poorer performance. It provides more flexibility though since each array in the second dimension could have a different size.
Big array to hold all values
The trick here is to create a massive array to hold every data you need. The hard part is that you still need the first array of pointers if you want to be able to access the data using the array[i][j] syntax.
int* buffer = new int[3*4];
int** array = new int*[3];
for( int i = 0; i < 3; ++i )
{
array[i] = array + i * 4;
}
The int* array is not mandatory as you could access your data directly in buffer by computing the index in the buffer from the 2-dimension coordinates of the value.
// You can then access your array data with
for( int i = 0; i < 3; ++i )
{
for( int j = 0; j < 4; ++j )
{
const int index = i * 4 + j;
std::cout << buffer[index];
}
}
The RULE to keep in mind
Computer memory is linear and will still be for a long time. Keep in mind that 2-dimension arrays are not natively supported on a computer so the only way is to "linearize" the array into a 1-dimension array.
You can alloc rowscolssizeof(int) and access it by table[row*cols+col].
Here is the easy way to do this in C:
void manipulate(int rows, int cols, int (*data)[cols]) {
for(int i=0; i < rows; i++) {
for(int j=0; j < cols; j++) {
printf("%d ", data[i][j]);
}
printf("\n");
}
}
int main() {
int rows = ...;
int cols = ...;
int (*data)[cols] = malloc(rows*sizeof(*data));
manipulate(rows, cols, data);
free(data);
}
This is perfectly valid since C99, however it is not C++ of any standard: C++ requires the sizes of array types to be compile times constants. In that respect, C++ is now fifteen years behind C. And this situation is not going to change any time soon (the variable length array proposal for C++17 does not come close to the functionality of C99 variable length arrays).
The standard way without using boost is to use std::vector :
std::vector< std::vector<int> > v;
v.resize(rows, std::vector<int>(cols, 42)); // init value is 42
v[row][col] = ...;
That will take care of new / delete the memory you need automatically. But it's rather slow, since std::vector is not primarily designed for using it like that (nesting std::vector into each other). For example, all the memory is not allocated in one block, but separate for each column. Also the rows don't have to be all of the same width. Faster is using a normal vector, and then doing index calculation like col_count * row + col to get at a certain row and col:
std::vector<int> v(col_count * row_count, 42);
v[col_count * row + col) = ...;
But this will loose the capability to index the vector using [x][y]. You also have to store the amount of rows and cols somewhere, while using the nested solution you can get the amount of rows using v.size() and the amount of cols using v[0].size().
Using boost, you can use boost::multi_array, which does exactly what you want (see the other answer).
There is also the raw way using native C++ arrays. This envolves quite some work and is in no way better than the nested vector solution:
int ** rows = new int*[row_count];
for(std::size_t i = 0; i < row_count; i++) {
rows[i] = new int[cols_count];
std::fill(rows[i], rows[i] + cols_count, 42);
}
// use it... rows[row][col] then free it...
for(std::size_t i = 0; i < row_count; i++) {
delete[] rows[i];
}
delete[] rows;
You have to store the amount of columns and rows you created somewhere since you can't receive them from the pointer.
2D C-style arrays in C and C++ are a block of memory of size rows * columns * sizeof(datatype) bytes.
The actual [row][column] dimensions exist only statically at compile time. There's nothing there dynamically at runtime!
So, as others have mentioned, you can implement
int array [ rows ] [ columns ];
As:
int array [ rows * columns ]
Or as:
int * array = malloc ( rows * columns * sizeof(int) );
Next: Declaring a variably sized array. In C this is possible:
int main( int argc, char ** argv )
{
assert( argc > 2 );
int rows = atoi( argv[1] );
int columns = atoi( argv[2] );
assert(rows > 0 && columns > 0);
int data [ rows ] [ columns ]; // Yes, legal!
memset( &data, 0, sizeof(data) );
print( rows, columns, data );
manipulate( rows, columns, data );
print( rows, columns, data );
}
In C you can just pass the variably-sized array around the same as a non-variably-sized array:
void manipulate( int theRows, int theColumns, int theData[theRows][theColumns] )
{
for ( int r = 0; r < theRows; r ++ )
for ( int c = 0; c < theColumns; c ++ )
theData[r][c] = r*10 + c;
}
However, in C++ that is not possible. You need to allocate the array using dynamic allocation, e.g.:
int *array = new int[rows * cols]();
or preferably (with automated memory management)
std::vector<int> array(rows * cols);
Then the functions must be modified to accept 1-dimensional data:
void manipulate( int theRows, int theColumns, int *theData )
{
for ( int r = 0; r < theRows; r ++ )
for ( int c = 0; c < theColumns; c ++ )
theData[r * theColumns + c] = r*10 + c;
}
If you're using C instead of C++ you might want to look at the Array_T abstraction in Dave Hanson's library C Interfaces and Implementations. It's exceptionally clean and well designed. I have my students do a two-dimensional version as an exercise. You could do that or simply write an additional function that does an index mapping, e.g.,
void *Array_get_2d(Array_T a, int width, int height, int i, int j) {
return Array_get(a, j * width, i, j);
}
It is a bit cleaner to have a separate structure where you store the width, the height, and a pointer to the elements.
I recently came across a similar problem. I did not have Boost available. Vectors of vectors turned out to be pretty slow in comparison to plain arrays. Having an array of pointers makes the initialization a lot more laborious, because you have to iterate through every dimension and initialize the pointers, possibly having some pretty unwieldy, cascaded types in the process, possibly with lots of typedefs.
DISCLAIMER: I was not sure if I should post this as an answer, because it only answers part of your question. My apologies for the following:
I did not cover how to read the dimensions from standard input, as other commentators had remarked.
This is primarily for C++.
I have only coded this solution for two dimensions.
I decided to post this anyway, because I see vectors of vectors brought up frequently in reply to questions about multi-dimensional arrays in C++, without anyone mentioning the performance aspects of it (if you care about it).
I also interpreted the core issue of this question to be about how to get dynamic multi-dimensional arrays that can be used with the same ease as the Java example from the question, i.e. without the hassle of having to calculate the indices with a pseudo-multi-dimensional one-dimensional array.
I didn't see compiler extensions mentioned in the other answers, like the ones provided by GCC/G++ to declare multi-dimensional arrays with dynamic bounds the same way you do with static bounds. From what I understand, the question does not restrict the answers to standard C/C++. ISO C99 apparently does support them, but in C++ and prior versions of C they appear to be compiler-specific extensions. See this question: Dynamic arrays in C without malloc?
I came up with a way that people might like for C++, because it's little code, has the ease of use of the built-in static multi-dimensional arrays, and is just as fast.
template <typename T>
class Array2D {
private:
std::unique_ptr<T> managed_array_;
T* array_;
size_t x_, y_;
public:
Array2D(size_t x, size_t y) {
managed_array_.reset(new T[x * y]);
array_ = managed_array_.get();
y_ = y;
}
T* operator[](size_t x) const {
return &array_[x * y_];
}
};
You can use it like this. The dimensions do not
auto a = Array2D<int>(x, y);
a[xi][yi] = 42;
You can add an assertion, at least to all but the last dimension and extend the idea to to more than two dimensions. I have made a post on my blog about alternative ways to get multi-dimensional arrays. I am also much more specific on the relative performance and coding effort there.
Performance of Dynamic Multi-Dimensional Arrays in C++
You could use malloc to accomplish this and still have it accessible through normal array[][] mean, verses the array[rows * cols + cols] method.
main()
{
int i;
int rows;
int cols;
int **array = NULL;
array = malloc(sizeof(int*) * rows);
if (array == NULL)
return 0; // check for malloc fail
for (i = 0; i < rows; i++)
{
array[i] = malloc(sizeof(int) * cols)
if (array[i] == NULL)
return 0; // check for malloc fail
}
// and now you have a dynamically sized array
}
There is no way to determine the length of a given array in C++. The best way would probably be to pass in the length of each dimension of the array, and use that instead of the .length property of the array itself.