non-standard syntax use '&' to create a pointer to member c++ - c++

I have created two vectors o3 ( a vector to hold the words from a string) and o4 ( a vector to hold those vector of words). In the if statement, once ";" has been found in the vectoro3[i], I want to stop putting words from thato3[i]` into o4, and go to the next line held in o3. I am getting the error "non-standard syntax use '&' to create a pointer to member c++" in the line commented as ERROR. Any help is highly appreciated. Thanks!
while (getline(myfile, line, (char)32)) // first read entire line into a
//string
// problem : this also reads empty lines
// and gives error
// while returning words
{
abc2.push_back(line); // inserting individual strings into a vector
//cout << abc[i] << "\n"; // use this to see
// them as a vector of lines
//i++;
}
for (int i = 0; i < abc.size(); i++)
{
single_line = abc[i];
if (((single_line[0] >= 'A') && (single_line[0] <= 'Z')) ||
((single_line[0] >= 'a') && (single_line[0] <= 'z')))
{
if (abc[i] != "")
{
o3 = output_words(abc[i], (char)32); // function to separate
//words in a line
int j1 = 0; int j2 = 0;
while (j2 < o3.size())
{
if (o3[j2] != "" && "\t") // *IMP* require this line to
// get words
// irrespective of spaces
{
if (o3[j2].find != ";") // ERROR
{
o4.resize(i + 1);// NO CLUE WHY IT WORKED WITH
// i+1 resize???!!!
o4[i].push_back(o3[j2]);
j2++;
}
else
{
j2++;
}
}
else
{
j2++;
}
}
}
}
else
{
o3 = { "" }; // o1 will be null vector (i.e will contain
// nothing inside)
o4.push_back(o3);
}
}

The result of expression o3[j2].find is a member of o3[j2] by the name find. That result is then compared with the string literal in the full expression o3[j2].find != ";".
The warning message seems to imply, that decltype(o3[j2])::find is a member function. In this context, the name of the member function decays to a member function pointer. The compiler warns you because such implicit conversion is ill-formed according to the standard, but supported as a language extension by the compiler. The standard way is to use the address-of operator & explicitly.
Comparing (a pointer to) a member function to a string literal makes little sense. You may have intended to call the member function instead. To call a function, you add the argument list surrounded by parenthesis: o3[j2].find(/* arguments */).
Assuming decltype(o3[j2]) is std::string (you forgot to declare o3), then the comparison with string literal also seems suspicious. std::string::find returns the index of the found substring or character. Comparing an integer to a string literal doesn't make any sense either. I recommend pondering what that line is supposed to do.

Related

Logical error. Elements in std::string not replaced properly with for loop

I'm currently doing a programming exercise from a C++ book for beginners. The task reads as follows: "Write a function that reverses the characters in a text string by using two pointers. The only function parameter shall be a pointer to the string."
My issue is that I haven't been able to make the characters swap properly, see the output below. (And I also made the assumption that the function parameter doesn't count, hence why I'm technically using three pointers).
I am almost certain that the problem has to do with the for loop. I wrote this pseudocode:
Assign value of element number i in at_front to the 1st element in transfer_back.
Assign value of element number elem in at_back to element number i in at_front.
Assign value of the 1st element in transfer_back to element number elem in at_back.
Increment i, decrement elem. Repeat loop until !(i < elem)
I wasn't sure whether of not I was supposed to take the null terminator into account. I tried writing (elem - 1) but that messed up with the characters even more so I've currently left it as it is.
#include <iostream>
#include <string>
using namespace std;
void strrev(string *at_front) {
string *transfer_back = at_front, *at_back = transfer_back;
int elem = 0;
while(at_back->operator[](elem) != '\0') {
elem++;
}
for(int i = 0; i < elem; i++) {
transfer_back->operator[](0) = at_front->operator[](i);
at_front->operator[](i) = at_back->operator[](elem);
at_back->operator[](elem) = transfer_back->operator[](0);
elem--;
}
}
int main() {
string str = "ereh txet yna";
string *point_str = &str;
strrev(point_str);
cout << *point_str << endl;
return 0;
}
Expected output: "any text here"
Terminal window: "xany text her"
The fact that the 'x' has been assigned to the first element is something I haven't been able to grasp.
Here is the correct answer
void strrev(string *at_front) {
string *at_back = at_front;
char transfer_back;
int elem = 0;
while(at_back->operator[](elem) != '\0') {
elem++;
}
for(int i = 0; i <elem; i++) {
transfer_back = at_front->operator[](i);
at_front->operator[](i) = at_back->operator[](elem);
at_back->operator[](elem) = transfer_back;
elem--;
}
}
Let me explain why you have that error. string *transfer_back = at_front those two are pointed to the same reference, that is why when you change transfer_back->operator[](0) = at_front->operator[](i);this change will reflect in at_front string as well.
"Write a function that reverses the characters in a text string by using two pointers. The only function parameter shall be a pointer to the string."
This sounds to me like the question addresses C strings but not std::string.
Assuming my feeling is right, this could look like:
#include <iostream>
#include <string>
void strrev(char *at_front) {
char *at_back = at_front;
if (!*at_back) return; // early out in edge case
// move at_back to end (last char before 0-terminator)
while (at_back[1]) ++at_back;
// reverse by swapping contents of front and back
while (at_front < at_back) {
std::swap(*at_front++, *at_back--);
}
}
int main() {
char str[] = "ereh txet yna";
strrev(str);
std::cout << str << '\n';
return 0;
}
Output:
any text here
Live Demo on coliru
Note:
I stored the original string in a char str[].
If I had used char *str = "ereh txet yna"; I had assigned an address of a constant string to str. This feels very wrong as I want to modify the contents of str which must not be done on constants.
strrev():
The at_back[1] reads the next char after address in at_back. For a valid C string, this should be always possible as I excluded the empty string (consisting of 0-terminator only) before.
The swapping loop moves at_front as well as at_back. As the pointer is given as value, this has no "destructive" effect outside of strrev().
Concerning std::swap(*at_front++, *at_back--);:
The swapping combines access to pointer contents with pointer increment/decrement, using postfix-increment/-decrement. IMHO, one of the rare cases where the postfix operators are useful somehow.
Alternatively, I could have written:
std::swap(*at_front, *at_back); ++at_front; --at_back;
Please, note that std::string is a container class. A pointer to the container cannot be used to address its contained raw string directly. For this, std::string provides various access methods like e.g.
std::string::operator[]()
std::string::at()
std::string::data()
etc.

iterating vector of strings C++

The code is to read instructions from text file and print out graphic patterns. One is my function is not working properly. The function is to read the vectors of strings I've got from the file into structs.
Below is my output, and my second, third, and sixth graphs are wrong. It seems like the 2nd and 3rd vectors are not putting the correct row and column numbers; and the last one skipped "e" in the alphabetical order.
I tried to debug many times and still can't find the problem.
typedef struct Pattern{
int rowNum;
int colNum;
char token;
bool isTriangular;
bool isOuter;
}Pattern;
void CommandProcessing(vector<string>& , Pattern& );
int main()
{
for (int i = 0; i < command.size(); i++)
{
Pattern characters;
CommandProcessing(command[i], characters);
}
system("pause");
return 0;
}
void CommandProcessing(vector<string>& c1, Pattern& a1)
{
reverse(c1.begin(), c1.end());
string str=" ";
for (int j = 0; j < c1.size(); j++)
{
bool foundAlpha = find(c1.begin(), c1.end(), "alphabetical") != c1.end();
bool foundAll = find(c1.begin(), c1.end(), "all") != c1.end();
a1.isTriangular = find(c1.begin(), c1.end(), "triangular") != c1.end() ? true : false;
a1.isOuter = find(c1.begin(), c1.end(), "outer") != c1.end() ? true : false;
if (foundAlpha ==false && foundAll == false){
a1.token = '*';
}
//if (c1[0] == "go"){
else if (c1[j] == "rows"){
str = c1[++j];
a1.rowNum = atoi(str.c_str());
j--;
}
else if (c1[j] == "columns"){
str = c1[++j];
a1.colNum = atoi(str.c_str());
j--;
}
else if (c1[j] == "alphabetical")
a1.token = 0;
else if (c1[j] == "all"){
str = c1[--j];
a1.token = *str.c_str();
j++;
}
}
}
Before debugging (or posting) your code, you should try to make it cleaner. It contains many strange / unnecessary parts, making your code harder to understand (and resulting in the buggy behaviour you just described).
For example, you have an if in the beginning:
if (foundAlpha ==false && foundAll == false){
If there is no alpha and all command, this will be always true, for the entire length of your loop, and the other commands are all placed in else if statements. They won't be executed.
Because of this, in your second and third example, no commands will be read, except the isTriangular and isOuter flags.
Instead of a mixed structure like this, consider the following changes:
add a default constructor to your Pattern struct, initializing its members. For example if you initialize token to *, you can remove that if, and even the two bool variables required for it.
Do the parsing in one way, consistently - the easiest would be moving your triangular and outer bool to the same if structure as the others. (or if you really want to keep this find lookup, move them before the for loop - you only have to set them once!)
Do not modify your loop variable ever, it's an error magnet! Okay, there are some rare exceptions for this rule, but this is not one of them.
Instead of str = c1[++j];, and decrementing later, you could just write str = c1[j+1]
Also, are you sure you need that reverse? That makes your relative +/-1 indexing unclear. For example, the c1[j+1 is j-1 in the original command string.
About the last one: that's probably a bug in your outer printing code, which you didn't post.

C++ char-by-char comparison of a string

I'm trying to work on a string comparison check for an introductory C++ course; it's an online course and unfortunately the instructor is not very responsive. For a current lab, I need to perform a number of manipulations on string data.
Currently, I'm working on a step to check if a string has any repeated characters, and if a repetition is found, to delete the repeated characters at their present spot and move one copy of the letter to the beginning of the string. This is only to be done for the first double to be found.
I've set up a basic counter to move through the string looking for matches, checking a stored character (updated on each iteration) to the current position in the string.
I tried multiple string functions (comparing the current inputString[i] to the previous such, stored as a second string tempStore), but those always gave char conversion errors. I've tried the below instead, but this is now giving an error: "invalid conversion from 'char' to 'const char*'.
inputString is given by the user, testA and testB are defined as type char
Any ideas?
while (opComplete == false) {
if (i == 0) {
i++;
}
else if (i == inputString.size()) {
//Not Found
opComplete = true;
}
else if (i > 0) {
testA = inputString[i-1];
testB = inputString[i];
if (strcmp(testA,testB) != 0) {
i++;
}
else {
inputString.insert(0,inputString[i]);
inputString.erase(i,1);
inputString.erase(i-1,1);
opComplete = true;
}
}
}
Your problem is in this line:
inputString.insert(0,inputString[i]);
The std::string.insert() function the way you call it here has the following signature:
string& insert ( size_t pos1, const char* s );
so it expects a const char pointer. You, however, are giving it the inputString[i]. The return value of std::string.operator[] is a reference (as here), hence the error. However, by the time you reach your else, you already have the desired character in your testB variable, so you can just change the line to
inputString.insert(0, &testB);
You also can't pass normal chars into strcmp. You can use operator==, or, in your case, operator!= though.
You are using the insert method incorrectly, check its reference here for possible arguments.
while (opComplete == false)
{
if (i == 0)
i++;
else if (i == inputString.size())
opComplete = true;
else if (i > 0) {
char testA = inputString[i-1];
char testB = inputString[i];
if(testA!=testB)
i++;
else {
inputString.insert(0,&testB); //Problem Corrected here.
inputString.erase(i,1);
inputString.erase(i-1,1);
opComplete = true;
}
}
}

skipping a character in an array if previous character is the same

I'm iterating through an array of chars to do some manipulation. I want to "skip" an iteration if there are two adjacent characters that are the same.
e.g. x112abbca
skip----------^
I have some code but it's not elegant and was wondering if anyone can think of a better way? I have a few case's in the switch statement and would be happy if I didn't have to use an if statement inside the switch.
switch(ent->d_name[i])
{
if(i > 0 && ent->d_name[i] == ent->d_name[i-1])
continue;
case ' ' :
...//code omited
case '-' :
...
}
By the way, an instructor once told me "avoid continues unless much code is required to replace them". Does anyone second that? (Actually he said the same about breaks)
Put the if outside the switch.
While I don't have anything against using continue and break, you can certainly bypass them this time without much code at all: simply revert the condition and put the whole switch statement within the if-block.
Answering the rectified question: what's clean depends on many factors. How long is this list of characters to consider: should you iterate over them yourself, or perhaps use a utility function from <algorithm>? In any case, if you are referring to the same character multiple times, perhaps you ought to give it an alias:
std::string interesting_chars("-_;,.abc");
// ...
for (i...) {
char cur = abc->def[i];
if (cur != prev || interesting_chars.find(cur) == std::string::npos)
switch (current) // ...
char chr = '\0';
char *cur = &ent->d_name[0];
while (*cur != '\0') {
if (chr != *cur) {
switch(...) {
}
}
chr = *cur++;
}
If you can clobber the content of the array you are analyzing, you can preprocess it with std::unique():
ent->erase(std::unique(ent->d_name.begin(), ent->d_name.end()), ent.end());
This should replace all sequences of identical characters by a single copy and shorten the string appropriately. If you can't clobber the string itself, you can create a copy with character sequences of just one string:
std::string tmp;
std::unique_copy(ent->d_name.begin(), ent->d_name.end(), std::back_inserter(tmp));
In case you are using C-strings: use std::string instead. If you insist in using C-strings and don't want to play with std::unique() a nicer approach than yours is to use a previous character, initialized to 0 (this can't be part of a C-string, after all):
char previous(0);
for (size_t i(0); ent->d_name[i]; ++i) {
if (ent->d_name[i] != previous) {
switch (previous = ent->d_name[i]) {
...
}
}
}
I hope I understand what you are trying to do, anyway this will find matching pairs and skip over a match.
char c_anotherValue[] = "Hello World!";
int i_len = strlen(c_anotherValue);
for(int i = 0; i < i_len-1;i++)
{
if(c_anotherValue[i] == c_anotherValue[i+1])
{
printf("%c%c",c_anotherValue[i],c_anotherValue[i+1]);
i++;//this will force the loop to skip
}
}

input string validation without external libraries for c++

I need to validate one input string from a user. Eventually it will need to break down into two coordinates. ie a4 c3. And once they are coordinates they need to be broken out into 4 separate ints. a=0 b=1, etc. They must also follow the following stipulations:
If an end-of-input signal is reached the program quits.
Otherwise, all non-alphanumeric characters are discarded from the input.
If what remains is the single letter 'Q'
Then the program quits.
If what remains consists of 4 characters, with one letter and one digit among the first two characters and one letter and one digit among the last two characters, and if each letter-digit pair is in the legal range for our grid
Then input is acceptable.
I have completely over-thought and ruined my function. Please let me know where I can make some corrections.
I am mainly having trouble going from one string, to four chars if and only if the data is valid. Everything else I can handle.
Here is what I have so far.
void Grid::playerMove()
{
string rawMove;
string pair1 = " ";
string pair2 = " ";
bool goodInput = false;
char maxChar = 'a';
char chary1, chary2;
int x11,x22,y11,y22;
for (int i =0; i<size; i++)
{
maxChar++;
}
while(!goodInput)
{
cout<<"What two dots would you like to connect? (Q to quit) ";
cin>>rawMove;
rawMove = reduceWords(rawMove);
if (rawMove == "Q")
{
cout<<"end game";
goodInput = false;
}
else if (rawMove.size() == 4)
{
for(int j=0;j<2;j++)
{
if (pair1[j] >='a' && pair1[j] <=maxChar)
{
chary1 = pair1[j];
}
else if(pair1[j] >=0 && pairl[j]<=size+1)
{
x1 = pair1[j];
}
}
for(int k=0;k<2;k++)
{
if (pair2[k] >='a' && pair2[k] <=maxChar)
{
chary2 = pair2[k];
}
else if(pair2[k] >=0 && pair2[k]<=size+1)
{
x2 = pair2[k];
}
}
}
if(char1 != NULL && char2 != NULL && x1 !=NULL && x2 != NULL)
{
for (int m = 0; m <= size m++)
{
if (char1 == m;)
{
x1 = m;
}
}
for (int n = 0; n <= size n++)
{
if (char2 == n)
{
x2 = n;
}
}
}
}
The end goal would be to have x1, x2, y1, and y2 with their respective values.
Keep in mind I am not allowed to have any external libraries.
It's not clear what exactly you want to achieve, but here are some pointers to get you started:
The while loop will never end because you're setting goodInput to false on quit which lets the loop continue.
The code probably does not even compile? You are missing a curly closing brace..
You are initializing pair1 and pair2 to empty strings but never change them again, so they will never contain any real information about your moves
maybe what you really want is to split up rawMove into the pair1 and pair2 substrings first?
Since this is a homework - and you're supposed to learn from those (right?) - I'm not going to give you the complete answer, but rather something like a recipe:
Use std::istream::getline(char*, std::streamsize s) to read a whole line from std::cin. Make sure you allocate a buffer large enough to hold the expected input (including the terminating null character) plus some more for invalid characters. After the call, check the failbit (input was too long) and the eofbit (hit the end-of-input) of the std::cin stream and handle those cases. Construct a std::string from the buffer if there was no error or EOF has not been reached.
Write a character-classification function (e.g. call it isAlNum(char c)) that returns true if the char argument is alpha-numeric, and false otherwise.
Combine std::string::erase(), std::remove_if(), std::not1(), std::ptr_fun() and your function isAlNum() to sanitise the input string.
Write a function that validates and parses the coordinates from the sanitised input string and call it with the sanitised input string.
Wrap the whole thing in an appropriate while() loop.
This should get you started in the right direction. Of course, if you're allowed to use C++11 features and you know how to write good regular expressions, by all means, use the <regex> header instead of doing the parsing manually.