I'm looking to process a string passed via a command line argument with a for loop in C. I'm wondering if this would be the correct way.
main(int argc, char * argv[])
{
char * somestring;
somestring = malloc( (strlen(argv[1]) + 1) * sizeof(char) );
somestring = argv[1];
...
}
or would C allocate the appropriate memory if I did:
char * somestring;
somestring = argv[1];
If you want to copy an argument in your own allocated memory then you have to write
int main(int argc, char * argv[1])
{
char * somestring;
somestring = malloc( strlen( argv[1] ) + 1 );
strcpy( somestring, argv[1] );
...
}
otherwise statement
somestring = argv[1];
results in a memory leak.
Also do not forget to free the memory when it will not be needed any more.
Take into account that though this record
int main(int argc, char * argv[1])
is valid it is better to write
int main(int argc, char * argv[])
because your intention by specifying char * argv[1] is not clear
If you need to preserve a transient string then yes you need to allocate memory, copy it into the new buffer (via strcpy-like function) and latter deallocate that buffer.
But in this case, the command line arguments are not transient. They are available for the whole lifetime of the process. Therefore it is enough to just remember the pointer to them. So something like this would be enough:
const char* firstParameter = nullptr;
int main(int argc, char* argv[])
{
if (argc > 1) firstParameter = argv[1];
}
A good way would be allocating the memory for the pointer and use strcpy function to copy the contents.
For example:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char * argv[])
{
char *somestring;
if(argv[1] == NULL)
{
puts("Argument 1 is not specified.");
exit(1);
}
somestring = malloc( strlen(argv[1])+1 );
strcpy(somestring, argv[1]);
printf("%s\n",somestring);
return 0;
}
Also before allocating the memory for pointer, first check if argv[1] is not NULL.
Fisrt of all this is a wrong way of copying a string into another string.
You have done memory allocation correcly but your method of copying a string into another is wrong. You have allocated memory for string and collected its address into somestring. Now you are assigning argv[1] to it which is address of command line argument vector which is 2D array actually. So you should use strcpy() to copy string.
Or if you want just base address of string use char pointer instead and assign argv[1] to it. But it is of no use.
P.S. passing command line argument like you are doing is not recommended as all arguments are stored in argument vector argv which is 2D array. So if you are passing only one string then it is okay but if you are passing more than one strings then use char **argv instead.
Related
I am trying to read argv[1] starting from the second character until the end of the string in argv[1] (ignoring the first character, which is a flag). How can I do this?
I tried some library functions and other ways such as storing it in a variable such as
char *variable = strncpy(argv[1][1], strlen(argv[1]))
but it didn't work.
You are running up against two fundamental misconceptions regarding variables and pointers in C.
Let's start with:
char *variable = strncpy(argv[1][1], strlen(argv[1]))
The biggest problem (aside from the improper use of strncpy) is you attempt to assign the return of strncpy to char *variable where char *variable is a pointer-to-char that is uninitialized and points to no valid storage. Your attempt to assign the return fails because the proper prototype for strncpy is:
char *strncpy(char *dest, const char *src, size_t n);
(note: the dest parameter. The destination must have adequate storage to accept n characters. **further note:** if there is nonull byte` among the first n bytes of src, the array of bytes placed in dest will not be a null-terminated string.)
Now either by cleverness or happy-circumstance using the strlen of the complete argv[1] to allocate storage for dest and copying from argv[1] + 1 does provide space for the null byte.
Your next misconception is using argv[1][1] in strncpy. argv[1][1] has type char, not char*. (though your could use &argv[1][1] to use the address of argv[1][1] -- but not as you have it above.
argv[1] is a pointer of type char *. Being a pointer-to-char, if you want to skip one char, you want to read from the address pointer + 1 (or argv[1] + 1 in this case). Now it may make things easier to understand if you declare a separate pointer, e.g. char *p = argv[1]; and then use p + 1, but it is the same thing.
Putting that together, it looks like you intended:
#include <stdio.h>
#include <string.h>
int main (int argc, char **argv) {
if (argc < 2)
return 1;
size_t len = strlen (argv[1]);
char variable[len];
strcpy (variable, argv[1] + 1);
printf ("variable : %s\n", variable);
return 0;
}
Where with your example argument of +name, you would get:
Example Use/Output
$ ./bin/argv1plus1 +name
variable : name
For sake of completeness, if your compiler does not support use of a Variable Length Array (VLA) as used in char variable[len]; above, then your options are to declare variable as a fixed size array and validate that strlen(argv[1]) has no more characters than your fixed size, or, you simply allocate storage for variable dynamically by calling malloc (or calloc or realloc). A short example using malloc would be:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (int argc, char **argv) {
if (argc < 2)
return 1;
size_t len = strlen (argv[1]);
char *variable = malloc (len); /* allocate a block of memory len chars long */
if (variable == NULL) { /* always validate malloc succeeded */
perror ("malloc failure");
exit (EXIT_FAILURE);
}
strcpy (variable, argv[1] + 1);
printf ("variable : %s\n", variable);
free (variable); /* don't forget to free the memory you allocate */
return 0;
}
(same example & output)
Look things over and let me know if you have further questions.
I'm trying to make a program which makes a copy of the file you put in, only then with a reversed filename (eg. input.txt = txt.tupni).
I start my program with
int main(int argc, char **argv) {
When I use printf("%s",argv[1]) I can see the file name which has been put in. However, when I try to manipulate it I can't get it to work.
char name = argv[1] doesnt work,
neither does char name[] = argv[1] work
All I want is either a char array or a piece of malloc memory which has all of the characters.
argv is of type char **, so argv[1] is of type char *. So that's the type of the variable you want to assign this to.
char *name = argv[1];
You can't declare name as char [] and initialize it with a char *. Only a string literal may be used for initialization.
If you want to make a copy of the string rather than have another pointer to it, you can use strdup which allocates memory for the copied string and copies it over.
char *name = strdup(argv[1]);
Don't forget to free it when you're done with it.
You need to use a function like strcpy to accomplish this, as well as know the string length.
Here's what you do:
int len = strlen(argv[1])
char *buffer = (char*)malloc(len + 1);
if(buffer != NULL)
{
strcpy(buffer, argv[1]);
// copy the file etc.
}
I guess I do something stupid here, please help me understand what it is, i get a crash :
char *data="xyz";
int EEIndex=0;
int getEEPROMindex();
void updateEEPROMindex();
void getCmd(char *cmd);
void getcmdAtIndex(int index,char *cmd);
int main(int argc, const char * argv[]) {
getCmd(data);
printf("%s ",data );
return 0 ;
}
void getCmd(char *cmd)
{
getcmdAtIndex(EEIndex, cmd);
}
void getcmdAtIndex(int index,char *cmd)
{
char *EEPROM[]={"A","E","C","D"};
strcpy(cmd, EEPROM[index]);
EEIndex=index+1;
}
It's customary to make string literals read-only. That is:
char *data="xyz";
when your code tried to change the bytes x, y and z, the OS crashes it.
To make it writable, replace a pointer with an array; you should also specify the size of the array. The easiest method to do it is:
char data[] = "xyz"; // will hold a maximum of 3 bytes (size is implicit)
or
char data[20]; // will hold a maximum of 19 bytes plus an end-of-string byte
You can also use strdup:
char* data;
...
strdup(cmd, EEPROM[index]); // instead of strcpy
but this involves dynamic memory allocation, which I think you don't want to bother with.
You're strcpying into static memory space, i.e.
char *data="xyz";
That is, you created a string xyz that was stored in a reserved memory location at compile-time. You can't write into that memory location. You want to allocate new space, e.g. malloc.
char *data="xyz"; defines a char pointer to "xyz" which is located in read-only area so you can't write to this place. What point you still persist?
Change it to char data[] = "xyz" ensures this literal is copied to stack - so it's modifiable.
In addition, getcmdAtIndex function is not safe. What about out of index position?
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 );
I'm trying to read in two filenames and save them as a global variable in C.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char infilename;
char outfilename;
int main(int argc, const char* argv[]){
strcopy(infilename, argv[1]);
return 0;
}
However this does not work. Can someone help me with a really simple problem like this?
You are trying to copy a string (const char *) to a character (char). You need to either declare infilename as a string:
char *infilename;
infilename = malloc(...
or make a static array:
char infilename[NUM_OF_CHARS];
Read up on c strings here.
Also choose your language, if you are really using c++ you need to start using std::string
A better way to do it.
char infilename[50];
char outfilename[50];
int main(int argc, const char* argv[]){
if(argc == 3)
{
strcpy (infilename,argv[1]);
strcpy (outfilename,argv[2]);
}
else
{
//do something else
}
return 0;
}
You need array of char and not only char. A string in C is an array of char. And you must always verify (if(argc == 3) if the user entered the quantity of argument you want, because if it's not the case your applicatin can crash.
That's not going to work.
These:
char infilename;
char outfilename;
declare a variables that store a single char, not an entire string.
You either need to make those char arrays:
char infilename[MAX_PATH];
char outfilename[MAX_PATH];
or pointers that you plan to initialize with malloced memory. You have to pick which one you mean.
P.s. there's no function called strcopy, it's strcpy.
The main problem is that you made your global variables single characters not an array of characters which is needed for a string.
Assuming you don't want to change the contents of the string then the easiest thing is to simply set a global to point to the same string rather than copying it. Because the program will end when main returns there is no worry about the parameters argv going out of scope.
Note you would have to worry about this if you create a new thread and terminate the thread running main without terminating the program.
#include <stdio.h>
#include <stdlib.h>
static char* gInFilenamePtr;
static char* gOutFilenamePtr;
int main(int argc, const char* argv[])
{
if( argc > 2 )
{
gInFilenamePtr = argv[1];
gOutFilenamePtr = argv[2];
}
return 0;
}