C++ Multi dimensional array from external file question - c++

I'm trying to get a contiguous line with values separated by "&" to load into a multi-dimensional array. Here's the way I'm trying to do it - Everything checks out in the code, except the string "str" which contains my separated values in the format "value1, value2, value3, etc..." just loads that whole string into array[0][0]. I know there are better ways of doing this, but what I would like to know is why C++ won't treat "str" as if I had typed out the individual values and hard coded "array".
Here is the code:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
int main(int argc, char* argv[])
{
string str, strTotal;
ifstream in;
in.open("Desktop/01_001.PAC");
getline(in,str);
while ( in ) {
strTotal += str;
getline(in,str);
}
string searchString( "&" );
string replaceString( ", " );
assert( searchString != replaceString );
string::size_type pos = 0;
while ( (pos = str.find(searchString, pos)) != string::npos ) {
str.replace( pos, searchString.size(), replaceString );
pos++;
}
string array[4][5] = {str};
cout << array[0][0];
return(0);
}
And here is the external file ("Desktop/01_001.PAC"):
void&void&void&void&a&a1&a2&a3&b&b1&b2&b3&c&c1&c2&c3&d&d1&d2&d3
Thanks in advance!

Because code and data are different things. Your code is compiled before it runs.
It sounds as if this is what you expect:
The string contains the text "foo, bar, baz".
The statement string[] whatever = {str}; is run.
Since "str" contains "foo, bar, baz", you want it to have the same effect as if the line of code were actually string[] whatever = {"foo", "bar", "baz"}.
Asking something like this implies a complete misunderstanding of how programming works.
Nothing this magical will ever happen in C++. It cannot, because (a) what if you actually wanted to put 'str' into the array? (b) what if 'foo', 'bar' and 'baz' were also variables in your program - should they be interpreted the same way?
Variable names are not text. They no longer exist, for all practical purposes, at the time that your code runs. They are only there so that you, as the programmer, can say "the value that is used over here should be the same one that is used over there".
Further, array initializations in C++ do not care how many elements are actually in the initialization vs. the declared size of the array. Any additional elements will be default-initialized (i.e., assigned empty strings).
A string cannot be treated like an array of strings, because it isn't one. If you want an array of strings, then build it, using the individual string elements as you determine them.
But since you don't know in advance how many elements there are, you should use std::vector instead of an array. And why are you trying to arrange the data into a 2-dimensional structure? How are you expecting to know how "wide" it should be?

If I'm reading your code correctly, you appear to be searching through the string (loaded from file), and only assigning the very last result to an array index (x=4, y=5). So your code is doing something like this:
while (have not found last variable)
search for next variable in string
assign variable to (4,5) in matrix
So that last assignment might even work, but since you only assign at the end, the array is not going to be filled the way I think you want it to be filled.
I'm going to assume the matrix you want is always the same size, otherwise things get more complicated. In this case, you could use something like this:
let xMax = 4
let yMax = 5
for (x from 0 to xMax)
for (y from 0 to yMax)
find the next variable in the string
assign it to the current (x,y) location in matrix
Debug statements are your friend here! Try the above solution without saving it to an array, and instead print out each term, to see if it is working correctly.
I would also point out that the string "void" is not the C++ keyword void, and so will not work if you want an array index to be void. Try getting your code to work without voids at first.

Related

Why do I have to make a 2d array for this

I was solving a question online on strings where we had to perform run-length encoding on a given string, I wrote this function to achieve the answer
using namespace std;
string runLengthEncoding(string str) {
vector <char> encString;
int runLength = 1;
for(int i = 1; i < str.length(); i++)
{
if(str[i - 1] != str[i] || runLength == 9)
{
encString.push_back(to_string(runLength)[0]);
encString.push_back(str[i - 1]);
runLength = 0;
}
runLength++;
}
encString.push_back(to_string(runLength)[0]);
encString.push_back(str[str.size() - 1]);
string encodedString(encString.begin(), encString.end());
return encodedString;
}
Here I was getting a very long error on this particular line in the for loop and outside it when I wrote:
encString.push_back(to_string(runLength));
which I later found out should be:
encString.push_back(to_string(runLength)[0]);
instead
I don't quite understand why I have to insert it as a 2D element(I don't know if that is the right way to say it, forgive me I am a beginner in this) when I am just trying to insert the integer...
In stupid terms - why do I gotta add [0] in this?
std::to_string() returns a std::string. That's what it does, if you check your C++ textbook for a description of this C++ library function that's what you will read there.
encString.push_back( /* something */ )
Because encString is a std::vector<char>, it logically follows that the only thing can be push_back() into it is a char. Just a single char. C++ does not allow you to pass an entire std::string to a function that takes a single char parameter. C++ does not work this way, C++ allows only certain, specific conversions betweens different types, and this isn't one of them.
And that's why encString.push_back(to_string(runLength)); does not work. The [0] operator returns the first char from the returned std::string. What a lucky coincidence! You get a char from that, the push_back() expects a single char value, and everyone lives happily ever after.
Also, it is important to note that you do not, do not "gotta add [0]". You could use [1], if you have to add the 2nd character from the string, or any other character from the string, in the same manner. This explains the compilation error. Whether [0] is the right solution, or not, is something that you'll need to figure out separately. You wanted to know why this does not compile without the [0], and that's the answer: to_string() returns a std::string put you must push_back() a single char value, and using [0] makes it happen. Whether it's the right char, or not, that's a completely different question.

How to create a C++ multidimensional array of names with basic types

I'm trying to instantiate and easily access an array of names in C++ using basic types in contiguous memory. I'm astounded that this is extremely difficult or complicated to do in C++ WITH ONLY basic types.
For some background, I am programming a microcontroller with limited memory, modest processing power, and it is handling serial communication over a network to 36 other microcontrollers sending continuous sensor data which is uploaded to a webserver. The shorter the refresh rate of the data, the better, so I prefer basic program features.
Not that I'm saying the more complicated stuff I've looked in other forums for, like an array of strings, has worked.
In my desperation, I was able to get this to work.
char names_array[] = "Bob\0\0Carl";
printf("%s",names_array); //outputs Bob
printf("%s",names_array + 5); //outputs Carl
This is a horrible solution though. My indexing is dependent on the longest name in the array, so if I added "Megan" to my list of names, I'd have to add a bunch of null characters throughout the entire array.
What I want to do is something like this:
char names_array[2] = {"Bob","Carl"}; //does not compile
printf("%s",names_array[0]);
printf("%s",names_array[1]);
//Error: A value of type "const char *" cannot be used to
//initialize an entity of type "char" in "main.cpp"
but that didn't work.
I want to loop through the names in my list and do something with each name, so at this point, this is my best solution.
char name0[] = "Bob";
loop_code(name0);
char name1[] = "Carl";
loop_code(name1);
.
.
.
I expect there's a reasonable way to make an array of pointers, each to an array of char terminated by null(s). I must be doing something wrong. I refuse to believe that a language like C++ is incapable of such a basic memory allocation.
You can, e.g., get an array of pointers to null-terminated strings:
const char* names_array[] = { "Bob", "Carl" };
and then
std::printf("%s", names_array[0]);
std::printf("%s", names_array[1]);
The problem with your attempt
char names_array[2] = {"Bob","Carl"};
is that you declare names_array to be an array of characters. This should never compile because what the = {"Bob","Carl"} essentially attempts to do is initialize each character in that array of characters with an entire array of characters of its own. A character is just a character, you cannot assign an entire array of characters to just an individual character. More precisely, initialization of a character array from a string literal is a special case of initialization [dcl.init.string] that allows a single string literal to be used to initialize an entire character array (because anything else doesn't make sense). What you actually want would be something more like an array of character arrays. However, the problem there is that you'd have to effectively pick a fixed maximum length for all strings in the array:
char names_array[][5] = { "Bob", "Carl" }; // each subarray is 5 characters in length
which would be potentially wasteful. You can flatten a series of multiple strings into one long array and then index into that, like you did with your first approach. The downside of that, as you've found out, is that you then need to know where each string starts in that array…
If you just want an array of string constants, a more modern C++ approach would be something like this:
#include <string_view>
using namespace std::literals;
constexpr std::string_view names[] = {
"Bob"sv,
"Carl"sv
};
The advantage of std::string_view is that it also has information about the length of the string. However, while std::string_view is compatible with most of the C++ standard library facilities that handle strings, it's not so simple to use it together with functions that expect C-style null-terminated strings. If you need null-terminated strings, I'd suggest to simply use an array of pointers to strings as shown at the very beginning of this answer…
char can has only one character.
If you want to use char, you can do it like
char name0[3] = "Bob";
char name1[4] = "Carl";
char *nameptr[2] = {&name0[0], &name1[0]};
Acutally, this pretty hard.
I suggest to you, use std::string.
std::string name[2] = {"Bob","Carl"};
this code is acceptable.

Need to access an element from part of a string array

Suppose I have this code:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string disectedString[5];
disectedString[0] = "011001";
string temp = disectedString[0];
string print = temp[0];
return 0;
}
So I'm selecting an element out of my array of strings, and then assigning it to a temp variable. From there, I want to select the first element out of the temp variable,(the first character). How would I go about doing this?
Your intuition is mostly valid: You use the square brackets operator, [], to access the element at an indexed position within a collection or sequence. Thus
disectedString[0] means "the first element of disectedString";
temp[0] means "the first element of temp";
What you've gotten mixed up are the types, as commenters and #demogorgon.net's answer have explained.
Now, with modern C++ you can "play dumb" and not declare what you know the types to be:
std::string disectedString[5];
disectedString[0] = "011001";
auto temp = disectedString[0];
auto print = temp[0];
Note the use of auto instead of a specific type name. This will work as you would like it to. You can then use use print, and do, for example:
std::cout << print;
and this will output 0.
By the way, I believe you should reconsider your choice of names:
Intuitively, print should refer to a function, or a method, which prints things; I'd suggest first_character or char_to_print or just c if you want to be brief.
temp is no more a temporary variable than, say, print.
It's better to avoid variable names which contain the type name, although we sometimes sort of have to resort to that. Specifically you using the word 'string' in variable names; probably not a good idea.
Your disectedString variable is not a string, it's an array of strings, which is confusing.
A string behaves in many ways like an array of char's (*). You need to set print to char type instead of string since you are trying to get a specific element from the string. So your print should look like this:
char print = temp[0];
(*) but it's really more complicated than that.
Here is a code example that prints the output.

How do I declare a new string the same length of a known const string?

I've been using:
string letters = THESAMELENGTH; // Assign for allocation purposes.
Reason being, if I:
string letters[THESAMELENGTH.length()];
I get a non constant expression complaint.
But if I:
string letters[12];
I'm at risk of needing to change every instance if the guide const string changes size.
But it seems foolish to assign a string when I won't use those entries, I only want my newly assigned string to be the same length as the previously assigned const string, then fill with different values.
How do you recommend I do this gracefully and safely?
You can
string letters(THESAMELENGTH.length(), ' '); // constructs the string with THESAMELENGTH.length() copies of character ' '
BTW: string letters[12]; doesn't mean the same as you expected. It declares a raw array of string containing 12 elements.
I only want my newly assigned string to be the same length as the previously assigned const string, then fill with different values.
Part of the reason the string class/type exists is so you don't have to worry about trying to manage its length. (The problem with arrays of char.)
If you have a const std::string tmp then you can't just assign anything to it after it has already been initialized. E.g.:
const std::string tmp = "A value"; // initialization
tmp = "Another value"; // compile error
How do you recommend I do this gracefully and safely?
If you really want to keep strings to a specific size, regardless of their contents, you could always resize your string variables. For example:
// in some constants.h file
const int MAX_STRING_LENGTH = 16;
// in other files
#include "constants.h"
// ...
std::string word = ... // some unknown string
word.resize(MAX_STRING_LENGTH);
Now your word string will have a length/size of MAX_STRING_LENGTH and anything beyond the end gets truncated.
This example is from C++ Reference
// resizing string
#include <iostream>
#include <string>
int main ()
{
std::string str ("I like to code in C");
std::cout << str << '\n';
unsigned sz = str.size();
str.resize (sz+2,'+');
std::cout << str << '\n';
str.resize (14);
std::cout << str << '\n';
return 0;
}
// program output
I like to code in C
I like to code in C++
I like to code
You can't just ask a string variable for its length at compile-time. By definition, it's impossible to know the value of a variable, or the state of any given program for that matter, while it's not running. This question only makes sense at run-time.
Others have mentioned this, but there seems to be an issue with your understanding of string letters[12];. That gives you an array of string types, i.e. you get space for 12 full strings (e.g. words/sentences/etc), not just letters.
In other words, you could do:
for(size_t i = 0; i < letters.size(); ++i)
letters[i] = "Hello, world!";
So your letters variable should be renamed to something more accurate (e.g. words).
If you really want letters (e.g. the full alphabet on a single string), you could do something like this:
// constants.h
const std::string ALPHABET_LC = "abc...z";
const std::string ALPHABET_UC = "ABC...Z";
const int LETTER_A = 0;
const int LETTER_B = 1;
// ...
// main.cpp, etc.
char a = ALPHABET_LC[LETTER_A];
char B = ALPHABET_UC[LETTER_B];
// ...
It all depends on what you need to do, but this might be a good alternative.
Disclaimer: Note that it's not really my recommendation that you do this. You should let strings manage their own length. For example, if the string value is actually shorter than your limit, you're causing your variable to use more space/memory than needed, and if it's longer, you're still truncating it. Neither side-effect is good, IMHO.
The first thing you need to do is understand the difference between a string length and an array dimension.
std::string letters = "Hello";
creates a single string that contains the characters from "Hello", and has length 5.
In comparison
std::string letters[5];
creates an array of five distinct default-constructed objects of type std::string. It doesn't create a single string of 5 characters. The reason for the non-constant complaint when doing
std::string letters[THESAMELENGTH.length()];
is that construction of arrays in standard C++ is required to use a length known to the compiler, whereas the length of a std::string is determined at run time.
If you have a string, and what to create another string of the same length, you can do something like
std::string another_string(letters.length(), 'A');
which will create a single string containing the required number of letters 'A'.
It is largely pointless to do what you are seeking as a std::string can dynamically change its length anyway, as needed. There is also nothing stopping a std::string from allocating more than it needs (e.g. to make provision for multiple increases in its length).

Confusing char arrays and pointers in c++

Hey everyone, thanks for taking the time to address my problem. I've looked at so much material at this point that I've just started getting more and more confused. Basically, I'm writing a simple segment of code that parses a string. Please understand that my question is NOT about parsing. I am using C++ and have never used C before and possess a little bit of c++ experience (introductory experience, I'm still a newbie).
struct parsedString{
char chunk1[50];
char chunk2[10];
char chunk3[50];
};
main(char* bigstring)
{
parsedString ps;
ps = parseMe(bigString)
cout << ps.chunk1 << endl;
cout << ps.chunk2 << endl;
cout << ps.chunk3 << endl;
}
parsedString parseMe(char* stringToParse)
{
char* parseStr = stringToParse;
parsedString ps;
ps.chunk1 = first x chars;
ps.chunk2 = next y chars;
ps.chunk3 = last z chars;
return ps;
}
Obviously this is not working code, I didn't want to throw up all the extra stuff since it would be tougher to read through and I'm pretty sure my problem is a newbie c/c++ problem and something about memory allocation or something like that...
Basically when the main function gets to printing the strings from the parsedString it prints out exactly what I want it to, plus garbage characters. I'm entering the values for each array ps.chunk using
ps.chunk1[i] = *parseStr
since parseStr gets me each individual character. I can't figure out where the garbage characters are coming from, does it have something to do with how I am accessing the big string? Originally I used char in the struct instead of arrays and when I printed from within the parseMe() function they would come out great but they would turn into gibberish when I accessed it from the main function. Any help is appreciated, thanks so much.
If something is unclear please let me know I'll do my best to elaborate.
It's not clear why you're trying to do this with '\0' terminated
strings, when C++ has a perfectly usable string class, but
supposing some pedagogical reasons: are your strings '\0'
terminated? How do you extract and copy the first x chars into
ps.chunk1? How do you ensure that it has a '\0'?
If you really want to get exactly n characters, you have to:
assert(strlen(parseStr) >= n);
, copy them into the target (which must contain at least n+1 char's),
memcpy(ps.chunk1, parseStr, n);
, and add the final '\0':
ps.chunk1[n] = '\0';
(And, of course, advance parseStr: parseStr += n;)
Or you can simply use std::string everywhere, and write
something like:
ps.chunk1(stringToParse.substr(startPosition, length));
As pointed out by others, you should use std::string to represent strings, and save yourself all the trouble. This could look like this:
struct parsedString{
std::string chunk1;
std::string chunk2;
std::string chunk3;
};
parsedString parseMe(const std::stirng & stringToParse) {
parsedString result;
// just an example - this assigns the first two characters of stringToParse
// to chunk1
result.chunk1 = stringToParse.substr(0, 2);
// get the other chunks
return result; // return the result
}
The above code should illustrate the usage. You can find more information on std::string here.
This could be happening due to a couple of reasons.
When you declare parsedString ps; it would be good to initialize the structure and make sure that you are receiving clean memory blocks to work with.parsedString ps = {0}; Some platforms don't do this and it's up to you to zero the memory before using it.
char* strings must end with the \0 character. This character signals the end of a char*. This is mandatory! Not inserting it at the end of the string will most probably make the print operation (for instance) display contents beyond the limits of the array giving you garbage characters. This is automatically achieved by zeroing all the struct as I suggest above.