Issue with main arguments handling - c++

I can't compare main() arguments with const char* strings.
Simple code for explaining:
#include <stdio.h>
int main(int argc, char *argv[])
{
int i;
if(argc>1)
{
for (i=1;i<argc;++i)
{
printf("arg[%d] is %s\n",i,argv[i]);
if(argv[i]=="hello")
printf(" arg[%d]==\"hello\"\n",i);
else
printf(" arg[%d]!=\"hello\"\n",i);
}
}
return 0;
}
Simple compile g++ test.cpp. When I try execute it, I see next thing:
>./a.out hello my friend
arg[1] is hello
arg[1]!="hello"
arg[2] is my
arg[2]!="hello"
arg[3] is friend
arg[3]!="hello"
Whats wrong with my code?

Strings can't be compared with ==, use strcmp:
if (strcmp(argv[i], "hello") == 0)
You have to #include <string.h>

Whenever you use argv[i] == "hello", the operator "==" donot take string as its operand so in actual the compiler compares the pointer to argv[i] with the pointer to constant string "Hello" which is always false and hence the result you are getting is correct, to compare string literals use srtcmp function.
int strcmp(const char *s1, const char *s2);
which compares the two strings s1 and s2. It returns an integer less than, equal to, or greater than zero, if s1 is found, respectively, to be less than, to match, or be greater than s2.

In this statement
if(argv[i]=="hello")
you compare pointers because the string literal is implicitly converted to const char * (or char * in C) that points to its first character. As the two pointers have different values the expression is always false. You have to use standard C function strcmp instead. For example
if( std::strcmp( argv[i], "hello" ) == 0 )
To use this function you should include header <cstring>(in C++) or <string.h> (in C).

Related

Does C++ treat char pointers as c style strings?

Does C++ treat char pointers as c-style strings?
int main(int argc,char* argv[])
{
if (argv[1] == "-d")
{
}
}
argv[1] contains a char pointer, how is the statement argv[1] == "-d" not causing the compiler to throw an error because "d" is a string whereas argv[1] is a pointer to a char value
because "d" is a string whereas argv[1] is a pointer to a char value
That's where you're kind of wrong friend.
argv[1] is in this case a char* like you said.
"-d" is a const char[3] (-d plus the null terminator), this array can decay to a pointer which means == compiles.
As pointed out in the comments though, this will probably not do what you expect it to do. This will do a pointer comparison and not a comparison of the actual strings. You'll need to use strcmp for that.

Trying to add a string object to an integer

This is probably a very basic question for which I have been searching on google for the last 20 mins. I am not sure if i am phrasing it correctly, but I am not getting an explanation that I understand.
Basically, I have a string object and when I add an integer value x, it shortens the string by x characters.
Here is the code:
#include <iostream>
#include <string>
void Print::print(std::string str)
{
std::cout << str << std::endl;
}
print("formatString:" + 5);
The output is: tString:
Now i realise that the above is incorrect and during my search I have found ways correct the behaviour, but I haven’t found what is actually happening internally for me to get the above result.
Thanks
The answer is simple: Pointer arithmetic.
Your string literal (array of const char including implicit 0-terminator), decays to a const char* on use, which you increment and pass to your print()-function, thus invoking the std::string-constructor for string literals.
So, yes, you start with a string object (0-terminated array of const char), but not a std::string object.
Basically, I have a string object
No, you do not have a string object. "formatString:" is not a std::string, but a "string" literal. It is in fact a const char*. A const char* has a operator + defined that takes an integer and advances the value of the pointer with a number of positions. In your case it's 5.
To get a compiler error you'd have to wrap the literal in a std::string.
print(std::string("formatString:") + 5);
"formatString:" is a string literal that has type const char[14] That is it is an array of const char with size equal to 14 (the array includes the terminating zero).
In expressions like this
"formatString:" + 5
the array is implicitly converted to a pointer to its first element. So if for example const char *p denotes this pointer then the expression looks as
p + 5
The result of the expression is a pointer that points to the element of the array with index 5. That is there is used the pointer arithmetic.
P + 5 points to the first symbol of string "tString"
And this expression is used by the constructor of class std::string.
Examine the following,
#include <iostream>
void print(std::string str)
{
std::cout << str << std::endl;
}
int main(int argc, char* argv[])
{
//following two lines created implicitly by the compiler
const char* pstr = "formatString";
std::string tmp(pstr + 5); //string c-tor: string (const char* s);
// now tmp: --> "tString"
print(tmp);
return 0;
}
pstr is a pointer and you are doing pointer arithmetic when you use + operation.
Note:Compiler may create different internal structure, but it is a instructive way to think the above two lines.

Is char and int interchangeable for function arguments in C?

I wrote some code to verify a serial number is alpha numeric in C using isalnum. I wrote the code assuming isalnum input is char. Everything worked. However, after reviewing the isalnum later, I see that it wants input as int. Is my code okay the way it is should I change it?
If I do need to change, what would be the proper way? Should I just declare an int and set it to the char and pass that to isalnum? Is this considered bad programming practice?
Thanks in advance.
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
bool VerifySerialNumber( char *serialNumber ) {
int num;
char* charPtr = serialNumber;
if( strlen( serialNumber ) < 10 ) {
printf("The entered serial number seems incorrect.");
printf("It's less than 10 characters.\n");
return false;
}
while( *charPtr != '\0' ) {
if( !isalnum(*charPtr) ) {
return false;
}
*charPtr++;
}
return true;
}
int main() {
char* str1 = "abcdABCD1234";
char* str2 = "abcdef##";
char* str3 = "abcdABCD1234$#";
bool result;
result = VerifySerialNumber( str1 );
printf("str= %s, result=%d\n\n", str1, result);
result = VerifySerialNumber( str2 );
printf("str= %s, result=%d\n\n", str2, result);
result = VerifySerialNumber( str3 );
printf("str= %s, result=%d\n\n", str3, result);
return 0;
}
Output:
str= abcdABCD1234, result=1
The entered serial number seems incorrect.It's less than 10 characters.
str= abcdef##, result=0
str= abcdABCD1234$#, result=0
You don't need to change it. The compiler will implicitly convert your char to an int before passing it to isalnum. Functions like isalnum take int arguments because functions like fgetc return int values, which allows for special values like EOF to exist.
Update: As others have mentioned, be careful with negative values of your char. Your version of the C library might be implemented carefully so that negative values are handled without causing any run-time errors. For example, glibc (the GNU implementation of the standard C library) appears to handle negative numbers by adding 128 to the int argument.* However, you won't always be able to count on having isalnum (or any of the other <ctype.h> functions) quietly handle negative numbers, so getting in the habit of not checking would be a very bad idea.
* Technically, it's not adding 128 to the argument itself, but rather it appears to be using the argument as an index into an array, starting at index 128, such that passing in, say, -57 would result in an access to index 71 of the array. The result is the same, though, since array[-57+128] and (array+128)[-57] point to the same location.
Usually it is fine to pass a char value to a function that takes an int. It will be converted to the int with the same value. This isn't a bad practice.
However, there is a specific problem with isalnum and the other C functions for character classification and conversion. Here it is, from the ISO/IEC 9899:TC2 7.4/1 (emphasis mine):
In all cases the argument is an int, the value of which shall be
representable as an unsigned char or shall equal the value of the
macro EOF. If the argument has any other value, the behavior is
undefined.
So, if char is a signed type (this is implementation-dependent), and if you encounter a char with negative value, then it will be converted to an int with negative value before passing it to the function. Negative numbers are not representable as unsigned char. The numbers representable as unsigned char are 0 to UCHAR_MAX. So you have undefined behavior if you pass in any negative value other than whatever EOF happens to be.
For this reason, you should write your code like this in C:
if( !isalnum((unsigned char)*charPtr) )
or in C++ you might prefer:
if( !isalnum(static_cast<unsigned char>(*charPtr)) )
The point is worth learning because at first encounter it seems absurd: do not pass a char to the character functions.
Alternatively, in C++ there is a two-argument version of isalnum in the header <locale>. This function (and its friends) do take a char as input, so you don't have to worry about negative values. You will be astonished to learn that the second argument is a locale ;-)

I am trying to compile a simple string but it does not work... why?

My compiler is Code::Blocks. I am trying to eliminate vocals from a character sequence.
#include <iostream>
#include <cstring>
using namespace std;
char sir[256];
int i=0;
int main (){
cout<<"sir=";cin.getline(sir,256);
for (i=strlen(sir);i>0;i--){
if (strstr(sir[i],'aeiou')==0){
strcpy(sir+i,sir+i+1);
break;}}
cout<<"sir="<<sir<<"\n";
return 0;
}
I receive the following error:
error: call of overloaded 'strstr(char&, int)' is ambiguous
note: candidates are:
note: char* strstr(char*, cost char*) near match
But I think the problem is on strstr command...
'aeiou' is not a string literal in c/c++ use "aeiou".
In c/c++ string literal are represented inside " "(double quotes)
Read more here
So, apparently, the idea is to remove vowels. As others have said, use "aeiou" and not 'aeiou'. But you also need to use the right function to check whether you have a vowel. That's strchr(const char* s, int c), not strstr. strchr looks for an occurrence of c in the string that s points to, and returns a pointer to that occurrence, or, if it's not found, a pointer to the terminating nil character. So the test in the original code should be:
if (*strchr("aeiou", sir[i] != '\0')
Personally, I'd write this a bit more succinctly:
if (*strchr("aeiou", sir[i]))
As I wrote in the first comment, the expression
strstr(sir[i],'aeiou')
is wrong for two reasons: ' is for single characters, " is for strings, but the main reason is, that strstr finds the occurance of the whole thing, not of the characters separately.
Try this:
#include <iostream>
#include <cstring>
using namespace std;
char sir[256];
char sir2[256];
int i=0;
int main (){
cout<<"sir=";cin.getline(sir,256);
char* reader = sir;
char* writer = sir2;
while(*reader) {
if(*reader!='a' && *reader!='e' && *reader!='i' && *reader!='o' && *reader!='u') {
*writer = *reader;
++writer;
}
++reader;
}
*writer = '\0';
cout<<"sir="<<sir2<<"\n";
return 0;
}
ststr is defined by two function prototypes
const char* strstr( const char* str, const char* target );
char* strstr( char* str, const char* target );
your call is calling as
strstr(sir[i],'aeiou')
the first arg is a char type, not a char * type, so the compiler does know how to map that to const char * or char *
Also check your loop index as
i=strlen(sir)
will over index the char array and
i > 0
will NOT access the last character.

Comparison in string literal results in inspecified behavior - C++

I'm using eclipse.
I declared #define OUTPUT_FLAG "-o"
and then, I have the main : int main(int argc, char **argv)
after that I write:
for (int i = 1; i < argc; i+=2)
{
if(argv[i]==INPUT_FLAG)
{
cout<<"input flag\n";
input_file=argv[i+1];
}
}
and there I get the error on the subject. Can you help me here?
Thank you
You cannot compare strings with == in C++. You either have to use strcmp or convert them to std::strings and then use the == operator. That is, either:
if (!strcmp(argv[i], INPUT_FLAG))
or
if (std::string(argv[i]) == INPUT_FLAG)
You can't compare C strings (char *) using the == operator, as that operator only checks for pointer equality (rather than dereferencing the pointer and comparing each character one by one). Use strcmp(), or convert the string in argv[] to a C++ string type first.