Reputation: 21
First, I need to execute two commands with system(), for example, I receive an string and open this string with an text editor, like this:
$ ./myprogram string1
And the output should be a command like this:
$ vim string1
But, I cannot find a way to do this like this pseudo code:
system("vim %s",argv[1]); //Error:
test.c:23:3: error: too many arguments to function 'system'
system("vim %s",argv[1]);
Therefore, my solution is store the argv[1] on a char array that already initialized with four characters, like this:
char command[strlen(argv[1])+4];
command[0] = 'v'; command [1] = 'i'; command[2] = 'm'; command[3] = ' ';
And assign the argv[1] to my new char array:
for(int i = 0; i < strlen(argv[1]) ; i++)
command[i+4] = argv[1][i];
And finally:
system(command);
But, if the arguments given to my program has less than 3 characters, its works fine, but if not, some weird characters that I do not expect appear in the output, like this:
./myprogramg 1234
And the output is:
$ vim 12348�M�
How can I solve this bug and why does this happen?
The full code is:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (int argc,char **argv) {
char command[strlen(argv[1])+4];
command[0] = 'v'; command [1] = 'i'; command[2] = 'm'; command[3] = ' ';
for(int i = 0; i < strlen(argv[1]) ; i++)
command[i+4] = argv[1][i];
system(command);
return 0;
}
Upvotes: 1
Views: 669
Reputation: 7020
The reason you're running into problems is that you aren't terminating your command
string with NULL
. But you really want to use sprintf
(or even better to use snprintf
) for something like this. It works similarly to printf
but outputs to memory instead of stdout
and handles the terminating NULL
for you. E.g:
char cmd[80];
snprintf(cmd, 80, "vim %s", argv[1])
system(cmd);
As @VTT points out, this simplified code assumes that the value in argv[1]
will be less than 75 characters (80 minus 4 for "vim " minus 1 for the NULL character). One safer option would be to verify this assumption first and throw an error if it isn't the case. To be more flexible you could dynamically allocate the cmd
buffer:
char *cmd = "vim ";
char *buf = malloc(strlen(argv[1]) + strlen(cmd) + 1);
sprintf(buf, "%s%s", cmd, argv[1]);
system(buf);
free(buf);
Of course you should also check to be sure argc > 1.
Upvotes: 3
Reputation: 13570
I know that there are already good answers here, but I'd like to expand them a little bit.
I often see this kind of code
system("vim %s",argv[1]); //Error:
and beginners often wonder, why that is not working.
The reason for that is that "%s", some_string
is not a feature of the C
language, the sequence of characters %s
has no special meaning, in fact it is
as meaningful as the sequence mickey mouse
.
The reason why that works with printf
(and the other members of the
printf
-family) is because printf
was designed to replace sequences like
%s
with a value passed as an argument. It's printf
which make %s
special,
not the C language.
As you may have noticed, doing "hallo" + " world"
doesn't do string
concatenation. C doesn't have a native string type that behaves like C++'s
std::string
or Python's String
. In C a string is just a sequence of
characters that happen to have a byte with value of 0 at the end (also called
the '\0'
-terminating byte).
That's why you pass to printf
a format as the first argument. It tells
printf
that it should print character by character unless it finds a %
,
which tells printf
that the next character(s)1 is/are special and
must substitute them with the value passed as subsequent arguments to printf
.
The %x
are called conversion specifiers and the documentation of printf
will list all of them and how to use them.
Other functions like the scanf
family use a similar strategy, but that doesn't
mean that all functions in C that expect strings, will work the same way. In
fact the vast majority of C functions that expect strings, do not work in that
way.
man system
#include <stdlib.h> int system(const char *command);
Here you see that system
is a function that expects one argument only.
That's why your compiler complains with a line like this: system("vim %s",argv[1]);
.
That's where functions like sprintf
or snprintf
come in handy.
1If you take a look at the printf
documentation you will see that
the conversion specifier together with length modifiers can be longer than 1
character.
Upvotes: 0
Reputation: 155323
You need to NUL
terminate your C-style strings, and that includes allocating enough memory to hold the NUL
.
Your array is a byte short (must be char command[strlen(argv[1])+4+1];
to leave space for NUL
), and you should probably just use something like sprintf
to fill it in, e.g.:
sprintf(command, "vim %s", argv[1]);`
That's simpler than manual loops, and it also fills in the NUL
for you.
The garbage you see is caused by the search for the NUL
byte (which terminates the string) wandering off into unrelated (and undefined for that matter) memory that happens to occur after the buffer.
Upvotes: 4