C convert const char * to char - c

I searched quite a while to find the answer, but I could only find a solution for C++ that didn't seem to work for C. I'm trying to convert argument of const char * to char to use in my switch statement. I tried various things like strdup(), but was unsuccessful.
#include <stdio.h>
int main(int argc, const char *argv[]) {
char argOne = argv[1];
char argTwo = argv[2];
switch(argOne) {
case '1234' :
printf("1234!\n" );
break;
default :
printf("Invalid\n" );
}
}
While compilation:
warning: incompatible pointer to integer conversion initializing 'char' with an expression of type 'const char *' [-Wint-conversion]
char argOne = argv[1];
^ ~~~~~~~
warning: overflow converting case value to switch condition type (825373492 to 52) [-Wswitch]
case '1234' :
^

In your code,
Point 1:
char argOne = argv[1];
is very wrong. You cannot put a const char * (pointer) to a char variable.
Point 2:
case '1234'
also wrong. Here, the '1234' does not denote a string. It is a multibyte charcater, which is most probably something you don't want. Again, even you change that to something like "1234", still it would be incorrect, as it will not give you the intended value, and strings cannot be used for case statement values.
Solution: Instead of using the switch case here, you can try using strcmp() to compare the incoming string and chose accordingly.
Note: The recommended signature of main() is int main(int argc, char *argv[])

You're getting mixed up between char (character) and char * (string). Also you can not use strings as switch/case labels. Here is a fixed version of your code:
#include <stdio.h>
int main(int argc, const char *argv[]) {
const char *argOne = argv[1];
const char *argTwo = argv[2];
if (strcmp(argOne, "1234) == 0)
{
printf("1234!\n");
}
else
{
printf("Invalid\n");
}
return 0;
}

First of all the standard declaration of main looks like
int main(int argc, char *argv[])
^^^^^^
That is the second parameter does not have qualifier const.
Secondly argv[1] has type char *. There is no any sense to compare it with a character literal similar to '1234'. As for string literal "1234" when it may not be used in the case label.
What you want is the following
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
if ( argc > 2 )
{
char *argOne = argv[1];
char *argTwo = argv[2];
if ( strcmp( argOne, "1234" ) == 0 )
{
puts( "1234!" );
}
else
{
puts( "Invalid" );
}
}
}

You can't (really) "convert" a pointer to char to a single char. You can however extract one single character from a string.
For example, to get the first character of the first argument to your program, you can do e.g.
char first_char_of_first_arg = 0;
if (argv > 1)
first_char_of_first_arg = argv[1][0];

the code contains several problems
compiling with all warnings enabled would allow the compiler to
display those problems.
for gcc, at a minimum, use: '-Wall -Wextra -pedantic'
Note: warnings need to be fixed, as the compiler knows the C language better than you or I.
#include <stdio.h>
int main(int argc, const char *argv[])
{
//<< parameter argc not used
// and it should be used to assure that argv[1] and argv[2] actually exist
char argOne = argv[1];
//<< argv[1] is a pointer to a character string.
// argOne is a single char
// it should be: 'char argOne = argv[0][0];'
char argTwo = argv[2];
//<< argv[2] is a pointer to a character string.
// argTwo is a single character
// it should be: 'char argTwo = argv[1][0];'
//<< argTwo is not used
switch(argOne)
//<< a character can be treated as an int, but due care needs to be exercised
{
case '1234' :
//<< a case statement can only look at an 'int',
// not a pointer to a (in this case unterminated) string
// and argOne is a single char, not a pointer to a unterminated string
printf("1234!\n" );
break;
default :
printf("Invalid\n" );
//<< for human readability, use consistent indentation
// and never use tabs for indenting
//<< every case should be terminated with 'break;'
// unless the case is to fall through to the next case
// I.E. just because a syntax 'can' be used does not mean it 'should' be used
}
}

Related

Can't accept multiple command line arguments and assign to variable

I am learning C and I am not used to pointers and the way C handles strings. I am trying to create a program that accepts multiple command line arguments and assigns them to variables so that I can later use them. I can get the program to accept the first argument and assign it as a int. But when I try to accept the second argument I get a SEGMENTATION FAULT. I have tried testing by removing the second variable (service) and then assigning port to argv[2] and it doesn't work. It is something about accepting the second argument that the compiler does not like but I am not able to figure it out.
#include <stdio.h>
int main(int argc, char *argv[]) {
int port = atoi(argv[1]);
char service = argv[2];
return 0;
}
When you write char service = argv[2];, you are assigning a char pointer to a char. You know argv is a char pointer array, because you define it as char *argv[]. Fix by just adding char *service = argv[2];
So your rewritten code could look like this:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
if (argc < 3) {
printf("Requires more arguments");
return 1;
}
int port = atoi(argv[1]);
char *service = argv[2];
printf("%s", service); //From edit
return 0;
}
You may want to add a check for the value of argc (i.e. argc >= 3), since it will seg fault if there aren't three arguments.
Edit (response to comment):
To print the service, use:
printf("%s", service);
The %s specifies you will print a string of characters (char *) and you simply use service, because you need to specify the pointer.
Edit 2:
If you don't add #include <stdlib.h>, you will receive something along the lines of "warning: implicit declaration of 'atoi' is invalid in C99", which may also produce an error depending on your compiler settings.

Char (single letter) must be a pointer to correctly work?

I've searched and maybe this is not even an issue but while working with chars in C (I'm working with X-Code on Mac) I'm having problems dealing with them unless I used pointers
int main(int argc, const char * argv[]){
char myChar = "A";
print("%c\n",myChar);
print("%d\n",myChar);
print("%c\n",65);
print("%c\n",74);
return 0;
}
So, simple stuff, but here's the output:
>J
>74
>A
>J
As you see, when I print myChar using %c, it gives me the lettre J and not A, same thing when I use %d, gives me 74 (char code for J) and not 65.
I also have a warning message on my variable declaration :
Incompatible pointer to integer conversion initializing char with an expression of type char[2]"
Which is kind of weird.
Now when replacing my code with this one :
int main(int argc, const char * argv[]){
char *myChar = "A";
print("%c\n",*myChar);
print("%d\n",*myChar);
print("%c\n",65);
print("%c\n",74);
return 0;
}
The output is as expected :
>A
>65
>A
>J
Any idea on what this behavior is due? Did I miss something or do I fail to understand something?
In your code,
char myChar = "A";
is not correct. "A" is a string literal, which is not a fit for a char. You may want to write
char myChar = 'A';
instead.
Note: Enable compiler warnings and pay heed to them.

Syntax for passing a const char parameter to static char *argv[] in C

Okay, I'm trying to build a daemon (for a Debian machine) that will take the command line arguments it receives (via cron) and pass them to different script files.
The daemon's main() is
int main(int argc , char *argv[])
{
if(argc != 3)
{
exit(0);
}
daemonize(argv[1], argv[2]);
return 0;
}
And the function daemonize has this set up
int daemonize(const char *cmd1, const char *cmd2) {...}
The troubling part in daemonize is here:
if (strcmp(cmd1,"sample_script") == 0)
{
static char *argv[] = {"/etc/init.d/sample_script", ["%s",cmd2], NULL };
execv("/etc/init.d/sample_script",argv);
exit(127);
}
On the line
static char *argv[] = {"/etc/init.d/sample_script", ("%s",cmd2), NULL };
I am getting this error
initializer element is not constant (near initialization for ‘argv[1]’)
Obviously ("%s",cmd2) is wrong. Because using "start" works fine.
So, how do I get cmd2 to be correctly put into *argv[]? Or is it something else I am doing wrong?
You need to change
static char *argv[] = {"/etc/init.d/sample_script", ["%s",cmd2], NULL };
to
const char *argv[] = {"/etc/init.d/sample_script", cmd2, NULL };
You have to remove the static keyword. As per chapter 6.7.9, C11 standard,
All the expressions in an initializer for an object that has static or thread storage duration
shall be constant expressions or string literals.
Which says, in C language objects with static storage duration have to be initialized with constant expressions or with aggregate initializers containing constant expressions.
And, regarding constant expression, from chapter 6.6 of the same document
A constant expression can be evaluated during translation rather than runtime, and
accordingly may be used in any place that a constant may be.
So, in C, a variable (name), even if declared as const is never a constant expression.
EDIT:
To resolve the latest issue, you can try the following
change int daemonize(char *cmd1, char *cmd2) {..
use char * const argv[] = {"/etc/init.d/sample_script", cmd2, NULL };
and you can keep the rest of the code unchanged.
The function declaration for execv is
int execv(const char *path, char *const argv[]);
The proper interpretation of the second argument is a "const array of char *", which is different than an "array of const char *". In other words, execv reserves the right to change the contents of the strings that the array points to, but won't change any of the pointers in the array.
Which is to say that all of the strings in the argv array must be in writable memory. So to be perfectly technically correct, the code should make writable copies of all the strings, like so
if (strcmp(cmd1,"sample_script") == 0)
{
char arg0[] = "/etc/init.d/sample_script";
char *arg1 = strdup( cmd2 );
char *argv[] = { arg0, arg1, NULL };
execv( argv[0], argv );
exit(127);
}
you can't initialize a static with a variable/argument only known at runtime.
leave the static out:
char *argv[] = {"/etc/init.d/sample_script", ["%s",cmd2], NULL };

Check if string can be mutated in C

Say I have this function:
void f(char *s) {
s[0] = 'x';
}
This function will sometimes cause errors and sometimes not. For example,
char *s = "test";
f(s); // Error
char t[] = "test";
f(t); // Success
Inside function f, is it possible to determine whether or not s[0] = 'x'; will cause an error before doing it?
The responsibility is on the caller to comply with requirements of the function that the argument be changeable, not the reverse.
const char *s = "test"; // tell compiler s is immutable
f(s); // compilation error since f() requires a non-const argument
char t[] = "test";
f(t); // Success
The only way to stop the compiler from rejecting f(s) in the above is to either remove the const from the declaration of s, or to cast the const'ness away. Except in exceedingly rare circumstances, both are positive indicators of a problem.
Note: it is an anomaly in the language that s can be declared without the const qualifier. Get in the practice of using const where needed (e.g. when initialisating a pointer using a string literal). A lot of program bugs are eliminated that way.
Given the feedback I've received, It sounds like I should instead document whether or not the function requires its arguments to be mutable. For example:
#include <stdio.h>
#include <string.h>
char* f(char*);
void g(char*);
int main(int argc, char *argv[]) {
// s is immutable.
char *s = "test";
puts(f(s));
// t is mutable.
char t[] = "test";
g(t);
puts(t);
}
/*
* Returns a copy of the given string where the first character is replaced with 'x'.
* Parameter s must contain at least one character.
*/
char* f(char *s) {
char *t = strdup(s);
t[0] = 'x';
return t;
}
/*
* Replaces the first character of the given sting with 'x'.
* Parameter s must contain at least one character and be mutable.
*/
void g(char *s) {
s[0] = 'x';
}

C pointer and type conversion

Need some help with type conversaion with string pointers in C. I have a function that gets the the *argv from main loop to pass command-line parameters to it. Since the parameters are fixed, I am trying to give my own *argv style parameter to it, but gcc everytime gives a warning:
passing argument 2 of ‘DirectFBInit’ from incompatible pointer type
Code:
int main (int argc, char *argv[])
{
...
char *argx[2] = {"self","--dfb:no-vt"};
char *argxPtr = argx;
DFBCHECK (DirectFBInit (&fakeArgc, &argxPtr));
...
}
I should mention that the function is manipulation argv (hence argx).
Here are the definition of DirectFBInit:
DFBResult DirectFBInit(
int *argc, /* pointer to main()'s argc */
char *(*argv[]) /* pointer to main()'s argv */
);
The prog is running but I'm concerned about it.
The web-site for DirectFB probably has useful information.
Your code should probably be:
int main(int argc, char **argv)
{
...
char *argvxData[] = { "self", "--dfb:no-vt", 0 };
char **argvx = argvxData;
int argcx = 2;
DFBCHECK(DirectFBInit(&argcx, &argvx));
...
}
Note the added null pointer to match the null pointer at argv[argc] in the main() program. I've not read the manual to ensure that's required, but consistency is good. When I checked the first edition of my answer, it did not compile without warnings — in fact, it got your warning; I've fixed that with the argvxData array and argvx double pointer. The [] in the prototype is mostly a red-herring, but avoids accusations of being a three-star programmer. It is equivalent to char ***argv.
Or you could pass the arguments to main:
DFBCHECK(DirectFBInit(&argc, &argv));
If we call char * "string" then that simplifies it a bit. The function expects a pointer to an array of strings. You are passing in a string, and an incorrectly-initialized string at that (argx has type char*[] but you are assigning it to a variable of type char*).
&argxPtr should actually be &argx (an expression of type char*(*[]) as expected by the function), and you don't need argxPtr at all.
Something like this?
int myargc = 2;
const char *myargv[] = { "self", "--dfb:no-vt" };
DirectFBInit(&myargc, &myargv);
A simple way to verify is to compile with -g and run gdb. Once in gdb, run the program, and type ptype and you will see the difference. I have replaced the func name with foo()
foo(int *argc, char *(*argv[]))
{
}
int
main (int argc, char *argv[])
{
char *argx[2] = {"self","--dfb:no-vt"};
char *argxPtr = argx;
foo (&argc, &argxPtr);
}
(gdb) ptype foo
type = int (int *, char ***)
(gdb) ptype main
type = int (int, char **)
Hence the warning. Hope this helps.

Resources