How to print a row of an array? - c++

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

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>

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

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]);

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.

error: expected primary-expression before 'int' (In the context of a function that accepts arrays)

I'm making a simple console application that has a function that takes two arrays, one with a series of column widths, and the other a series of strings, and cout's each string then adds spaces until it reaches the next column.
I'm getting this error: error: expected primary-expression before 'int' at the first line of my columnizer function. I've tried changing the declaration in both the header and cpp file without success.
Here's the relevant code:
//cashier.cpp
void columnizer(int sizes[], std::string values[]){
int columnCount = (sizeof sizes) / (sizeof int);
for (int i=0; i < columnCount; i++){
string value = values[i];
cout << value;
char valueLength = sizeof value / sizeof char
char extraSpace = columnSizes[i] - valueLength;
while (extraSpace > 0){
cout << " ";
extraSpace--;
}
}
}
The call to columnizer:
//cashier.cpp
int columnSizes[5] = {7, 15, 20, 9, 9};
string headers[5] = {"Qty","ISBN","Title","Price","Total"};
...
columnizer(columnSizes, headers);
...
Header file:
//cashier.h
int cashier();
void columnizer(int sizes[], std::string values[]);
This code is riddled with problems:
what looks like argument arrays is actually turned into _pointers
there is a missing semicolon after one statement
the same statement is likely ill-advised: the length of a std::string s is determined using s.size()
names are used inconsistently
Here is an approach how you can patch up you code and avoid the obvious problems:
template <int N>
void columnizer(int (&sizes)[N], std::string (&values)[5]){
for (int i=0; i < N; i++){
std::string const& value = values[i];
std::cout << value;
char valueLength = value.size();
char extraSpace = sizes[i] - valueLength;
while (extraSpace > 0){
std::cout << " ";
extraSpace--;
}
}
}
The key magic is that you can pass references to arrays. Even more interesting, you can have the compiler deduce the size of arrays when passing them by reference, i.e., there is no need for the sizeof-hack. To make the deal even sweeter, the compiler will verify that the passed arrays are identical.
It seems you actually want to print column headers but your code actually doesn't print the column names. Note that you do not need to pad manually. You can, instead, set up the stream to pad with whitespace as needed, e.g.
std::cout << ' ' << std::setw(sizes[i]) << values[i];
You can use the manipulators std::left and std::right to put the output to the left or the right of any padding (you can also use std::internal to have the stream pad within the value, e.g. between the sign and value).

C++ Copying an array of chars using char* (no string libraries)

I am writing a C++ function that is supposed to duplicate an array of chars by copying each element character-by-character into a new array. Ideally, if I make the statements
char* a = "test";
char* b = copyString(a);
then both a and b should contain the string "test." However, when I print the copied array b, I get "test" plus a series of nonsense characters that seem to be the pointer. I don't want those, but I can't figure out where I'm going wrong.
My current function is as follows:
char* copyString(char* s)
{
//Find the length of the array.
int n = stringLength(s);
//The stringLength function simply calculates the length of
//the char* array parameter.
//For each character that is not '\0', copy it into a new array.
char* duplicate = new char[n];
for (int j = 0; j < n; j++)
{
duplicate[j] = s[j];
//Optional print statement for debugging.
cout << duplicate[j] << endl;
}
//Return the new array.
return duplicate;
}
For the purposes of understanding certain aspects of C++, I cannot use string libraries, which is where other answers I have found have fallen short in this case. Any help with this problem is greatly appreciated.
EDIT: I though my stringLength function was fine - perhaps I was wrong.
int stringLength(char* s)
{
int n;
//Loop through each character in the array until the '\0' symbol is found. Calculate the length of the array.
for (int i = 0; s[i] != '\0'; i++)
{
n = i + 1;
}
//Optional print statement for debugging.
// cout << "The length of string " << s << " is " << n << " characters." << endl;
return n;
}
You need to copy the 0 too. That's what a C-style string is, a null-terminated character array.
Really, all you need to do is add one to the length:
int n = stringLength(s) + 1; // include the '\0'
And then everything else will account for itself - you'll allocate an array of sufficient size, and copy the '\0' in your loop too.