Comparing chars in a character array with strcmp - c++

I have read an xml file into a char [] and am trying to compare each element in that array with certain chars, such as "<" and ">". The char array "test" is just an array of one element and contains the character to be compared (i had to do it like this or the strcmp method would give me an error about converting char to cons char*). However, something is wrong and I can not figure it out. Here is what I am getting:
< is being compared to: < strcmp value: 44
Any idea what is happening?
char test[1];
for (int i=0; i<amountRead; ++i)
{
test[0] = str[i];
if( strcmp(test, "<") == 0)
cout<<"They are equal"<<endl;
else
{
cout<<test[0]<< " is being compare to: "<<str[i]<<" strcmp value= "<<strcmp(test, "<") <<endl;
}
}

strcmp() expects both of its parameters to be null terminated strings, not simple characters. If you want to compare characters for equality, you don't need to call a function, just compare the characters:
if (test[0] == '<') ...

you need to 0 terminate your test string.
char test[2];
for (int i=0; i<amountRead; ++i)
{
test[0] = str[i];
test[1] = '\0'; //you could do this before the loop instead.
...
But if you always intend to compare one character at a time, then the temp buffer isn't necessary at all. You could do this instead
for (int i=0; i<amountRead; ++i)
{
if (str[i] == "<")
cout<<"They are equal"<<endl;
else
{
cout << str[i] << " is being compare to: <" << endl;
}
}

strcmp wants both strings to be 0 terminated.
When you have non-0 terminated strings, use strncmp:
if( strncmp(test, "<", 1) == 0 )
It is up to you to make sure that both strings are at least N characters long (where N is the value of the 3rd parameter). strncmp is a good functions to have in your mental toolkit.

Related

C++ Check and modify strings / String subscript out of range

I'm trying to make a program which modifies words in a specific manner:
It should first check the ending of the words and then proceed to modify them. I won't explain it in detail, because it doesn't make much sense in English.
I've written the following:
#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;
int main()
{
cout << "Por favor, introduzca los gentilicios separados por la tecla enter, para finalizar, escriba OK" << '\n';
string name[10];
string place[10];
for (int i(0); (i < 10); i++)
{
getline(cin, name[i]);
if (name[i] == "OK") //Error here
break;
}
for (int i(0); (i < 10); i++)
{
place[i] = name[i];
if (name[i][name[i].length() - 1] == 'c')
{
if (name[i][name[i].length()] == 'a' || (name[i][name[i].length()] == 'o') || (name[i][name[i].length()] == 'u'))
place[i][place[i].length() - 1] = 'q';
place[i][place[i].length()] = 'u';
place[i] = place[i] + "istan";
}
else if (name[i][name[i].length()] == 'a' || name[i][name[i].length()] == 'e' || name[i][name[i].length()] == 'i' || name[i][name[i].length()] == 'o' || name[i][name[i].length()] == 'u')
{
place[i][place[i].length()] = 'i';
place[i] = place[i] + "stan";
}
if (name[i][name[i].length()] == 's')
place[i] = place[i] + "tan";
else {
place[i] = place[i] + "istan";
}
place[i][0] = toupper(place[i][0]);
}
for (int i(0); (i < 10); i++)
{
cout << place[i] << '\n';
}
return 0;
}
Now I'm getting the error "String subscript out of range" . I would like to know where is the error exactly. I know it prompts when I write "OK", at line "18".
The condition i <= sizeof(name). sizeof(name) returns the size of the array in bytes, not the number of elements in it. Even if it returned the number of elements, <= is wrong and would cause an out-of-bounds access (should be <).
To loop through all elements in an array, you can use the range-based for-loop:
for(auto& n : name)
{
getline(cin, n);
if (n == "OK")
break;
}
Or to do it the right way with the C-style for-loop:
for (int i(0); i < sizeof(name)/sizeof(name[0]; i++)
{
…
}
Here:
for (int i(0); (i <= sizeof(name)); i++)
sizeof(name) is the size in bytes of the array, which as it is an array of std::string is effectively meaningless. If you want to iterate over 10 items, simply say so (note also that less-than-or-equals is also wrong here):
for (int i = 0; i < 10; i++)
And here:
getline(cin, name[i]);
whenever you perform input you must check the return value of the input function and handle any errors:
if( ! getline(cin, name[i]) ) {
// handle error somehow
}
And here:
string * p;
you do not want to be dealing with pointers to strings. If you want to access the contents of a string, you use operator[] or other string member functions on the string.
std::strings are not like cstrings. You can just grab a part of them using a std::string*. When you do
*(p+ (name[i].length()-2))
You actually say advance the address stored in p by name[i].length()-2 amount and access that string. If you go past the end of the name array then that is undefined behavior. If not you still haver a std::string which cannot be compared with a char. If you want to check if the string ends with "ca" then you can just use
if (name[i].substr(name[i].size() - 2) == "ca")
You're last loop is doing something quite funky. There's no need to go that far. You can just do something like:
if (name[i][name[i].length - 2] == 'c')
To compare the next to last character with c. And a very similar test to compare the last one with a.
To clarify why what you're doing is not OK, you first get p as a pointer to a string to the current element. Then you do some pointer arithmetic p + (name[i].length - 2), which still results in a pointer to a string. Finally, you dereference this, resulting in a string. Which you can't compare to a char. Moreover, the pointer was to some arbitrary address in memory, so the dereference would produce a string with very bad data in it. Quite arbitrary, one might say. If you tried to work with it you'd break your program
You seem to be working with the string as one would with a C-like string, a char*. The two are not the same, even though they represent the same concepts. A C++ string, usually, has a size field, and a char* pointer inside it, as well as a bunch of other logic to make working with it a char-m.
Because you aren't comparing against a specific char in the string, you're comparing against a string.
Considering the following bit of code:
*(p + (name[i].length() - 2))
This evaluates to a string because you are taking p (a string*) and concatenating a char to it. This means it's still a string (even though it's a one-character string), thus the other side of the equation won't be comparable to it.
What you need here instead is this:
if (name[i][name[i].length() - 2] == 'c')
Since name[i] is already a string, we can just get the char from it using the code above. This does return char, so it's comparable. This also allows you to get rid of the whole string* bit as it is not needed.
First, (i <= sizeof(name)) is wrong, it should be i < sizeof(name) / sizeof(*name). sizeof(array) return the size of array in bytes, you need to divide the size of an array's element to actually get the maximum element count of an array. If you find that complicated then use std::vector:
vector<string> name(10); //a vector of size 10
for (size_t i = 0; i < name.size(); i++) //name.size(), simple
Secondly, you need to keep track of how many strings in your name array. Or you need to check if name[i] == "OK" then break the second loop (similar to the first loop). name[i] after "OK" are invalid.
Thirdly, don't use *(p+ (name[i].length()-2)). If you want the second last character of name[i], you can write it as name[i][name[i].size()-2] or name[i].end()[-2] or end(name[i])[-2]
If you want to check if the word ends in "ca", then you can use substr:
if (name[i].substr(name[i].size() - 2) == "ca")
{
//...
}

C++ Vowels in string, comparison forbidden

I'm trying to count the total number of vowels in a string. I'm using strlen to get the total length of the string but then when I try and count through the string by each letter it says C++ forbids comparison. So I assume something is wrong in my if statement.
#include <iostream>
#include <cstring>
using namespace std;
int main() {
char sentence[] = "";
int count;
int total;
int length;
int lengthcount;
int output;
output = 0;
length = 0;
count = 0;
total = 0;
cin >> total;
while (total != count){
cin >> sentence;
length = strlen(sentence);
while (length != lengthcount)
if (sentence[length] == "a" ||sentence[length] == "e"||sentence[length] == "i"||sentence[length] == "o"||sentence[length] == "u"||sentence[length] == "y"){
++ output;
++ lengthcount;
else{
++lengthcount;
}
}
++count;
}
return 0;
}
sentence[length] is a single character. It should be compared to a 'a' and not "a".
"a" is a character array and direct comparison with the built in operator== is not supported.
sentence[index] == 'a'; // where index is probably lengthcount in your example
Should do the trick. If use of std::string is an option, you should favour that over char arrays.
In addition, your char sentence[] = ""; will need some more space than just the '\0' character. Some alternatives include the use of std::string and std::getline or char[nnn] with cin.get(...) to make sure that you don't overrun the buffer you allocate.
See Nialls answer for one of the main problems.
The algorithmic problem with your code is again in the if statement.
sentence[length] returns the last character of your c_string (in this case, the null character '/0' that terminates the string).
Your if statement should look more like:
if (sentence[lengthcount] == 'a'\
||sentence[lengthcount] == 'e'\
||sentence[lengthcount] == 'i'\
||sentence[lengthcount] == 'o'\
||sentence[lengthcount] == 'u'\
||sentence[lengthcount] == 'y')
{
\\do something
}
Please remember to pre-allocate space for the string too, i.e.
char sentence[50];
which would give you space for 49 chars + terminator.
Alternatively, use a std::string
If you wish to count the total number of vowels in the given string, you need to use sentence[lengthcount]. Lets say the sentence is abc strlen(sentence) would return 3, and since in c++, the indexing begins with 0 and not 1, therefore sentence[length] would check for '\0' hence in the entire loop you check against the last value which is '\0' which is meaningless. Also, don't forget to initialize lengthcount. Rest all the things per-mentioned.
char sentence [] = "" produces an array sentence with a length of 1.
cin >> sentence isn't going to work very well, is it, if sentence cannot hold more than one character and one character is already needed for the trailing nul byte?
lengthcount is an unitialised variable, and the rest of the code just makes my head hurt.

How does strings comparison in C++ work?

I am trying to solve this problem.
I am implementing it with strings. Here is my code snippet
string s,ss;
// s and ss both contains integer input.
while(s <= ss )
//while( s<=ss && s.size() <= ss.size())
{
int i = inc, j = dec; // inc and dec are middle values. both equal if odd else different
while((s[j]-'0')==9 && i < len && j>=0){
// for cases like 999
s[i] = s[j] = '0';
i++;
j--;
}
if(j<0){
s = "1" + s;
int l = s[len-1] - '0';
l++;
//cout<<l<<"\n";
s[len] = (l + '0');
}
else{
int l = s[j] - '0';
l++;
s[i] = s[j] = (l+'0');
}
if(s <= ss)
cout<<"out in wild "<<s<<" and "<<ss<<"\n";
}
cout<<s<<endl;
The problem that I am facing is when input is like 999 or 9999. The outer while loop keeps on looping even when the value of s increases, but if I add while( s<=ss && s.size() <= ss.size()) it works completely fine. Why is while(s<=ss) is not working? I rarely use the string class, so I don't understand it completely. Why don't string s= 101 and ss=99 stop the while loop?
Complete code link is here
You are comparing strings with lexicographical order, not numbers , so "101" is less than "99" (because '1' < '9') , e.g.
int main(){
std::string s = "99";
std::string ss = "101";
std::cout << std::boolalpha << (s <= ss);
}
Outputs false.
Notes:
A better design for your program would be to manipulate numbers (int or double ...) and not strings in the first place, so this kind of expressions would naturally work as you expect.
E.g. "101" + "99" is "10199", not "200" ...
But if you really need strings, consider this post to sort strings containing numbers.
As pointed by #Deduplicator, a program that needlessly overuses strings is sometimes called Stringly Typed
Also see std::lexicographical_compare
Since your input explicitly only involves positive integers without leading 0, writing a comparison function is trivial, something like : (untested)
/* Returns 1 if the integer represented by s1 > the integer represented by s2
* Returns -1 if the integer represented by s1 < the integer represented by s2
* Return 0 is both are equals
*
* s1 and s2 must be strings representing positive integers without trailing 0
*/
int compare(const std::string& s1, const std::string& s2)
{
if(s1.size() > s2.size())
return 1;
if(s2.size() > s1.size())
return -1;
for(std::size_t i = 0 ; i < s1.size() ; ++i)
{
if(s1[i] - '0' < s2[i] - '0')
return 1;
if(s2[i] - '0' < s1[i] - '0')
return -1;
}
return 0;
}
While s and ss are string variables, they are compared character by character.
In the case that you mentioned being: s = "101" & ss = "99", by first hand it will check the first character in each string, and as '1' < '9' it exit up with s < ss. I would advise you to convert those values to integers before comparison.
As the s is compared with ss in lexicographical order, I would suggest you to compare one char from tail with one char from head (one by one till you reach the middle) to solve that problem.

Input C-style string and get the length

The string input format is like this
str1 str2
I DONT know the no. of characters to be inputted beforehand so need to store 2 strings and get their length.
Using the C-style strings ,tried to made use of the scanf library function but was actually unsuccessful in getting the length.This is what I have:
// M W are arrays of char with size 25000
while (T--)
{
memset(M,'0',25000);memset(W,'0',25000);
scanf("%s",M);
scanf("%s",W);
i = 0;m = 0;w = 0;
while (M[i] != '0')
{
++m; ++i; // incrementing till array reaches '0'
}
i = 0;
while (W[i] != '0')
{
++w; ++i;
}
cout << m << w;
}
Not efficient mainly because of the memset calls.
Note:
I'd be better off using std::string but then because of 25000 length input and memory constraints of cin I switched to this.If there is an efficient way to get a string then it'd be good
Aside from the answers already given, I think your code is slightly wrong:
memset(M,'0',25000);memset(W,'0',25000);
Do you really mean to fill the string with the character zero (value 48 or 0x30 [assuming ASCII before some pedant downvotes my answer and points out that there are other encodings]), or with a NUL (character of the value zero). The latter is 0, not '0'
scanf("%s",M);
scanf("%s",W);
i = 0;m = 0;w = 0;
while (M[i] != '0')
{
++m; ++i; // incrementing till array reaches '0'
}
If you are looking for the end of the string, you should be using 0, not '0' (as per above).
Of course, scanf will put a 0 a the end of the string for you, so there's no need to fill the whole string with 0 [or '0'].
And strlen is an existing function that will give the length of a C style string, and will most likely have a more clever algorithm than just checking each character and increment two variables, making it faster [for long strings at least].
You do not need memset when using scanf, scanf adds the terminating '\0' to string.
Also, strlen is more simple way to determine string's length:
scanf("%s %s", M, W); // provided that M and W contain enough space to store the string
m = strlen(M); // don't forget #include <string.h>
w = strlen(W);
C-style strlen without memset may looks like this:
#include <iostream>
using namespace std;
unsigned strlen(const char *str) {
const char *p = str;
unsigned len = 0;
while (*p != '\0') {
len++;
*p++;
}
return len;
}
int main() {
cout << strlen("C-style string");
return 0;
}
It's return 14.

"The Debugger has exited due to signal 10" when writing a char* iteration

So I have a program that makes char* stuff lowercase. It does it by iterating through and manipulating the ascii. Now I know there's probably some library for this in c++, but that's not the point - I'm a student trying to get a grasp on char*s and stuff :).
Here's my code:
#include <iostream>
using namespace std;
char* tolower(char* src);
int main (int argc, char * const argv[])
{
char* hello = "Hello, World!\n";
cout << tolower(hello);
return 0;
}
char* tolower(char* src)
{
int ascii;
for (int n = 0; n <= strlen(src); n++)
{
ascii = int(src[n]);
if (ascii >= 65 && ascii <= 90)
{
src[n] = char(ascii+32);
}
}
return src;
}
( this is not for an assignment ;) )
It builds fine, but when I run it it I get a "The Debugger has exited due to signal 10" and Xcode points me to the line: "src[n] = char(ascii+32);"
Thanks!
Mark
Yowsers!
Your "Hello World!" string is what is called a string literal, this means its memory is part of the program and cannot be written to.
You are performing what is called an "in-place" transform, e.g. instead of writing out the lowercase version to a new buffer you are writing to the original destination. Because the destination is a literal and cannot be written to you are getting a crash.
Try this;
char hello[32];
strcpy(hello, "Hello, World!\n");
Also in your for loop, you should use <, not <=. strlen returns the length of a string minus its null terminator, and array indices are zero-based.
As Andrew noted "Hello World\n" in code is a read-only literal. You can either use strcpy to make a modifiable copy, or else try this:
char hello[] = "Hello, World!\n";
This automatically allocates an array on the stack big enough to hold a copy of the literal string and a trailing '\0', and copies the literal into the array.
Also, you can just leave ascii as a char, and use character literals instead of having to know what the numeric value of 'A' is:
char ascii;
for (int n = 0; n < strlen(src); n++)
{
ascii = src[n];
if (ascii >= 'A' && ascii <= 'Z')
{
src[n] = ascii - 'A' + 'a';
}
}
While you're at it, why bother with ascii at all, just use src[n]:
for (int n = 0; n < strlen(src); n++)
{
if (src[n] >= 'A' && src[n] <= 'Z')
{
src[n] -= 'A' - 'a';
}
}
And then, you can take advantage of the fact that in order to determine the length of a c-string, you have to iterate though it anyway, and just combine both together:
for (char *n = src; *n != 0; n++)
if (*n >= 'A' && *n <= 'Z')
*n -= 'A' - 'a';