This is Arduino code, but I have a feeling my error is with C++ in general and not specific to Arduino. I'm new to pointers and strings, so I probably am doing something wrong in that regard.
This is from a much larger program, but I've whittled it down to as little code as I can where I can still reproduce the bug.
It should just iterate through the letters of text[] and save each letter into newText[0][0], as well as print newText[0][0] and the counter variable i.
void setup() {
Serial.begin(9600);
}
void loop() {
const char text[] = "chunk";
static char newText[][10] = {};
static unsigned int i=0;
static int code = 0;
if(code == 0){
newText[0][0] = text[i]; //This
Serial.print(i);
Serial.println(newText[0][0]); //This
i++;
if(i>=strlen(text)){
code=1;
}
}
}
But as I have the code, i jumps to some number like 104 by the second iteration, when it should be equal to 1. (The exact value varies depending on how exactly the code looks.) If I comment out either of the lines that have the comment //This, then the counter works fine. Also, if I switch Serial.print(i); and the line before it, then it counts fine.
static char newText[][10] = {};
This creates a zero sized array (to be more precise a matrix of 0 rows and 10 columns). This would be illegal in C++ but gcc has an extension to allow it. Nevertheless even with gcc's extension, it's UB when you access newText[0][0] which is outside the size of the array. When you have UB anything can happen, the program can appear to work as you expect, it can print gibberish, it can crash, etc., literally anything.
So you need to declare a size that accommodates all your accesses, e.g.:
static char newText[1][10] = {};
if you only want 1 row (but in this case you don't need a matrix, a one dimension array would do fine).
Tip: use the String class for strings instead of raw arrays.
I have code in which I have a large number of characters all declared as being 1 higher than the other.
e.g. m1, m2, m3...
is there any way to increase the number I'm searching for by 1 in a for loop?
I have a long string of letters that I need to check to see if any of them match to the individual, but I cannot use strings due to situational limitations.
a1 is the particular character I'm looking for, m1 is the first in a long string of characters I am having to store as individuals
My attempt that wouldn't run:
for (a1 != m["%d"], &check, check++)
Unfortunately due to the limits of my application I can only use stdio.h and stdlib.h in my solution. Any help would be greatly appreciated
Variable names are used by the compiler, but are not part of the generated executable and therefore not accessible at runtime. You can simulate something like that by an array initialized with the addresses of the respective variables:
#include <stdio.h>
int main() {
int a0=0,a1=10,a2=15;
int *a[3] = { &a0, &a1, &a2 };
for (int i=0; i<3; i++) {
int val = *(a[i]);
printf("a%d:%d\n",i,val);
}
}
Output:
a0:0
a1:10
a2:15
I have the following code
#include<iostream>
#include<cmath>
#include<string>
using namespace std;
#include<fstream>
#include<iomanip>
#include<cstdio>
int main() {
//Here the code that creates the file benchmarks_cleaned.dat
int ncol = 16; //number of data per row
double datos[ncol];
char aux2;
double aux3;
int icol;
ifstream benchmarks2;
ofstream out_benchmarks2;
benchmarks2.open("benchmarks_cleaned.dat");
out_benchmarks2.open("benchmarks_final.dat");
if (benchmarks2.is_open()) {//second if
for (icol = 0; icol < ncol; icol++) {
benchmarks2>>datos[icol];
out_benchmarks2<<datos[icol]<<" ";
};
out_benchmarks2<<"\n";
benchmarks2.get(aux2);
while (aux2 != 'X') {
benchmarks2.unget();
benchmarks2>>aux3;
if (aux3 != datos[0]) {
benchmarks2.get(aux2);
} else {
out_benchmarks2<<datos[0]<<" ";
for (icol = 1; icol < ncol; icol++) {
benchmarks2>>datos[icol];
out_benchmarks2<<datos[icol]<<" ";
};
out_benchmarks2<<"\n";
benchmarks2.get(aux2);
};
};
} else {
cout<<"ERROR: unable to open the file"<<endl;
};//end of second if
out_benchmarks2<<"X";
out_benchmarks2.close();
out_benchmarks2.close();
benchmarks2.close();
return 0;
}; //end of main
The data file dummyValues.dat is:
{5.12, 0.1, 0.25} {{0.10, 4, 3, 2, 1, 1.44, 10.2}} {11.1, 12.2, 13.3, 14.4, 15.5, 16.6} 1000 2000 {{{{ 5.12, 0.1} {17.7, 18.08, 19.0, 020.0} {1.115, 2.0, 3.01, 4.65, 5, 6, 7, 8, 9, 10.0}, 3000 4000 { 5.12, 0.1} {117.7, 118.08, 119.0, 0120.0} {11.115, 21.0, 31.01, 41.65, 51, 61, 71, 81, 91, 110.0} 5000 6000 X
In benchmarks_cleaned.dat you reduce this file to just numbers separated by a blank space. The idea now is to write benchmarks_final.dat where in each row you have only 16 values and they must start by the same number 5.12 = datos[0] that you can check is repeated along dummyValues.dat
Nonetheless, while benchmarks_cleaned.dat is indeed created as desired (see below), benchmarks_final.dat does never start. I've checked that the programme runs but it does not write anything in benchmarks_final.dat. Where is the mistake?
benchmarks_cleaned.dat is:
5.12 0.1 0.25 0.1 4 3 2 1 1.44 10.2 11.1 12.2 13.3 14.4 15.5 16.6 1000 2000 5.12 0.1 17.7 18.08 19 20 1.115 2 3.01 4.65 5 6 7 8 9 10 3000 4000 5.12 0.1 117.7 118.08 119 120 11.115 21 31.01 41.65 51 61 71 81 91 110 5000 6000 X
Your calls to get(...) are catching blank spaces and missing the 'X'.
There's no need for get. Get rid of aux2 and change the while loop to:
while(benchmarks2 >> aux3)
So, the answer is given. It is good, correct. It is upvoted and accepted. Very good.
Just as an additional information, I will show a C++ solution, using more modern language elements. This solution skips the intermediate file (Can be generated by an one-liner) and also has no need to use the 'X' (Could also be added very simply).
With using the STL, we can come up with a solution, from the original source file to the final destination file in net 5 lines of code.
Please see:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <regex>
#include <iterator>
#include <algorithm>
std::regex reFloat{ R"([-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?)" };
using SVector = std::vector<std::string>;
using SVectorIter = SVector::iterator;
int main() {
// Open source file and check, if it coud be opened
if (std::ifstream sourceFileStream{ "r:\\dummyValues.dat" }; sourceFileStream) {
// Open destination file and check, if it could be opened
if (std::ofstream finalFileStream("r:\\benchmarks_final.dat"); finalFileStream) {
// Algorithm start ----------------------------------------------------------
// Define a string variable and initialize it with the contents of the file
std::string completeFile(std::istreambuf_iterator<char>(sourceFileStream), {});
// Define vector and initialize it with all float values from the file
SVector values(std::sregex_token_iterator(completeFile.begin(), completeFile.end(), reFloat), {});
// Iterate over the vector and find the next value equal to first-value
for (SVectorIter svi{ values.begin() }; (svi = std::find(svi, values.end(), values[0])) != values.end(); ++svi) {
// Copy 16 value to the final file
std::copy_n(svi, std::min(16, std::distance(svi, values.end())), std::ostream_iterator<std::string>(finalFileStream, " "));
finalFileStream << '\n';
}
// Algorithm end ----------------------------------------------------------
}
else {
std::cerr << "\n*** Error: Could not open final file\n";
}
}
else {
std::cerr << "\n*** Error: Could not open source file\n";
}
}
I guess not, but if you should have interest in understanding that, then I will explain to you. Please ask, I am happy to help.
EDIT You are interested in further explanations. That is OK, but I can of course not give a whole tutorial here.
Then let us start with some important feature that we are using here. The so called constructor. This you should know already. It is a special function of a class and basically used to "initialize" the data of a class. If you have a class like
struct MyClass {
int a;
// Constructor. Very simplified
MyClass(int value) { a = value; }
};
And if you want to define a variable of this type (create an instance of this type), the you can write:
MyClass test(3);
This will call the constructor and assign 3 to the class member a. You should basically know this already. If you look for classes in the C++ Reference, then you will always find a constructor for the defined classes.
Ok, then let's start now. First, we want to open a file for input. For this, we will use the STL class std::ifstream. And we will use one of it's constructors. Please look at the reference. The constructor 2 takes a filename as a const char* and opens the file. It implicitely calls open (see description in the link). The destructor, which will be called automatically, when the variable falls out of scope (After the next matching }. The destructor will automatically close the file for you. That is very good, and avoids mistakes.
So, you can write:
// Some previous code here
// . . .
{
// Some previous code here
// . . .
// Open the file
std::ifstream sourceFileStream{ "r:\\dummyValues.dat" };
// more code
// . . .
} // Now the scope is closed. The Variable "sourceFileStream" will fall out of scope
// and the file will be close automatically.
Cool.
Now a very important recommendation. You should always check, if an IO operation was successful. How to do that. For that, you should know, that std::stream have a kind of error state. And you can and should check this. You can read about those "states" here. If, you open a file, and it does not work. the the failbit will be set. This you can read here. So, you can check the failbit with the statement:
if (sourceFileStream.rdstate() == std::ios_base::failbit)
But that is somehow complicated. So, the designers of the IO-stream classes have defined a bool operator for the class. And, as you can read in the description, it checks whether the stream has no errors. An if statement needs a boolean condition. And if you write
if (sourceFileStream) {
then the boolean operator of this variable is returned and shows, if there is an error or not. That is very helpful.
Next, in C++17, a new syntax for the if statement has been introduced. Now you can define and initialize a variable within the if statement. For example
if (int inner = 0; x < y) { . . . }
Still the condition is x < y. Additionally, the variable "inner" will be defined and the advantage is that this variable is only visible in the inner scope of the if statement. After the closing bracket } of the if block, the variable will be gone.
And now, we can put all peices together:
if (std::ifstream sourceFileStream{ "r:\\dummyValues.dat" }; sourceFileStream) {
The first part of this if statement defines a variable "sourceFileStream" and calls its constructor with the filename. And so, it opens the file. The second part of the if statement is the condition, and calls the bool operator of the "sourceFileStream", to check, if the file could be opened. And the good thing is, the the variable "sourceFileStream", is only vidible within the if block. There is no need to have it available outside of this block, because, if the file could not be opened, then what would you do with it. And, additionally. After the if block is finished with "}", then the file will be automatically closed, because the variable falls out of scope, which will call the destructor.
Wow, that was a big explanation for one line of code.
Next line:
std::string completeFile(std::istreambuf_iterator<char>(sourceFileStream), {});
Uh, oh. What is that?
Obviously, we define a variable with the name "completeFile" with the data type std::string. Ok, that is still understandable. And then we have a (...), so calling the std::strings constructor. Please read here about the constructor number 6. It says:
Constructs the string with the contents of the range [first, last).
So, it takes a iterator to the first item of the range and an iterator to after the last item of the range. And then, it copies all characters in this range to the variable "completeFile". So it will fill out std::string with characters given by the 2 iterators.
So, nect part: std::istreambuf_iterator<char>(sourceFileStream). This is the begin iterator of the range. Please read here, that
std::istreambuf_iterator is a single-pass input iterator that reads successive characters from the std::basic_streambuf object for which it was constructed.
So, this thing reads successive characters from our "sourceFileStream". It will read character aftr character from the source file and copies them in our string variable. It does this until the end iterator, so until {}. Hm, whats that? This is the empty braced default initializer and it will simply call the default constructor. And if you look into the description of the std::istreambuf_iterators constructor number 1, then you see that it will be the "end-of-stream iterator". And, with that, all characters from thesource file, from the firts character to the last character, will be read and copied into our std::string variable "completeFile".
Cool, right? Defining a avriable and reading the complete source file at the same time.
Next line:
std::vector<std::string> values(std::sregex_token_iterator(completeFile.begin(), completeFile.end(), reFloat), {});
This is maybe too complicated for here and I can therefore only explain the basics. So, first, we will define a varaible with the name "values" of the type std::vector`````ofstd::strings. So, we want to store manystd::stringsin astd::vector````. That is understandable. And guess what, we will initialize this variable by using its constructor. And we will use again the range constructor, here constructor number 5. And this
Constructs the container with the contents of the range [first, last).
So basically the same as with the std::string above. It copies all strings, pointed to by the iterators, from first to last, into our vector. The begin iterator is the std::sregex_token_iterator. I cannot explain the regex theory here, but simply said, it will iterate over a pattern of similar items, defined by a regex in a "meta-language" and return them, so that they can be copyied into our vector.
And the pattern is that of a float value. If you look at a float value, then you can detect a pattern. It consists of optional +- signs, then some digits, maybe a period and more digits. That is always the same. And this pattern, we describe with the regex [-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?. You can copy and paste that into here and play with it. Then you may get a first understanding.
Back to the iterator. So, it will only return strings, that match with the patterns. So, it will only return float-value-strings. It will not return any other characters. Just those, that you need.
And similar as above, it starts with the first pattern in the given string and stops at {}. Same as above, the default constructor no 1 "Constructs the end-of-sequence iterator."
If you are interested in more, please comment, and I will explain the rest
I'm trying to define macros to read and print matrices in C++, but I'm trying something different, and it's not working:
#define rm(A, m, n, type)
for(int i = 0; i < m; i++)
for(int j = 0; j < n; j++)
scanf("%##type##", &A[i][j]);
A is the matrix (int or char)
I want to write d or c to read int or char, but this code isn't working and I don't even know why, I just tried to use the concat ## symbol to create the string that scanf receive as argument, but it bugs.
My questions are:
1 - why is it wrong?
2 - how can I make this macro work fine?
(if necessary, the solution may contain 1 or 2 macro declarations, but short ones, otherwise I wouldn't ask and I could just create a macro for int and other for char.
PS: this macro is written one line, the algorithm above is just to show what it does.
Thanks
If you really must make a macro for this - which, as others have pointed out, is a Really Bad Idea and Not The Right Way To Do This - the issue that you're encountering is that macros are interpreted by the preprocessor, which treats line breaks as as the end of a macro replacement. To fix this, you'll need to introduce some escape sequences at the ends of the lines:
#define rm(A, m, n, type) \
for(int i = 0; i < m; i++) \
for(int j = 0; j < n; j++) \
scanf("%" #type, &A[i][j]);
Notice that I've factored out your use of the token-pasting operator from the inside of the string, since the preprocessor doesn't fill in string literals for you, and instead opted to use the stringizing operator # to convert the type to a string literal. Since the compiler automatically concatenates adjacent string literals together, there's no need to paste anything. I should repeat that this is a really bad idea in that it hurts code readability and doesn't offer anything you can't already do with a regular C++ function.
You've tagged this question as C++, though, so I should point out that scanf has all sorts of type safety issues that can come up, so it's almost certainly safer to use the iostream library, which for all its faults does catch a ton of possible errors at compile-time.
Fundamentally, though, you shouldn't use macros for this. Just write a regular old function. Here's one way to do this, which has the added benefit that it automatically infers the sizes of arrays:
template <typename T, size_t m, size_t n>
void readArray(T (&array)[m][n], std::istream& source = std::cin) {
for (size_t i = 0; i < m; i++) {
for (size_t j = 0; j < n; j++) {
source >> array[i][j];
}
}
}
Now, you can say something like this:
double arr[137][42];
readArray(arr);
to read an array of doubles from cin, or
int arr[5][5];
ifstream input("my-file.txt");
readArray(arr, input);
to read an array of ints from an external file. This is type-safe and will raise a compiler error if you try reading in a case where the array size isn't defined or where the type can't be read. This prevents all sorts of possible problems. Compare this with your macro, where I could do something like this:
int arr[5][5];
rm(arr, 6, 6, f);
Oops - I just used the wrong array size and the wrong scanf specifier. Any time you can offload work to the compiler that saves you from having to make code changes across lots of places, it's worth considering!
I'm in a basic csci, computer programming course, and have been fiddling with this code for hours. I'm trying to pass an array through a function, and my code will not compile. I can't figure out what's going wrong with my code. It is as follows:
int buildArray (double*);
int main ()
{
int valuesPerLine;
int randomValues;
double array[110];
srand(time(NULL));
cout<<"How many values should be displayed per line? ";
cin>>valuesPerLine;
randomValues=buildArray(array[]);
cout<<array[50];
return (0);
}
int buildArray (double array[])
{
int t; //t is the total number of numbers in the array
t=rand();
array[t];
for (int i=0; i<t; i++)
{
array[i]=randDouble();
}
return(t);
}
The cout<<array[50]; is just there for myself to see if the answer changed. It will not be in the final code.
Is there something simple I missed? I've usually been able to help other people with the code in class but for some reason I can't figure this one out.
Thanks for everything!
P.S.
This isn't the entire code, and I know in this case I haven't said what the randDouble is, but I don't believe that is important, because that code seems to compile fine as it is. If it is needed, let me know and I can post it below.
When passing an array to function, you only pass the pointer to the first element of the array.
In your case, it would be:
randomValues = buildArray(array);