C Arguments character Array - c

I would like to pass in arguments and output them as an array of characters or string. What is the easiest way to do this? Once I have them as an array of characters I want to be able to manipulate the array. I was able to pass them in and use a character pointer to traverse through the string but I'd like to use a char array. Is there any easy way to do this? Im pretty new to C, here is what I have so far.
if(argc != 3){
printf("incorrect number of arguments, program needs 3\n");
exit(1);
}
char s1[20];
s1 = (char*)argv[1];
char s2[20];
s2 = (char*)argv[2];
printf("String1 is %s\n", s1);
printf("String2 is %s\n", s2);
exit(0);

The strings pointed to by the argv array are modifiable, you can just modify the strings pointed to by the argv array, there is no need to copy them.
From the C standard:
(C99, 5.1.2.2.1p2) "The parameters argc and argv and the strings pointed to by the argv array shall be modifiable by the program, and retain their last-stored values between program startup and program termination."

You can simply print the values of argv directly:
printf("String1 is %s\n", argv[1]);
printf("String2 is %s\n", argv[2]);
If you need to modify the strings, here is how you would do that
char *newString1 = malloc(strlen(argv[1]) + 1 + charactersToAdd); // add one for null termination.
strcpy(newString1, argv[1]);
// manipulate newString1 however you choose
printf("String1 is %s\n", newString1);
free(newString1);

argv[1] and argv[2] are already pointers to character arrays, so you can use those directly. Moreover (see #ouah's post), the strings are already mutable, so you might not need anything beyond this at all.
If you really want to have a scope-local array, you need to use the C99 feature called "variable-length arrays", since the string lengths are only known at runtime:
#include <string.h>
int main(int argc, char * argv[])
{
char s1[strlen(argv[1]) + 1];
strncpy(s1, argv[1], sizeof s1);
// ...
}
Alternatively you could malloc enough space for a copy of the string (say char * s1 = malloc(strlen(argv[1]) + 1);), but then you wouldn't have a local array after all (and you might as well use the original strings, unless you really wanted to make a copy).

argv is already char* (actually an array of an array), however, they are noted const as in "do not modify" ;). What you want is actually making a copy of them so you can manipulate them freely:
char str[40];
strcpy (str,argv[1]);
Now you can manipulate str as you wish.

Related

Reverse order in array of char in C

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);
}

Not printing outside of if statement

I am making my own version of make. I allow for some arguments to be passed via command line.
I am working on it in chunks. I am setting the fileName right now
I have the following code
int main(int argc, char *argv[]) {
char *fileName = NULL;
char fileFlag[2];
strcpy(fileFlag, "-f");
printf("%s\n", fileFlag);
if (argc == 1) {
fileName = (char *) malloc(sizeof("Makefile"));
strcpy(fileName, "Makefile");
printf("One arg %s\n", fileName);
}
printf("\n%s", fileName);
return 0;
}
When it runs I get the following output.
-f
One arg Makefile
Shouldn't it print another line?
The first problem is
strcpy(fileFlag, "-f");
fileFlag is one element short of the required space, you need to have 3 element-array to store "-f" along with the terminating null. In this case, as per the strcpy() behaviour,
The strcpy function copies the string pointed to by s2 (including the terminating null
character) into the array pointed to by s1. [...]
So, including the null-character, the size of the source is 3, so is needed for the destination also. Otherwise, you'll be accessing out of bound memory which invokes undefined behavior.
That said,
please see this discussion on why not to cast the return value of malloc() and family in C..
Always check for the success of malloc() before using the returned pointer.

Free allocated string after strcat

According to the Allocate string (char*) in another function I have now code like this:
void someFunction(char** string, char** argv) {
*string = (char*)malloc(strlen(argv[2]) + 1);
strcpy(*string, argv[2]);
strcat(*string, ".txt"); //works fine without this
}
int main(int argc, char** argv) {
char *string;
char *string2;
someFunction(&string,argv);
printf("%s",string);
free(string); // freezes here due the strcat
}
After adding strcat to the code from the linked question, it freezes when I try to free my string.
You didn't allocate enough space for the resulting concatenated string; when you write past the end you invoke undefined behavior (in this case, likely heap corruption). Change the malloc to allocate strlen(argv[2]) + strlen(".txt") + 1 so you have a large enough buffer to hold the whole string.
Function someFunction has a bug. It does not allocate enough memory to append
".txt".
It could look the following way
void someFunction(char** string, char** argv) {
*string = (char*)malloc(strlen(argv[2]) + 1 + 4 );
strcpy(*string, argv[2]);
strcat(*string, ".txt"); //works fine without this
}
However in any case the design of the function is bad. It uses magic number 2 in the expression argv[2] . If the function deals with argv[2] then there is no sense to pass as an argument the whole array pf pointers argv. You should just pass argv[2]. Moreover it uses parameter string by reference but does not free the memory that the parameter can point to. So its interface is confusing.
You can use the function shown in my answer to the question
Safe way to concat two strings in C
The function could be called like
char *string = getConcatString( argv[2], ".txt" );
if ( string ) puts( string );
free( string );

How to memcpy() from argv[]?

I want to copy string from argv[0] but I don't know how to get the size of argv[0].
How to do this?
int main(int argc, char* argv[])
{
char str[20];
if(argc>0)
memcpy(str, argv[0], sizeof(argv[0]));
}
Since argv[0] is a string, use strlen.
#include <string.h>
size_t length = strlen (argv[0]) + 1;
memcpy (str, argv[0], length);
By the way, you could also use strcpy, which is more suitable for strings.
#include <string.h>
strcpy (str, argv[0]);
In every case, in order to make sure that your copy won't overflow, you should check whether the size of str is sufficient.
if (sizeof str >= length)
{
/* Do the copy. */
}
else
{
/* Report an error, or use dynamic allocation. */
}
You can use strdup() if your platform supports it. this makes your code more simple
int main(int argc, char* argv[])
{
char *str = NULL;
if(argc>0) {
str = strdup(argv[0]);
}
.......
// when the str became useless then free it
free(str);
........
}
You need to use strlen. If you were to use sizeof, then you would get the size of the char*.
To copy the string, you should use strcpy or just assign to another char*. Better yet, use strncpy in conjunction with a size (the size of the destination - 1) to prevent buffer overflows into str. The -1 is to account for the null-terminating character (\0). Don't forget about this character! The problem becomes if strlen returns 20. Then it will drop the \0. You should also read up on secure use of strcpy and you can read more about strncpy here.
OR, you can do this and it makes everything I said moot:
const char* arg1 = argv[0];
which would make strlen pointless in this case.
char* argv[] is an array of pointers (char*) so sizeof(argv[0]) is equal to sizeof(char*).
You could either use strlen:
memcpy(str, argv[0], strlen(argv[0]) + 1); // +1 because of '\0' at the end
or yet even better you could use strcpy:
strcpy(str, argv[0]);
but note that the length of the argv[0] might be greater than the size of your destination buffer (str) so you should either check the size of argv[0] before copying it.
You could also use strcnpy to copy only specified amount of characters, but in that case be very careful, because if there is no \0 in first 20 characters of argv[0], you'll have to terminate your string explicitly.
If your Cxx is >= C99
than you can do it in this way:
int main(int argc, char* argv[])
{
int len = (argc>0) ? strlen(argv[0]) : 0;
char str[len+1];
if (argc>0)
memcpy(str, argv[0], len+1);
}
I suggest to you to use pointer and allocate memory depending of the length of argv[0]:
int main(int argc, char* argv[])
{
char *str = NULL;
if(argc>0) {
int len = strlen(argv[0])
str = malloc((len+1) * sizeof(char))
memcpy(str, argv[0], (len+1));
}
.......
// when the str became useless then free it
free(str);
........
}
To summarise, because there's a lot of confusion and bad advice here:
The answer to your question in the narrowest sense is that you can find out the length of strings using strlen (sizeof returns the size of the data type in bytes, which for strings in char*, which (on a typical modern machine) will be either 4 (on 32-bit systems) or 8 (on 64-bit systems) regardless of the length of the string), but...
Make sure this is something you need to be doing in the first place. If you don't intend to change the string, there's no reason to copy it. If you do intend to change it, you only need to copy it if you also want to preserve the old value, because the argv strings are mutable (as per the standard).
If you either don't intend to change it or don't need the old value, but you still want another variable for some reason (readability, presumably), you should declare that variable as a pointer rather than an array and just assign to it:
char *str = argv[0];
If you're sure you do want to copy the string, you should not be using memcpy for this. You should be using strcpy, and you should be sure your new string is big enough to hold argv[0]. If you're using C99, you can do this easily:
char str[strlen(argv[0]) + 1];
strcpy(str, argv[0]);
If you're using an older standard, you will need to allocate memory dynamically:
char *str = malloc(strlen(argv[0]) + 1);
strcpy(str, argv[0]);
If you're on a POSIX system, you can shorten that by using strdup:
char *str = strdup(argv[0]);
If you're using malloc or strdup, remember that you need to free your memory manually when you're done with it.
(You don't need to check if argc > 0 in any case, by the way; the standard guarantees that argv[0] is either the program name or a zero-length string (that is, argv[0][0] is '\0').)
If you can't get away from using a fixed-length buffer, you can use strncpy if you remember to nul-terminate the resulting string manually and it's acceptable that your string is truncated if it is longer than the buffer:
char str[20];
strncpy(str, argv[0], 20); /* or 19, it doesn't matter. */
str[19] = '\0';
I think that's everything.
There is such a flood of bad advice here, I have no idea why, this question is not complicated rocket science, but rather beginner level programming.
You check that there is an argument in argv[0], but formally there will always be at least one argument passed to main. The check against argc > 0 is to be regarded as defensive programming, but extra error checks are never bad.
You need to check against buffer overflows before copying the contents of an unknown buffer.
#include <string.h>
#include <stdlib.h>
int main(int argc, char* argv[])
{
if(argc == 0)
{
// unexpected error
}
size_t len = strlen(argv[0]);
char* str = malloc(len * sizeof(char) + 1);
if(str == NULL)
{
// no memory, error
}
strcpy(str, argv[0], len);
...
free(str);
}
And that's it.
strdup is bad advice because it isn't C standard and therefore not portable. It is also a completely superfluous function.
strncpy is bad advice, it was never intended as a secure version of strcpy. It is an old legacy function for handling records in dinosaur unix systems. It is much more dangerous than strcpy because it is easy to forget the null termination. There is never a reason to use strncpy in a modern C program. For some reason unknown, there is a lot of programmers who have been brainwashed into using strncpy as a guard against buffer overflows. Don't do this, the correct way is to ensure that the buffer is large enough before using strcpy/memcpy.

In C, how can I convert a string to a character array?

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.

Resources