C++ Pass an array to a function and read its members - c++

in my c++ program I want to pass an array to a function and print the members of that array to console.
now I got into two problems:
int main()
{
unsigned char numbers[8] = { 1,2,3,4,5,6,7,8 };
for (auto i = 0; i < sizeof(numbers); i++)
{
std::cout << numbers[i] << "\n"; // First Problem: Here i get
}
logger(numbers);
}
passing the numbers to logger defined as void logger(unsigned char data[]) cause the type change to unsigned char * so there is no way to iterate over the array as the size is unknown.
my goal also is to pass any sized arrays but assuming that the size of an array is always 8, I changed the signature to
logger(&numbers)
void logger(unsigned char(*data)[8])
{
for (auto i = 0; i < sizeof(*data); i++)
{
std::cout << *(data[i]) << "\n";
}
}
iterating over data has the first problem and output is ``
so the questions are;
why do I get a weird ASCII character at cout.
how should we deal passing an array to another function and iterate over it, I searched alot but found no solution

The problem lies in the contents of your array:
unsigned char numbers[8] = { 1,2,3,4,5,6,7,8 };
Those get interpreted as character codes (because of the array element type)., not literal values. Most probably the character mapping used is ASCII, and characters 1 through 8 aren't printable.
To obtain the character value representing 1, you'd need to write a character literal '1'. If your intended to store and treat them as numbers, you could either change the type of the array to int[8], or cast them when printing:
std::cout << static_cast<int>(numbers[i]) << "\n";
As a side not, if you intended to use characters, you should change the type to char.
To solve passing the arrays of arbitrary size, either use a template and pass a reference to std::array, or simply use a vector.

You cannot pass an array to a function in C++. There are several ways around this
1) Use vectors instead of arrays
2) Pass a reference to the array (this only works with a fixed size array)
3) Pass a pointer to the first element of the array (this requires that you pass the size as a seperate parameter).
Here's how you do all three
1) use vectors
#include <vector>
std::vector<unsigned char>{1,2,3,4,5,6,7,8}:
logger(numbers);
void logger(const vector<unsigned char>& data)
{
for (auto i = 0; i < data.size(); i++)
{
std::cout << (unsigned)data[i] << "\n";
}
}
2) use a reference
unsigned char numbers[8] = { 1,2,3,4,5,6,7,8 };
logger(numbers);
void logger(unsigned char (&data)[8])
{
for (auto i = 0; i < 8; i++)
{
std::cout << (unsigned)data[i] << "\n";
}
}
3) use a pointer
unsigned char numbers[8] = { 1,2,3,4,5,6,7,8 };
logger(numbers, 8);
void logger(unsigned char *data, size_t size)
{
for (auto i = 0; i < size; i++)
{
std::cout << (unsigned)data[i] << "\n";
}
}
vectors are the best solution. C++ has proper data structures as standard, use them.
As has already been explained your printing problems are due to the special rules for printing characters, just cast to unsigned before printing.
No code has been tested (or even compiled).

For your first problem use:
int arr_size = sizeof(numbers)/sizeof(numbers[0]);

Related

C++ loop breaked 'cause the std::find algorithm

I have the next C++ code snippet:
...
static constexpr const char* my_char_array [10] { // Some literals here... } // Member of a class
std::vector<std::string> splitted_input { // Contains C++ strings }
std::vector<std::string> matched_keywords { // The coincident ones will be copied here }
for (int i = 0; i < sizeof(this->my_char_array); i++) {
std::cout << "Comparing: " << this->my_char*_array[i] << std::endl;
auto value = std::find(splitted_input.begin(), splitted_input.end(), (std::string) this->my_char_array[i]);
if ( value != end(splitted_input) ) {
matched_keywords.push_back(this->keywords[i]);
}
}
I am iterating over an const char*, looking for a literal that could be inside a vec<string>.
When I use the std::find algorithm, the for loop stops on the first iteration (std::cout just outputs the first value on my_char*_array).
Never faced an issue like that. Any idea?
Thanks in advice.
In this line:
for (int i = 0; i < sizeof(this->my_char_array); i++) {
you are using sizeof operator which is returning number of bytes which my_char_array occupies, and this is equal to size of pointer (8 bytes on x64 system) multiplied by number of pointers in your array. So this code is iterating over more elements than actually are in you array which is causing UB (undefined behaviour). The usual solution is to divide by element size:
for (int i = 0; i < sizeof(this->my_char_array)/sizeof(this->my_char_array[0]); i++) {
or even better, replace array with std::array, example:
static constexpr std::array<const char*, 2> my_char_array = {"dsds", "dddd"};
and
for (int i = 0; i < my_char_array.size(); i++) {
and don't forget to #include <array>

How to print a row of an array?

I am fairly new to C++ programming, and I am getting stuck at how to print values from a specific row.
I mean:
std::string musical_things [][][] = {
{
{"Scale"}, {"Minor Natural"}, {"1","2","b3","4","5","b6","b7"}
},
{
{"Scale"}, {"Major"}, {"1","2","3","4","5","6","7"}
},
};
So, when I try to access just a single full row, I get the memory address.
If I loop it, I get the memory address of each element.
for (int i = 0; i < 10; i++)
std::cout << "Output: " << musical_things [i]<< "\n" << std::endl;
And I am just trying to get musical_things [i].
For i = 0, output should be: {"Scale"}, {"Chromatic"}, {"1","2","3","4","5","6","7"}.
Note that your data doesn't fit a 3-D array model: the individual arrays are of different length, which will make the compiler "pad" them with zero-valued characters. This is a great amount of padding, and, what's worse, it's not easily predictable.
For example, the longest string in your data has 13 characters, so all strings will be padded to that size (including e.g. "1"). Also, the longest list of strings contains 7 strings, so all lists will be padded to that size. So your array {"Scale"} will be padded to an array of 7 strings, with strings which contain 13 zero-values characters.
This is really not what you want. You can ignore it (you really don't care if compiler does unnecessary work) but it will backfire when you try to count your strings - you will have to ignore the empty strings somehow.
Assuming you want to fix this, note that your data is a jagged array of strings and not a 3-D array.
std::vector<std::vector<std::vector<std::string>>> musical_things =
{
{
{"Scale"}, {"Minor Natural"}, {"1","2","b3","4","5","b6","b7"}
},
{
{"Scale"}, {"Major"}, {"1","2","3","4","5","6","7"}
},
};
To make code which prints it, I decided to use bottom-up approach, which is easy to explain.
First of all, I made a function which prints a string in the format you want:
void print(std::ostream& stream, const std::string& string)
{
stream << '"' << string << '"';
}
Then, I made a function which prints an array of strings:
void print(std::ostream& stream, const std::vector<std::string>& array)
{
bool first_time = true;
stream << '{';
for (const std::string& s: array)
{
if (!first_time)
stream << ",";
print(stream, s);
first_time = false;
}
stream << '}';
}
It iterates over the array, and calls the print function for each string. It cannot use operator<< because you want each string to be enclosed in quotes.
It uses the first_time flag to print the separators properly - there is one separator fewer than the number of strings.
Finally, the code which prints an array of arrays:
void print(std::ostream& stream, const std::vector<std::vector<std::string>>& array)
{
bool first_time = true;
for (const auto& v: array)
{
if (!first_time)
stream << ", ";
print(stream, v);
first_time = false;
}
}
It's mostly the same, but it uses a different separator, and the type of the loop-variable is const auto&, because I was too lazy to type const std::vector<std::string>& (I let the compiler deduce it).
Oops, I've just typed it! So I actually wasn't lazy :)
There is no overload for ostreams operator << that does what you want directly. You need to iterate the strings and print them:
for (int i = 0; i < 10; i++) {
std::cout << "Output: ";
for (int j = 0; j < 10; j++) {
for (int k = 0; k < 10; k++) {
std::cout << musical_things[i][j][k];
}
std::cout << "\n";
}
I assumed all dimensions are of size 10, which isnt the case in your example. Managing sizes of multidimensional c-arrays is a mess, you should use a std::vector instead, or rather define a struct that holds data the belongs together. Chances are high that you actually only need a single dimensional std::vector<my_struct>.

Why does passing a 2D array without the complete size of the array still compile and run? [duplicate]

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

C++: How to allocate and fill dynamic array of a struct passed by reference?

I have a very simple structure for adding size field to dynamic arrays:
template <typename T>
struct sized_array {
int size;
T* array;
};
I cannot use std::vector or std::array. The function to fill the array initializes the sized_array.array field and fills it with random integers:
void array_fill(sized_array<int> &array, int size = ARRAY_SIZE) {
array.array = new int[size];
array.size = size;
for (int i = 0; i < size; i++) {
array.array[i] = random_in_range(RANDOM_MIN, RANDOM_MAX);
}
}
The other functions, array_join and array_print print the contents of an array:
string array_join(sized_array<int> &array, string delimiter) {
string text = "";
for (int i = 0; i < array.size; i++) {
text += array.array[i];
if (i < array.size) text += delimiter;
}
return text;
}
void array_print(sized_array<int> &array) {
cout << "array(" << array.size << ") = [";
cout << array_join(array, ", ") << "]" << endl;
}
The array variable is declared like so, and the program runs this code:
sized_array<int> number_array;
int main() {
srand(time(NULL));
array_fill(number_array);
array_print(number_array);
system("pause");
return 0;
}
When debugging, the array shows this value when first initialized, then appears to take the first returned value of random_in_range and never change, staying at one element -- the first returned value.
When printed, the array appears to be filled with random ASCII characters, and the first element is never the one it was (even though the debugger displayed it had one element).
What is the cause of this and how to avoid this problem?
When printed, the array appears to be filled with random ASCII characters
This is because you have an error in your array_join function:
text += array.array[i];
This would append an int re-interpreted as char, not a decimal representation of the number.
Use std::to_string to fix the problem:
text += std::to_string(array.array[i]);
If you are restricted to a C++ version prior to C++11, use std::stringstream instead.

sizeof continues to return 4 instead of actual size

#include <iostream>
using namespace std;
int main()
{
cout << "Do you need to encrypt or decrypt?" << endl;
string message;
getline(cin, message);
int letter2number;
for (int place = 1; place < sizeof(message); place++)
{
letter2number = static_cast<int>(message[place]);
cout << letter2number << endl;
}
}
Examples of problem: I type fifteen letters but only four integers are printed. I type seven letters but only four integers are printed.
The loop only occurs four times on my computer, not the number of characters in the string.
This is the only problem I am having with it, so if you see other errors, please don't tell me. (It is more fun that way.)
Thank you for your time.
sizeof returns the size of an expression. For you, that's a std::string and for your implementation of std::string, that's four. (Probably a pointer to the buffer, internally.)
But you see, that buffer is only pointed to by the string, it has no effect on the size of the std::string itself. You want message.size() for that, which gives you the size of the string being pointed to by that buffer pointer.
As the string's contents change, what that buffer pointer points to changes, but the pointer itself is always the same size.
Consider the following:
struct foo
{
int bar;
};
At this point, sizeof(foo) is known; it's a compile-time constant. It's the size of an int along with any additional padding the compiler might add.
You can let bar take on any value you want, and the size stays the same because what bar's value is has nothing to do with the type and size of bar itself.
You want to use message.size() not sizeof(message).
sizeof just gives the number of bytes in the data type or expression. You want the number of characters stored in the string which is given by calling size()
Also indexing starts at 0, notice I changed from 1 to 0 below.
for (int place = 0; place < message.size(); place++)
{
letter2number = static_cast<int>(message[place]);
cout << letter2number << endl;
}
Any pointer on an x86 system is only 4 bytes. Even if it is pointing to the first element of an array on the heap which contains 100 elements.
Example:
char * p = new char[5000];
assert(sizeof(p) == 4);
Wrapping p in a class or struct will give you the same result assuming no padding.
class string
{
char * ptr;
//...
size_t size(); // return number of chars (until null) in buffer pointed to by ptr
};
sizeof(message) == sizeof(string) == sizeof(ptr) == 4; // size of the struct
message.size() == number of characters in the message...
sizeof(type) returns the size of the type, not the object. Use the length() method to find the length of the string.
#include<iostream>
#include<conio.h>
using namespace std;
int main()
{
cout << "Do you need to encrypt or decrypt?" << endl;
string message;
getline(cin, message);
int letter2number;
for (int place = 0; place < message.size(); place++)
{
letter2number = static_cast<int>(message[place]);
cout << letter2number << endl;
}
getch();
return 0;
}