I'm a beginner in C and have been trying to figure out what has gone wrong with my code code for the past hour or two. I have been following through K&Rs book and I keep looking through it but still do not understand my logic mistake.
while (*argv>0){
while (**argv>0){
printf("%c\n",**argv);
**argv++;
}
argv++;
}
Task:Print out all the arguments being fed to my program using argv.
To my understanding, argv is a pointer to an array that contains further pointers to arrays of character pointers. So, I said that while *argv>0 or while the first array still has elements, we should follow the pointers from the first array to the next array. Then we should print out all the elements in the next array.
Too many * in this line:
**argv++;
It should be like this:
*argv++;
Plus additional braces, because the ++ operation has higher priority:
(*argv)++;
And it will work.
I suggest you don't confuse yourself by using pointer dereferencing the way you do when the subscript notation ([]) allows you to do the same.
#include <stdio.h>
int main(int argc, char** argv)
{
int i;
for(i = 0; argv[i]; i++)
printf("%s\n", argv[i]);
return 0;
}
This will also print argv[0], which is the name/path of the program.
Now what does my code do? for(i = 0; argv[i]; i++) counts up i from 0 to the element when argv[i] resolves to false (i.e. 0 aka NULL), that is the last element of the argv array. And then for every element in the array it uses the %s format specifier of printf to print it. You could also pass the argv[i] as the first and only parameter to printf, but that is usually frowned upon as it opens the door for certain string formatting attacks.
argv is of type char *argv[] i.e. a pointer to an array of strings (char*'s). argv++ moves to the next string in the array.
Usually this function would be written as follows:
int main(int argc, char *argv[]){
int i;
for (i = 0; i < argc; i++){ //loop from 0 to argc (argument count)
printf("%s ", argv[i]);
}
return 0;
}
this will work::
while(argc--)//can't use *argv here, because *argv would be the address of the
// element which argv is pointing to, just by knowing the address u can't say whether it still has elements or not
{
while( **argv )
{
printf("%c", **argv);
(*argv)++; //by using **argv++, you are actually moving argv to next array, not to the next character of current array
}
argv++;
printf("\n");//move your \n to here, else you will end up printing every character in a new line
}
Related
I am currently working on a project where I am manipulating command line data, but I can't seem to get it work if I initialize the size of the array before.
char* len2[50]; // will store "1","2","3" from command line args
int size_arr = sizeof(len2) / sizeof(len2[0]);
printf("%d", size_arr);
this will input 50 when I am looking for it to input 3. How would I be able to find the size?
int size_arr = sizeof(len2) / sizeof(len2[0]);
sizeof(len2) asks for the total allocated size of len2 in bytes. This only works because C knows how many you allocated at compile time and turns it into a constant. It doesn't tell you which ones you've filled in. C does not keep track of that; you have to.
Because len2 is an array of pointers, you can mark the end with a null pointer. The term for this is a sentinel value. First, be sure to initialize the array to null.
// This will initialize the entire array to NULL
char* len2[50] = {NULL};
Now you can find how many elements are in the array by looking for the first null, or by hitting the allocated size.
size_t len2_size = sizeof(len2) / sizeof(len2[0]);
int size = 0;
for( ; len2[size] != NULL && size < len2_size; size++ );
printf("size: %d\n", size);
This is, incidentally, basically how C strings work. The end of the string is marked with a 0.
Alternatively, you can store the allocated size and number of elements in a struct and keep track, but that's another question.
Finally, if you're just reading command line arguments, use argc and argv. argc is the size of argv. argv[0] is the name of the program, and the rest are the command line arguments.
int main( const int argc, const char **argv) {
printf("%d arguments in argv\n", argc-1);
}
And argv is also terminated with a NULL pointer so it's easy to iterate through.
// Because argv[0] is the name of the program,
// start at 1 and read until you hit a null pointer.
for( int i = 1; argv[i] != NULL; i++ ) {
printf("argv[%d] = %s\n", i, argv[i]);
}
From the comments:
I guess what I'm trying to find is the number of items. Since there are 3 numbers I'll be getting from the command line, I want to be able to manipulate the array using 3 for a for or while loop for example.
According to the standard you have two versions of main function available (while the implementation defining further ones is legal):
int main();
int main(int, char**);
The second form gets the command line parameters passed to directly while the first form can be used if command line parameters are irrelevant.
Typically (but not necessarily) these two arguments get named argc and argv with argc containing the total number of command line arguments and argv a null-terminated array to the actual arguments. First one of is always the name that has been used to call the programme (which can differ in some cases from the actual executable name, e.g. if symbolic links are involved) which you might want to skip.
So a programme simply iterating over all arguments and printing them back to console might look like this:
int main(int argc, char* argv[])
{
for(++argv; *argv; ++argv)
{
printf("%s\n", *argv);
}
return 0;
}
with first ++argv skipping the programme name, *argv profiting from and testing for the null-terminator of the array and second ++argv being the normal loop post operation.
If you want to see the programme name as well you might just skip very first pointer increment:
for(;*argv;++argv)
Alternative variants might use an integer to count up to argc – just a matter of personal taste...
The pointers confuse me a lot. I have a function that takes as arguments argc (the number of argument that are strings + 1 that is the name of the code) and char* argv[], that, if I understood well, is an array of pointers. Now as result I need to print on each line the argument (string) and the reversed string. This means that if I pass as arguments hello world, I need to have:
hello olleh
world dlrow
I tried to implement a part of the code:
int main(int argc, char *argv[])
{
int i = 1;
int j;
while (i < argc)
{
while (argv[i][j] != 0) {
printf("%c", argv[i][j]);
j++;
}
i++;
}
return 0;
}
}
And now I'm literally lost. The inner loop doesn't work. I know that argv[i] pass through all my arguments strings, but I need obviously to enter in the strings (array of chars), to swap the pointers. Also I don't understand why the difference between argv[0] and *argv, because in theory argv[0] print the first element of the array that is a pointer, so an address, but instead of this it prints the first argument.
char* argv[] is a "array of pointers to a character" It's important to learn how to read types in C; because, those types will enable / thwart your ability to do stuff.
Types are read right to left. [] is a type of array, with an unspecified number of elemnts * is a pointer type, char is a base type. Combine these, and you now have "array of pointers to a character"
So to get something out of argv, you would first specify which element it is in the array. argv[0] would specify the first element. Let's look at what is returned. Since the array is not part of the result, the answer is "a pointer to a character"
char* line = argv[0];
would capture the pointer to a character, which is stored in argv[0].
In C a char* or a "pointer to a character" is the convention used for a string. C doesn't have a new type for "string"; rather it uses pointers to characters, where advancing the pointer eventually runs into the \0 character that signals the string's end.
int main(int argc, char* argv[]) {
int index = 0;
while (index <= argc) {
char* line = argv[index];
printf("%d, %s\n", index, line);
index++;
}
}
should dump the arguements passed to your program. From there, I imagine you can handle the rest.
Notice that I never converted the pointer to an array. While arrays can be used as pointers if you never specify the index of the array, in general pointers can't be used as arrays unless you rely on information that isn't in the type system (like you clearly grabbed the pointer from an array elsewhere).
Good luck!
---- Updated to address the question "How do I reverse them?" ----
Now that you have a simple char* (pointer to a character) how does one reverse a string?
Remember a string is a pointer to a character, where the next characters eventually end with a \0 character. First we will need to find the end of the string.
char* some_string = ...
char* position = some_string;
while (*position != 0) {
position++;
}
// end_of_string set, now to walk backwards
while (position != some_string) {
position--;
printf("%c", *end_of_string);
}
Let's say I type in $./file ABCDEFG into the command line and I want to store chose as individual chars in an array in my file. Based on my research it should look something like this but it is not giving me any output. The nextChar is calling a different function and can be ignored here.
int main(int argc, char * argv[]) {
int i = 0;
char findThisString[argc];
while(i < argc){
findThisString[i] = argv[i];
i++;
printf("%c \n", findThisString[i]);
}
while(c != EOF){
nextChar();
}
}
first: char findThisString[argc]; . don't do staff like that. when you declare an array the compiler will need to know the size of the array to find and save place for the array. use pointers, malloc and free. this an undefined behavior that only allowed in C99.
second: findThisString[i] = argv[i]; . you declared one of them as an array of strings (char*) and another as an array of chars (char).
third: did you declared nextChar somewhere?? use getchar instead.
forth: you write int i=0; while(...){...; i++; }. this is not an error but when you are writing this loop like this it is better to write
for(int i=0; i<argc; i++).
int main(int argc, char *argv[]) {
int i;
for(i = 0; i < argc; i++)
printf("arg %d: %s\n", i, argv[i]);
return 0;
}
Let's say I run the program in the command line as
./program mom cat dad
argv[1] is equal to "mom"
How do I get the array of characters in argv[1] to put them individually into a linked list ?
argv[1] is the array you are looking for. That means argv[1][0] is the first character, for instance.
In C, strings are always just char arrays, so argv[1] is already an array of characters. For example, you could do this:
for (int i = 0; i < strlen(argv[1]); i++) {
printf("Character %d = %c\n", i, argv[1][i]);
}
There are already plenty of resources on implementing linked lists in C (e.g: here), so I suggest you use this information to give it a go and come back if you're stuck with that. Good luck!
In addition to the answers already here, it's worth mentioning that you would generally copy strings into your list. You can use strdup (defined in string.h) to copy a string. For example:
listnode->value = strdup(argv[1]);
That means your list now owns a little slice of memory containing that copied string, so it's responsible for calling free on that pointer when the list node is freed.
However, I ought to mention that you are allowed to modify the arguments array. So if your list is only operating on the supplied arguments you don't necessarily need to copy them (unless you want to reallocate the memory), even if you plan to modify the string data.
If you are just storing a single character value in each list node, there's no such requirement. You would simply have a list structure like this:
struct node {
char value;
struct node *next;
};
Assume I have char **argv. How do I determine its size?
I have a string - an example would be: sleep 30 & that is held in argv. I would like to be able to access the last array in *argv. In this case, the last array contains &. How can I access it? strlen(argv) doesn't seem to work properly. sizeof() obviously wouldn't work properly because **argv is a pointer.
Note: I am not talking about **argv as an argument in main(), therefore, I do not have argc or any other indicator of how long the string is.
EDIT: Edited to work with a custom array of strings. A NULL pointer indicates the end of the array. Although this declares an array of 4 strings, this method could be used with a dynamically sized array.
#include <stdio.h>
int main()
{
char* custom[4] = { "sleep", "30", "&", NULL };
int last;
for (last = 0; custom[last + 1]; last++);
printf("%i - %s\n", last, custom[last]);
return 0;
}
// ./a.out
// > 2 - &
For this to work for you, you would have to edit your program to explicitly include an extra NULL string in your char** when you build it. Without that indicator, the address after the last string wouldn't necessarily be NULL, so you could include garbage in the count or cause a segmentation fault.
Passing in a count like argc is the most common usage - but you say you don't have that.
Then the usual way is to have the last element of argv to point to NULL to indicate it is the last array element.
int argc = 0;
while (*argv++) {
argc++;
}
You may need to use strtok to tokenize the arguments and work through them until you have the last one.
Referemce for strtok.
char *argv[] = {"abc","123","xya"};
//prints the last string
printf("%s",a[strlen(*a)-1]);
// if you are sure that the array of strings ends with NULL
char *temp = 0 ;
while(*argv){
temp = *argv;
(*argv)++;
}
//temp has the last string