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);
}
Related
I know this was asked a few times, but I still do not fully understand the issue.
I have an assigment where I need to save and sort the arguments.
int main(int argc, char* argv[])
{
int c;
char* s = malloc(argc * sizeof(char));
extern char *optarg;
extern int optind;
extern int optopt;
while ( (c = getopt(argc, argv, ":adh")) != -1) {
s[argc] = argv;
switch (c) {
case 'a': printf("a\n");
break;
case 'd': printf("d\n");
break;
case 'h': printf("h\n");
break;
}
}
return 0;
}
I know that it has something to do with me saving a pointer to an integer or not doing it.
char* argv[] is what? An array of pointers?
And s is only an array of chars?
char* argv[] is what? An array of pointers?
When such a declaration appears in a function prototype, as in your code, it is equivalent to char **argv. That's a pointer to a pointer to char. In this particular case, the pointed-to pointer is the first element of an array of pointers.
And s is only an array of
chars?
As you have declared an initialized it, s is a pointer to char, and in particular, it points to the first char in a dynamically allocated block. You can use the block via s as if it were an array of char, but it is not technically an array, and s definitely is not an array. Although related, pointers and arrays are very different things.
The compiler should have told you at least on which line the error occurs, but you did not pass that information on to us. Nevertheless, I think I can guess. This line ...
s[argc] = argv;
... is nonsense. Since s is a pointer to char, s[argc] designates one char (and in C, char is among the integer data types). On the other hand, argv is a pointer (to pointer to char). Although C permits pointers to be converted to integers, it is rarely useful to do so, and anyway, a conforming program must use a cast to perform such a conversion. Since you don't actually use s for anything, your best bet is probably to just remove that line.
For what it's worth, if you wanted to set s to point to one of the command line arguments, say the second, the syntax would be
s = argv[2];
(The zeroth element of argv is conventionally the name of the program; the arguments start at index 1.) But if you intend to do that then you don't need to malloc() any memory for s; whatever you do allocate for it is leaked when you assign a new value to it.
char *argv[] is a pointer to an array of strings. AKA char **argv
int argc is an integer count of the number of strings on the command line, including exe name.
Note also that the length of each string in argv[] has nothing to do with the value of argc. The strings can be as short as two characters, such as a\0 or as long as (or longer than) 1000 characters.
So the statement char* s = malloc(argc * sizeof(char)); will not do what you are thinking it will do.
First it is the form of an expression that will create some space for only one string, not argc of them.
Second, if your command line included 3 item, ( argc == 3 ) and one of the arguments was a string of length 9, say arguments, then your malloc statement would create space for 1 string, with only 3 characters. Not big enough to contain the string `arguments\0', not to mention the other two.
Use something like the following to determine the length of the longest of the argc strings:
int len = 0, lenKeep = 0;
for(i=0;i<argc;i++)
{
len = strlen(argv[i] > len)
if(len > lenKeep) lenKeep = len;
}
Now, lenKeep + 1 has been established as the length needed to contain the longest string (+ 1 for the NULL character, which strlen(...) does not include in its count.). This can be used, along with knowing the number of strings, argc, to allocate memory for each of them.
For example:
int main(int argc, char* argv[])
{
...
char **string = Create2DStr(argc, lenKeep + 1);//will create space
//sufficient to contain
//strings of your command line
...
}
Where Create2DStr(...) could be defined as:
char ** Create2DStr(ssize_t numStrings, ssize_t maxStrLen)
{
int i;
char **a = {0};
a = calloc(numStrings, sizeof(char *));
for(i=0;i<numStrings; i++)
{
a[i] = calloc(maxStrLen + 1, 1);
}
return a;
}
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
}
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
So I'm not very good with C but I'm designing a GLUT application that reads in a file that is not case sensitive. To make it easier I want to convert my strings to all lower case. I made a function makeLower that is modifying a variable that was passed in by reference.
I have a While Loop in the method makeLower that seems to get through part of the first iteration of the while loop and then the EXE crashes. Any tips would be great, thanks!
Output:
C:\Users\Mark\Documents\Visual Studio 2010\Projects\Project 1\Debug>"Project 1.e
xe" ez.txt
Line is #draw a diamond ring
Character is #
Then error "project 1.exe has stopped working"
Code:
void makeLower(char *input[]){
int i = 0;
printf("Line is %s\n", *input);
while(input[i] != "\0"){
printf("Character is %c\n", *input[i]);
if(*input[i] >= 'A' && *input[i] <= 'Z'){
*input[i] = tolower(*input[i]);
}
i++;
}
}
int main(int argc, char *argv[]) {
FILE *file = fopen(argv[1], "r");
char linebyline [50], *lineStr = linebyline;
char test;
glutInit(&argc, argv);
while(!feof(file) && file != NULL){
fgets(lineStr , 100, file);
makeLower(&lineStr);
printf("%s",lineStr);
//directFile();
}
fclose(file);
glutMainLoop();
}
I see more problems now, so I extend my comments to an answer:
You allocate an array of 50 characters, but tell fgets to get up to 100 characters, which might be fatal as fgets will overwrite memory not in the string.
When passing a C string to a function, you don't have to pass the address of the pointer to the string (&lineStr), the actual pointer or array is okay. This means you can change the makeLower function to void makeLower(char *input) or void makeLower(char input[]). Right now the argument to makeLower is declared as an array or char pointers, not a pointer to an array of char.
In the new makeLower I proposed above, you can access single characters either as an array (input[i]) or as a pointer plus offset (*(input + i). Like I said in my comment, the last version is what the compiler will probably create if you use the first. But the first is more readable so I suggest that.
Also in makeLower you make a comparison with "\0", which is a string and not a character. This is almost right actually: You should use input[i] != '\0'.
And finally this is how I would implement it:
void makeLower(char *input)
{
while (*input != '\0') /* "while (*input)" would also work */
{
*input = tolower(*input);
input++;
}
}
A few explanations about the function:
All char arrays can be converted to a char pointer, but not the other way around. Passing char pointer is the most common way to pass a string actually, as you can see from all standard functions that accepts strings (like strlen or strcpy.)
The expression *input dereferences (i.e. takes the value of what a pointer points to) the string. It is the same as *(input + 0) and so get the value of the first character in the string.
While the first character in the string is not '\0' (which technically is a normal zero) we will loop.
Get the first character of the string and pass it to the tolower function. This will work no matter what the character is, tolower will only turn upper case characters to lower case, all other characters will be returned as they already were.
The result of tolower copied over the first character. This works because the right hand side of an assignment must be executed before the assignment, so there will not be any error or problem.
Last we increase the pointer by one. This will make input point to the next character in the string. This works because input is a local variable, so operations on the pointer will not affect anything in the calling function.
This function can now be called like this:
char input[100];
fgets(input, sizeof(input), stdin);
printf("before: \"%s\"\n", input);
makeLower(input);
printf("after : \"%s\"\n", input);
Did you try while(*input[i] != "\0") instead of what you have ? For some reason you seem to pass to your function a pointer to pointer to char (*input[]) and &lineStr so it would make sense to dereference twice when you check for string terminator character "\0"....
Just a thought, hope it helps
I think the problem is that you don't know that the string is going to equal '\0' when you want it to. So you may be going out of bounds which is very likely that you don't know the length of the string.
As far as I understand things, it's fine to pass '\0' to tolower(). It's a valid unsigned char value, and tolower() simply returns the input character if it is not able to do any conversion.
Thus, the loop can be succinctly put as:
while(input[i] = tolower(input[i]))
++i;
This does one more call to tolower(), but it's shorter and (imo) quite clear. Just wanted to mention it as an alternative.
I have the passed argument argv[1] in my C program, and I want to convert that string into a character array. How may I do this?
int main(int argc, char* argv[])
{
char c [] = argv[1]; // This is what I want to do...
}
EDIT:
What I'm trying to do is get certain characters from argv[1] and check if they are numbers. So, ideally, I would do something like:
int a = argv[1][2]
But this just runs into another problem - how can I check the type of a variable in C?
First of all, it already is a character array, NULL-terminated. You can simply choose to make another pointer to it, by saying char *c = argv[1];, or you can copy the entire string (null-terminator and all) into another array using the strcpy(char *destination, char *source)function http://www.cplusplus.com/reference/clibrary/cstring/strcpy/ like this:
char c[BUFFER]; //This has to be big enough to hold length + 1
strcpy(c, argv[1]);
Either approach is valid.
You can treat argv[1] as though it were an array of char (i.e., you can subscript it as argv[1][i]). You can pass it as an argument to any function that doesn't try to modify it (e.g., printf, strtol, strchr, etc.). You cannot write to it, though, so if you need to modify the contents for any reason (either directly or through a function like strtok or strcpy), you'll have to create a local copy and manipulate that.
If you are using C89 or earlier, use this method:
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv)
{
char *c = NULL;
if (argc >= 2)
{
c = malloc(strlen(argv[1]) + 1);
strcpy(c, argv[1]);
}
/**
* Do stuff with c
*/
free(c);
return 0;
}
If you are using C99, you can use a VLA:
#include <string.h>
int main(int argc, char **argv)
{
if (argc < 2)
return 0;
size_t len = strlen(argv[1]);
char c[len+1];
strcpy(c, argv[1]);
/**
* do stuff with c
*/
return 0;
}
Just remember a few things:
The type of argv is char **, not char *[N]; similarly, the type of argv[i] is char *, not char [M]. In most circumstances it doesn't matter; you can use a subscript operator on a pointer as though it were an array (array subscripting is defined in terms of pointer arithmetic), but remember that pointers and arrays are not the same thing and are not always interchangeable;
The value of argv[argc] is always NULL;
Except when it is the operand of the sizeof or unary & operators or is a string literal being used as an initializer in a declaration, an expression of array type is converted ("decays") from "N-element array of T" to "pointer to T", and the value of the expression is the location of the first element;
C doesn't have a string data type as such; strings are represented as 0-terminated sequences of char. String literals such as "hello" are stored in such a way that they exist over the lifetime of the program, and you can access them via a pointer value; attempting to modify them results in undefined behavior (i.e., don't do that).
argv[1][2] is of type char, always (<pedantry>accessing it causes undefined behavior if there are less than two arguments or if the length of the second argument is less than two - so its questionable whether it has a type in those cases</pedantry>). The character itself may represent a number however, and to check that, use isdigit() from header <ctypes.h>
#include <ctypes.h>
...
if (argc > 1) {
int digits = 0;
for (int i = 0, len = strlen(argv[1]); i < len; ++i)
if (isdigit(argv[1][i]))
digits++;
printf("Digits in %s: %d\n", argv[1], digits);
}
Technically, argv[1] is already a character array. There really isn't such a thing as a "string" in standard C.
What do you want to do with it? Do you just want a copy of it? In that case, you'd need to malloc some space for a new character array and then use "strcpy" to copy from argv[1] into your character array.