Accessing arguments with argv - c

This is something I've been testing by just printing out a bunch of stuff, but there's one case I can't quite figure out for some reason.
I need to pass an integer as an argument to a function to be used later, but when I print it back out again to make sure I stored it correctly, I get a random number. This is the relevant part of the code:
int num_bytes = argv[1];
....
printf("Max number of bytes: %d", num_bytes);
I only passed one argument to the function, which was an int. I also tried casting argv[1] as an int, but that didn't work either. I'm not sure if this is an issue with the printf or not. If it's just that, I don't mind. I just needed to know I stored the value as an int properly. I know that argv is an array of pointers to strings (C strings I think?) but I thought you could cast characters to ints.

char **argv is considered an array of characters (or a string). You'll need to convert the value inside of argv to an integer first.
You can do this through atoi:
int num_bytes = atoi(argv[1]);

argv is a pointer to an array of strings. You need to call atoi(argv[1]) to get the integer argument that you passed.

Related

When printf a string we are not using *. Why?

In c programming when we print a string. We are not using * . But when print a number using printf we are using *. So how it is understanding, i am printing a string or int. Is understanding using %s operator?
Attaching an example code
#include<stdio.h>
int main(int argc,char* argv){
char data[]="This is an example of pointer";
char *pointerstringdata =data;
printf("print the string data is >> %s\n",pointerstringdata); /* Here we are not using * why? case -1*/
int numberdata =100;
int *pointerintdata=&numberdata;
printf("print the int data is >> %d\n",*pointerintdata); /* Here we are using * why? case -2*/
return 0;
}
when we print a string. We are not using * . But when print a number using printf we are using *
Because the d conversion specifier expects an int, whereas the s conversion specifier expects a pointer (to a char and with this to the 1st element of a 0-terminated char array, which in fact is what C uses to mimik what commonly is called a "string").
The C language has no provision for treating a string as a value. You cannot pass a string to function. The pointer pointerstringdata is just a pointer to a char, so *pointerstringdata is one char, not a string. Passing *pointerstringdata will pass only one character, not a string.
To print strings, when %s is used, printf expects the argument to be a pointer. It uses this pointer to read from memory, and it reads and prints characters until it finds null characters.
In contrast, C does support treating numbers as values, so they can be passed to functions directly.
The %s format specifier is expecting a pointer.
If you pass *pointerstringdata the function will receive the first character in the array, which the function will try to dereference, and probably cause a crash.
in
char data[]="This is an example of pointer";
char *pointerstringdata =data;
printf("print the string data is >> %s\n",pointerstringdata); /* Here we are not using * why? case -1*/
if you want to print all the string you have to give its address, no *
if you want to print its first character you do `printf("%c", *pointerstringdata);
in
int numberdata =100;
int *pointerintdata=&numberdata;
printf("print the int data is >> %d\n",*pointerintdata); /* Here we are using * why? case -2*/
you do not want to print the address memorized in pointerintdata but the value same in that address, so you have to dereference
there is no difference with a string ... except that you want to write all the string
a pointer is a pointer, whatever it is a pointer to a char or a pointer to an int
Disclaimer: This is an explanation about how it appear to the developer, this is not how it is after compiling the code (especially because the optimizer might change it all).
C is a very low level language. You need to understand that a variable always contains a value of a few bytes.
C is also one of the languages that made it very convenient to access larger structures.
The content of the variable can be:
A value (e.g: as you mentioned a number)
A address in the RAM
A structure that uses more consecutive ram (and C makes it nice to use it as if it was more than that)
stuct (fixed length)
array with fixed length
There is no real concept of having a dynamic length variable as a value, therefor strings as well as arrays of dynamic length only have the address in the variable.
As stings are variable length, the convention in C is:
Have an address in the variable
Read the real data byte by byte starting at that address
Read data until the byte is 0 (NULL)
That is called a null-terminated string.
This way you can pass data of variable length to printf, and printf will find out the length by looking for the first byte that is 0.
Converting variables containing address to those containing value works like this:
var_with_value = *var_with_address
var_with_address = &var_with_value
"var_with_address" is called a pointer.
In conclusion: You need to pass strings as address not as value, and numbers as value not as address, and that is the difference why you have to use *
Because pointers hold reference to the object. * dereference this object. So if the pointer holds the reference to the char object when we dereference it we get this object. So dereference char pointer is just the single char not the address of the first char in the string.

C *argv[] and char array[][]

Im completely stuck on how to convert a output from one of my functions of char fileParameters[10][10] into the format of *argv[] to pass into another function that expects the same format of argv. The purpose of this is to pass a file input through the same parser that parses command line input.
I understand argv is a array of pointers but I'm getting confused as aren't all arrays a pointer to the first element?
So therefore fileParameters[10][10] is a pointer to a pointer and if take the address using & then I expected an array of pointers? I've tried everything and whatever I do results in a segfault.
Any nudges in the right direction would be appreciated.
I understand argv is a array of pointers but im getting confused as arent all arrays a pointer to the first element?
No. Arrays can be implicitly converted to a pointer to the first element, but they are not the same thing. You can easily tell by the fact that after char a[10];, sizeof a will give 10 rather than sizeof(char*). Your char[10][10] is an array of arrays, not an array of pointers.
You need to convert your array to an array of pointers:
char fileParameters[10][10];
// ...
char *fileParameterPtrs[10];
for (int i = 0; i != 10; i++)
fileParameterPtrs[i] = fileParameters[i];
and then you can pass fileParameterPtrs to the code that is expecting an array of pointers.
#Vasfed rightly adds that you mentioned "that expects the same format of argv". This doesn't mean just any array of pointers, it means an array of pointers that is terminated by NULL. Your original fileParameters cannot hold any NULL value, so you will need to add one yourself. If all 10 parameters are filled, this is as simple as changing fileParameterPtrs's length to 11 and adding one more assignment. If you have some other way of keeping track of how many fileParameters are used, adjust the code accordingly.

Char* array of chars, but int* not array of ints?

In C99 a string is typically initialized by using the char* data type since there is no primitive "string" data type. This effectively creates an array of chars by storing the address of the first char in the variable:
FILE* out = fopen("out.txt", "w");
char* s = argv[1];
fwrite(s, 12, 1, out);
fclose(out);
//successfully prints out 12 characters from argv[1] as a consecutive string.
How does the compiler know that char* s is a string and not just the address of a singular char? If I use int* it will only allow one int, not an array of them. Why the difference?
My main focus is understanding how pointers, referencing and de-referencing work, but the whole char* keeps messing with my head.
How does the compiler know that char* s is a string and not just the address of a singular char?
It doesn't. As far as "the compiler" is concerned, char* s is a pointer to char.
On the other hand, there are many library functions that assume that a char* points to an element of a null-terminated sequence of char (see for example strlen, strcmp etc.).
Note that fwrite does not make this assumption. It requires that you tell it how many bytes you want to write (and that this number doesn't take you beyond the bounds of the buffer pointed at by the first argument.)
If I use int* it will only allow one int, not an array of them. Why the difference?
That is incorrect. The C language does not have a special case for char*. An int* can also point to an element of an array of int. In fact, you could write a library that uses 0 or another sentinel value to indicate the end of a sequence of int, and use it much in the same was as char* are used by convention.
In your code
fwrite(s, 12, 1, out);
is equivalent to writing
write 12 elements of size 1 byte, location starting from address s to the file pointed by out.
Here. a char is of one byte exactly, so you get the desired output.
How does the compiler know that char* s is a string and not just the address of a singular char?
Well, it does not (and does not need to). You asked to (read from s and) write 12 bytes, so it will do that. If the memory is inaccessible, that's a programming mistake. fwrite() itself won't handle that.
Beware:
If s is not allocated memory to be accessed upto s[11] (technically), it will be undefined behaviour. It's upto the programmer to pass the valid values as argument.
In case of int, the size is 4 bytes (usually, on 32 bit system) and printing byte-by-byte won't give you the desired result.
In that case, you need to make use of fprintf() to print formatted output.
Compiler won't have any idea other than char* is an address of a character. We can make it read the characters following by incrementing the address of the first character. The case is similar to any pointer int*,long* etc., compiler just treat a pointer as something points to an address of its type.

Second command line argument a pointer to an array or an array of pointers?

K&R says the following about command line arguments:
The first [command line argument] conventionally called argc (for argument count) is the number of command-line arguments the program was invoked with; the second (argv, for argument vector) is a pointer to an array of character strings that contain the arguments, one per string.
As shown above, the second argument is described as a pointer to an array of strings. Just to clarify, is this saying that the second argument is a pointer to a single array that has multiple strings stored in it?
Wouldn't the syntax just be: main (int argc, char argv)
but the syntax is main (int argc, char *argv[])
The parameter syntax looks more like an array of pointers, where each element points to string constants or the first elements of strings in another array.
The loop construct to print what these pointers point at look more like what I just described:
for(i = 1; i < argc; i++)
printf("%s\n", argv[i])
Is the argument an array of pointers? If so, What do the elements actually point to? If it's not, what is the parameter?
In C, a "string" is actually char[].
Also, array (of any base type) in function signature is fully equivalent to pointer to the first element.
Each argument is a string, i.e. a char[], or char*.
An array of strings is char *[], or char**.
Therefore K&R are right, and the signature is what it should be.
BTW, argv[0] is typically the file name of the program and is not interesting unless you have multiple links to the same executable and are doing different things depending on the name by which your program was called. You can also use it for user feedback, such as usage instructions.

Pointer to one single char of a two dimensional array

As far as I know, an array like
int example[10]
Is nothing else than a pointer to the first element in this array.
char* argv[]
Is an array of pointers; so that should be pointers which point to other pointers.
I have following problem now:
int main(int argc, char* argv[])
{
double ptrarg2=argv[2][1];
printf("beginletter=%c\nbeginpos=%d\n",&ptrarg2, ptrarg2);
return 0;
}
I am starting the program with ./program test and expecting the output to be:
beginletter=c
beginpos=123213123
While 123213123 should be the adress where the c is actually stored.
I am actually getting:
beginletter=
beginpos=0
what am I doing wrong? Thank you in advance!
It looks like argv[0] is going to be "./program", argv[1] is going to be "test", and argv[2] is going to be undefined or NULL because you don't have three arguments. The value of argc should tell you how many items there are in argv[]. My guess in this case is that the answer will be 2, and therefore only the first two (argv[0] and argv[1]) are valid.
There are several other strange things going on here. ptrarg2 is declared as a double, not as a char; the behavior here would be to convert the character to its floating point numeric equivalent and store that. Perhaps you meant ptrarg2 to be a char?
Next up, the printf() doesn't correspond very well to its additional arguments. &ptrarg2 is a double *, but you're assigning it to a %c (character) field, not a %p (pointer) field. ptrarg2 is a double, but you're assigning it to a %d (decimal number) field, not a %lf (long float, aka double) field. printf will happily try and print out values even when your types don't match, but they will be wrong, and crashing is quite possible.
&ptrarg2 is the address of the local variable, which is not the address that you are expecting. Just use argv[1][0] and argv[1]. argv[1][0] will give you the first character of the first argument, and argv[1] will give you the pointer to the first argument.
#include <stdio.h>
int main(int argc, char* argv[])
{
printf("beginletter=%c\nbeginpos=%p\n",argv[1][0], argv[1]);
return 0;
}

Resources