For some reason my C program is refusing to convert elements of argv into ints, and I can't figure out why.
int main(int argc, char *argv[])
{
fprintf(stdout, "%s\n", argv[1]);
//Make conversions to int
int bufferquesize = (int)argv[1] - '0';
fprintf(stdout, "%d\n", bufferquesize);
}
And this is the output when running ./test 50:
50
-1076276207
I have tried removing the (int), throwing both a * and an & between (int) and argv[1] - the former gave me a 5 but not 50, but the latter gave me an output similar to the one above. Removing the - '0' operation doesn't help much. I also tried making a char first = argv[1] and using first for the conversion instead, and this weirdly enough gave me a 17 regardless of input.
I'm extremely confused. What is going on?
Try using atoi(argv[1]) ("ascii to int").
argv[1] is a char * not a char you can't convert a char * to an int. If you want to change the first character in argv[1] to an int you can do.
int i = (int)(argv[1][0] - '0');
I just wrote this
#include<stdio.h>
#include<stdlib.h>
int main(int argc, char **argv) {
printf("%s\n", argv[1]);
int i = (int)(argv[1][0] - '0');
printf("%d\n", i);
return 0;
}
and ran it like this
./testargv 1243
and got
1243
1
You are just trying to convert a char* to int, which of course doesn't make much sense. You probably need to do it like:
int bufferquesize = 0;
for (int i = 0; argv[1][i] != '\0'; ++i) {
bufferquesize *= 10; bufferquesize += argv[1][i] - '0';
}
This assumes, however, that your char* ends with '\0', which it should, but probably doesn't have to do.
(type) exists to cast types - to change the way a program looks a piece of memory. Specifically, it reads the byte encoding of the character '5' and transfers it to memory. A char* is an array of chars, and chars are one byte unsigned integers. argv[1] points to the first character. Check here for a quick explanation of pointers in C. So your "string" is represented in memory as:
['5']['0']
when you cast
int i = (int) *argv[1]
you're only casting the first element to an int, thus why you
The function you're looking for is either atoi() as mentioned by Scott Hunter, or strtol(), which I prefer because of its error detecting behaviour.
Related
I am new to C programming and trying to make a program to add up the digits from the input like this:
input = 12345 <= 5 digit
output = 15 <= add up digit
I try to convert the char index to int but it dosent seems to work! Can anyone help?
Here's my code:
#include <stdio.h>
#include <string.h>
int main(){
char nilai[5];
int j,length,nilai_asli=0,i;
printf("nilai: ");
scanf("%s",&nilai);
length = strlen(nilai);
for(i=0; i<length; i++){
int nilai1 = nilai[i];
printf("%d",nilai1);
}
}
Output:
nilai: 12345
4950515253
You have two problems with the code you show.
First lets talk about the problem you ask about... You display the encoded character value. All characters in C are encoded in one way or another. The most common encoding scheme is called ASCII where the digits are encoded with '0' starting at 48 up to '9' at 57.
Using this knowledge it should be quite easy to figure out a way to convert a digit character to the integer value of the digit: Subtract the character '0'. As in
int nilai1 = nilai[i] - '0'; // "Convert" digit character to its integer value
Now for the second problem: Strings in C are really called null-terminated byte strings. That null-terminated bit is quite important, and all strings functions (like strlen) will look for that to know when the string ends.
When you input five character for the scanf call, the scanf function will write the null-terminator on the sixth position in the five-element array. That is out of bounds and leads to undefined behavior.
You can solve this by either making the array longer, or by telling scanf not to write more characters into the array than it can actually fit:
scanf("%4s", nilai); // Read at most four characters
// which will fit with the terminator in a five-element array
First of all, your buffer isn't big enough. String input is null-terminated, so if you want to read in your output 12345 of 5 numbers, you need a buffer of at least 6 chars:
char nilai[6];
And if your input is bigger than 5 chars, then your buffer has to be bigger, too.
But the problem with adding up the digits is that you're not actually adding up anything. You're just assigning to int nilai1 over and over and discarding the result. Instead, put int nilai1 before the loop and increase it in the loop. Also, to convert from a char to the int it represents, subtract '0'. All in all this part should look like this:
int nilai1 = 0;
for (i = 0; i < length; i++) {
nilai1 += nilai[i] - '0';
}
printf("%d\n", nilai1);
For starters according to the C Standard the function main without parameters shall be declared like
int main( void )
This character array
char nilai[5];
can not contain a string with 5 digits. Declare the array with at least one more character to store the terminating zero of a string.
char nilai[6];
In the call of scanf
scanf("%s",&nilai);
remove the operator & before the name nilai. And such a call is unsafe. You could use for example the standard function fgets.
This call
length = strlen(nilai);
is redundant and moreover the variable length should be declared having the type size_t.
This loop
for(i=0; i<length; i++){
int nilai1 = nilai[i];
printf("%d",nilai1);
}
entirely does not make sense.
The program can look the following way
#include <stdio.h>
#include <ctype.h>
int main(void)
{
enum { N = 6 };
char nilai[N];
printf( "nilai: ");
fgets( nilai, sizeof( nilai ), stdin );
int nilai1 = 0;
for ( const char *p = nilai; *p != '\0'; ++p )
{
if ( isdigit( ( unsigned char ) *p ) ) nilai1 += *p - '0';
}
printf( "%d\n", nilai1 );
return 0;
}
Its output might look like
nilai: 12345
15
I have this code:
int main(int argc, char *argv[]) {
int num = *argv[1];
When I run the function in terminal with a parameter: for example, if I were to call ./main 17, I want num = 17. However, with this code, num = 49 (ASCII value for 1 because argv is an array of characters). How would I get it to read num = 17 as an int? Playing around with the code, I can get it to convert the parameter into an int, but it will still only read/convert the first value (1 instead of 17).
I'm new to C and the concept of pointers/pointers to arrays is still confusing to me. Shouldn't *argv[1] return the value of the second char in the array? Why does it read the first value of the second char in the array instead?
Thanks for help!
How do you convert parameters from char to int?
Can be done by a simple cast (promotion), but this isn't your case.
In your case *argv[] is array of pointer to char (You can use this for breaking down complex C declarations), meaning that argv[1] is the 2nd element in the array, i.e. the 2nd char* in the array, meaning *argv[1] is the first char in the 2nd char* in the array.
To show it more clearly, assume argv holds 2 string {"good", "day"}. argv[1] is "day" and *argv[1] is 'd' (note the difference in types - char vs char*!)
Now, you are left with the 1st char in your input string i.e. '1'. Its ascii is indeed 49 as, so in order to get it's "int" value you should use atoi like this:
int i = atoi("17");
BUT atoi gets const char * so providing it with 17 is a good idea while sending it a char would not. This means atoi should get argv[1] instead of *argv[1]
int main(int argc, char *argv[]) {
int num = atoi(argv[1]);
// not : int num = *argv[1]; --> simple promotion that would take the ascii value of '1' :(
// and not: int num = atoi(*argv[1]); --> argument is char
note: atoi is considered obsolete so you may want to use long int strtol(const char *str, char **endptr, int base) but for a simple example I preferred using atoi
Shouldn't *argv[1] return the value of the second char in the array?
Look at the signature:
int main(int argc, char *argv[])
Here, argv is an array ([]) of pointers (*) to char. So argv[1] is the second pointer in this array. It points to the first argument given at the command line. argv[0] is reserved for the name of the program itself. Although this can also be any string, the name of the program is put there by convention (shells do this).
If you just dereference a pointer, you get the value it points to, so *argv[1] will give you the first character of the first argument. You could write it as argv[1][0], they're equivalent. To get the second character of the first argument, you'd write argv[1][1].
An important thing to note here is that you can never pass an array to a function in C. The signature above shows an array type, but C automatically adjusts array types to pointer types in function declarations. This results in the following declaration:
int main(int argc, char **argv)
The indexing operator ([]) in C works in terms of pointer arithmetics: a[x] is equivalent to *(a+x). The identifier of an array is evaluated as a pointer to the first array element in most contexts (exceptions include the sizeof operator). Therefore indexing works the same, no matter whether a is an array or a pointer. That's why you can treat argv very similar to an array.
Addressing your "core" problem: You will always have strings in argv and you want numeric input, this means you have to convert a string to a number. There are already functions doing this. A very simple one is atoi(), you can use it like this:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
if (argc != 2)
{
// use program name in argv[0] for error message:
fprintf(stderr, "Usage: %s [number]\n", argv[0]);
return EXIT_FAILURE;
}
int i = atoi(argv[1]);
printf("Argument is %d.\n", i);
return EXIT_SUCCESS;
}
This will give you 0 if the argument couldn't be parsed as a number and some indeterminate value if it overflows your int. In cases where you have to make sure the argument is a valid integer, you could use strtol() instead (note it converts to long, not int, and it can handle different bases, so we have to pass 10 for decimal):
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
int main(int argc, char **argv)
{
if (argc != 2)
{
// use program name in argv[0] for error message:
fprintf(stderr, "Usage: %s [number]\n", argv[0]);
return EXIT_FAILURE;
}
errno = 0; // reset error number
char *endptr; // this will point to the first character not read by strtol
long i = strtol(argv[1], &endptr, 10);
if (errno == ERANGE)
{
fprintf(stderr, "This number is too small or too large.\n");
return EXIT_FAILURE;
}
else if (endptr == argv[1])
{
// no character was converted. This also catches the case of an empty argument
fprintf(stderr, "The argument was not a number.\n");
return EXIT_FAILURE;
}
else if (*endptr)
{
// endptr doesn't point to NUL, so there were characters not converted
fprintf(stderr, "Unexpected characters in number.\n");
return EXIT_FAILURE;
}
printf("You entered %ld.\n", i);
return EXIT_SUCCESS;
}
I'm new to C and the concept of pointers/pointers to arrays is still confusing to me.
In C strings are represented by null terminated ('\0') character arrays. Let's consider the following example:
char str[] = "Hello world!"
The characters would lie contiguous in memory and the usage of str would decay to a character pointer (char*) that points to the first element of the string. The address of (&) the first element taken by &str[0] would also point to that address:
| . | . | . | H | e | l | l | o | | W | o | r | l | d | ! | \0 | . | . | . |
^ ^
str null terminator
Shouldn't *argv[1] return the value of the second char in the array?
First of all in the argv is an array of character pointer char* argv[], so that it could be interpreted like an array of strings.
The first string argv[0] is the program name of the program itself and after that the arguments that are passed are coming:
argv[0] contains a pointer to the string: "program name"
argv[1] contains a pointer to the argument: "17"
If you dereference argv[1] with the use of * you get the first character at that address, here 1 which is 49 decimal in the Ascii code. Example:
p r ("program name")
^ ^
argv[0] (argv[0] + 1)
--------------------------------------------
1 7 ("17")
^ ^
argv[1] (argv[1] + 1)
How would I get it to read num = 17 as an int?
Check the number of passed arguments with argc which contains also the program name as one (read here more about argc and argv). If there are 2 you can use strtol() to convert argv[1] to the an integer. Use strtol() over atoi() because atoi() is considered to be deprecated because there is no error checking available. If atoi() fails it simply returns 0 as integer instead of strtol() that is setting the second argument and the global errno variable to a specific value.
The followig code will use the pointer that strtol() set the second argument to, to check for conversion errors. There are also overflow and underflow errors to check like it's described here on SO. Moreover you have to check if the returned long value would fit into an int variable if you want to store it into an int variable. But for simplicity I've left that out:
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char* argv[])
{
/* At least 1 argument passed? */
if (argc >= 2)
{
char* endptr;
long num = strtol(argv[1], &endptr, 10);
/* Were characters consumed? */
if (argv[1] != endptr)
{
printf("Entered number: %ld\n", num);
}
else
{
printf("Entered argument was not a number!\n");
}
}
else
{
printf("Usage: %s [number]!\n", argv[0]);
}
return 0;
}
Here's what you want to do:
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char *argv []) {
int num = atoi (argv[1]);
printf ("Here's what you gave me: %d", num);
return 0;
}
Here's the documentation for atoi ().
argv is an array of strings, so argv[x] points to a string. atoi () accepts an ASCII string as input and returns an int.
Bonus: This is still a bit unsafe. Try running this program without passing it a parameter and see what happens.
Also, you must take a look at the documentation for strtol (), which is a safe way of doing this.
my program is taking an argument which says how many prints that should be used.
example of arguments: prints 2.
I then want to loop through the value after prints, the number 2. and then print that many times. I tried like this:
for(i = 0; i < argv[2]; i++)
{
....
The problem is that argv is a char and i is an int. So when I run this loop, argv[2] aquire the value: 123123123 or something, instead of just 2. Is there any way around this or to compare the value in a char with an int. Thanks in advance
argv[2] is a char* not a char. argv[2] points to a string( array of null terminated characters ). When you pass an arguments to you program, the argument is in that form.
You will have to convert it, you can use atoi() ;
argv[2] is char*, is string in C language, if you want to change it to int, you must
convert it. Convert String to int.
Here is an example:
int atoi(char *str){//Just suit for int
int ans = 0,i=0;
while(str[i]){
ans = ans*10 + (str[i]-'0');
i++;
}
return ans;
}
You can call it like this atoi(argv[2]);
i am trying to pass an "unsigned char *" to another program by "execl" command by address
Here is the first program:
unsigned char myString;
...
unsigned char * myarr = malloc(80*sizeof(char));
...
//myarr is filled with some encrypted data
...
printf("\nresult:\t");
for(i=0;*(myarr+i)!=0x00;i++)
printf("%X ",*(myarr+i));
...
myString = malloc(80*sizeof(char));
myString = *myarr;
...
execl(".../Child", "Child", &myString, NULL);
On the second program;
unsigned char *myString;
...
myString = (unsigned char *)argv[1];
...
unsigned char * mynewarr = malloc(80*sizeof(char));
mynewarr = myString;
...
printf("\nresult:\t");
for(i=0;*(mynewarr+i)!=0x00;i++)
printf("%X ",*(mynewarr+i));
HERE THE RESULTS I GOT
first program
result: 20 DD 3E 99 2 94 7E C6 D DD 4 A 36 85 5B DA
second program
result: 20
why results are different? what am i doing wrong? Please help me.
i am using eclipse and i am coding in ubuntu 13.10.
I apologize. I completely misunderstood your question and jumped the gun.
The arguments to execl have to be null terminated strings and you are just passing myString incorrectly. That said there are caveats to what you are doing. You can't have embedded nulls in the encrypted data or they will be interpreted (prematurely) as the end of the string. As Zan Lynx notes, you can text encode your strings if they are binary. You also can't pass a string of unbounded length. There are system limits on how big the combined size of the argument list and environment can be and if exceeded execl will fail with E2BIG. (My initial misunderstanding was thinking you were trying to get around this limitation.)
Here is minimal working example of your programs (some liberties taken).
First program:
int main(int argc, char *argv[])
{
unsigned char *myString = malloc(80 * sizeof(char));
strcpy(myString, "filled with secret sauce");
printf("\nresult:\t");
for(int i = 0; *(myString + i) != '\0'; i++)
printf("%X ", *(myString + i));
printf("\n");
execl("./execpgm", "execpgm", myString, (char *) NULL);
perror("execl");
exit(1);
}
Second program:
int main(int argc, char *argv[])
{
unsigned char *mynewarr = malloc(80 * sizeof(unsigned char));
strncpy(mynewarr, argv[1], 80);
printf("\nresult:\t");
for (int i = 0; *(mynewarr + i) != '\0'; i++)
printf("%X ", *(mynewarr + i));
printf("\n");
exit(1);
}
Again, my apologies for answering without first understanding.
You can fix this by writing the complete string into the command line of the new process or by writing into a temporary file and passing that filename.
You said it was encrypted data. Which means that it probably contains zeros. Which means that it won't work to just write a string into the command line. Although you could write it in an escaped format like '\0' for null and then '\\' for backslash, or you could use BASE64 encoding.
But writing a pointer will not work because the memory space is wiped out when exec runs.
I am trying to figure out how to print the ascii value of a character in binary. Here is what I have done so far, but it does not work at all and I dont know why. Can someone of you C wizards help me??
#include <stdio.h>
int main(int argc, char** argv)
{
char myChar;
printf("Enter a character:\n");
scanf("%c", &myChar);
printf("Your character is %c\n", myChar);
printf("ASCII in BIN: %c\n", toBinary(myChar));
return 0;
}
char* toBinary(int decimalNumber)
{
char binaryValue[7] = "";
for (int i = sizeof(binaryValue); i >= 0; ++i)
{
int remainder = decimalNumber % 2;
decimalNumber = decimalNumber / 2;
binaryValue[i] = remainder;
}
return &binaryValue;
}
The %c format string will always interpret the corresponding printf argument as a character. In this case, its probably not what you want.
printf("ASCII in BIN: %d\n", myChar);
will print out the ascii code point of myChar just by telling printf to treat it as a number.
If you'd like to print out the string being returned by your toBinary function, you can do that with
printf("ASCII in BIN: %s\n", toBinary(myChar));
There's a good reference of the various % codes and what they mean here.
However, it's also worth noting that your toBinary function probably doesn't do what you want. This loop condition:
for (int i = sizeof(binaryValue); i >= 0; ++i)
will start at sizeof(int) and count up until it runs out of integers, then stop only because INT_MAX + 1 == INT_MIN. Because you're using i as an array index, this will almost certainly crash your program.
You also need to make sure to terminate the string you're generating with a '\0', as that is how subsequent calls to printf will recognize the string has ended.
And, as noted in other answers, your toBinary implementation is also returning a pointer to a memory address that will get automatically deleted as soon as toBinary returns.
You are returning address of local array.
This is both incorrect return type (char ** vs char *) and a bad thing to do at all.
printf("ASCII in BIN: %c\n", toBinary(myChar));
%c is to print a character.
And, there is no BOOL type in C, so you can change it in to a string, and pass the pointer to an array to printf("%s", pointer)