felipX
felipX

Reputation: 21

**argv contain a lot of characters than expected

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

Answers (3)

Turn
Turn

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

Pablo
Pablo

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

ShadowRanger
ShadowRanger

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

Related Questions