I have been trying for hours to create a program that outputs something like command[/home/nerdofcode/]: by running something like:
printf("Command[", system("pwd"),"]: ");...
But the problem I am receiving is that when I go to type input, it starts typing at command[... and then once I click enter, it finally outputs the system("pwd");...
Technical Info
I am using the system() function to execute a system command on Linux.
To use printf correctly for a null-terminated string you need to change the parameters:
printf("Command[%s]: ", string_with_result);
In order to get the string_with_result correctly, you need to study the way system() works in your environment. Its return value is implementation specific and therefor does not allow to answer with code which does what you want.
char * string_with_result; /* pointer to null-terminated sequence of char */
This is the declaration for the string result to be used in printf as proposed above.
In case you want to just get the result, but do not insist on using system() check this StackOverflow question and accepted answer:
'pwd' to get path to the current file
This Q/A might be the way on a "unix-ish" environment to actually use system(), it uses popen():
C: Run a System Command and Get Output?
printf does not work as a "concat" operation of comma separated strings. It rather has a format string with placeholders and the arguments for the placeholders.
So you could write:
char *s1 = "hello", *s2 = "world";
printf("%s %s", s1, s2);
But the following code will not concat the both strings; it will rather treat s1 as a format string (without placeholders) and will ignore the argument:
char *s1 = "hello", *s2 = "world";
printf(s1, s2);
Note further that int system(const char* cmd) does not return a string, which you could use in printf then, at all. So I'd recommend to write.
printf("Command[");
system("pwd");
printf("]: ");
This should work on console as long as system-command and your programsstdout` target the same output stream.
Related
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;
}
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.
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.
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.
./a.out "this is a string of words"
char *str = argv[1];
printf("%s\n", str);
How do I manipulate this so that it accounts for the spaces? Right now I am only able to print "this" because the white space prevents the rest of the argument from printing!
OK so I am going to assume it is my own system... something maybe with the shell or something.
I have tried all of these and none are working:
printf("%s\n", str);
printf("%s\n", argv[1]);
while (*p != '\0')
{
printf("%c", *p);
p++;
}
Assuming the completed code looks like:
#include <stdio.h>
int main(int argc, char **argv)
{
if (argc > 1)
{
char *str = argv[1]; // Not really necessary, but consistent with the question
printf("%s\n", str);
}
return 0;
}
Then there is very little chance on a Unix-like system with a standard shell of seeing what you claim to be seeing. Given that source code in e1.c and having compiled e1 (I use make, so I never get a program a.out), I can run:
$ ./e1 "This is a string of words"
This is a string of words
$
as would be expected. You could get just This if you used some obscure invocation:
$ ./e1 $(echo "This is a string of words")
This
$ ./e1 “This is a string of words”
“This
$
The second of these commands uses Unicode U+201C ('“', LEFT DOUBLE QUOTATION MARK) and U+201D ('”', RIGHT DOUBLE QUOTATION MARK) in place of U+0022 ('"', QUOTATION MARK). The shell does not recognize these as shell quotes, so you get to see the open quote and the word 'This' as the first argument to the command. This is, however, pretty improbable as an explanation of your problem.
So, either the code I deduced is not close enough to the full code you have (please provide the code for an SSCCE — Short, Self-Contained, Correct Example), or you've not told us the full story of how you are invoking the program. Which shell are you using? Which platform are you on?
(I tested on Mac OS X 10.9 Mavericks, with GCC 4.8.2, just for the record, but this is not going to be compiler sensitive. I'm using bash as provided with Mac OS X. I don't have any odd settings in bash that could mess up the interpretation of words, but if you weren't seeing the double quotes in front of This in the echoed output, … well, I'm at a loss to explain how you got the output you claim to get.)
i am learning now c and i come up with this example, where i can print a text using pointers.
#include <stdio.h>
main ()
{
char *quotes = "One good thing about music, when it hits you, you feel no pain. \"Bob Marley\"\n";
printf(quotes);
}
I get a warning from the compiler "format not a string literal and no format arguments" and when I execute the program it runs successfully.I read some other questions here that they had the same warning from the compiler but I didn't find an answer that fits me. I understood the reason why i get this message:
This warning is gcc's way of telling you that it cannot verify the format string argument to the printf style function (printf, fprintf... etc). This warning is generated when the compiler can't manually peek into the string and ensure that everything will go as you intend during runtime...
Case 3. Now this is somewhat your case. You are taking a string generated at runtime and trying to print it. The warning you are getting is the compiler warning you that there could be a format specifier in the string. Say for eg "bad%sdata". In this case, the runtime will try to access a non-existent argument to match the %s. Even worse, this could be a user trying to exploit your program (causing it to read data that is not safe to read).
(See the answer)
but what i have to add in my case to in order to have not warnings from the compiler?
Change it to printf("%s", quotes); which adds the specifier that quotes is a 'string', or array of char.
You need to tell printf what is it that you are printing. %s descriptor will tell printf that you are printing a string.
Format of printf = ("descriptor of what type of data you are printing",variable holding the data);
descriptor for strings is %s, for characters %c, for int %d
Change printf to:
printf("%s",quotes);
You have to specify format string - in simplest form:
char *quotes = "One good thing about music(...)\n";
printf("%s", quotes);
or, you can use format string to decorate output:
char *quotes = "One good thing about music(...)"; // no newline
printf("%s\n", quotes); // newline added here
or, if you don't want to mess with format strings:
char *quotes = "One good thing about music(...)"; // no newline
puts(quotes); // puts() adds newline
or
char *quotes = "One good thing about music(...)\n";
fputs(quotes,stdout);
This warning is gcc's way of telling you that it cannot verify the format string argument to the printf style function (printf, fprintf... etc). This warning is generated when the compiler can't manually peek into the string and ensure that everything will go as you intend during runtime. Lets look at a couple of examples.
So as other suggested explicitly use format specifier to tell the compiler...i.e.
printf("%s",quotes);
You are getting the warning because it is dangerous when the string you are printing contains '%'. In this line it makes no sense for percents but when you want to print this for instance:
int main ()
{
int percent = 10;
char *s = "%discount: %d\n";
printf(s, percent);
return 0;
}
your program will likely crash when printf encounters the second percent and it tries to pop a value from the stack from printf.
When you want to print a percent sign use: "%%discount:"
Try this:
#include <stdio.h>
main ()
{
char *quotes = "One good thing about music, when it hits you, you feel no pain. \"Bob Marley\"\n";
puts(quotes); //Either
printf("%s",quotes);//or
return 0;
}
Say we are working in C.
if I go ahead and do this:
char *word;
word = "Hello friends";
printf(word);
then XCode tells me that because I'm not using a string literal, that I might have something that is potentially insecure. Does that mean an opening for something to hack my program? If so, how could that happen?
Alternatively, if I do this:
char *word;
word = "Hello friends";
printf("%s", word);
Then XCode raises no flags and I'm fine. What exactly is the difference?
The first argument to printf is not the string you want to print. It's a format string. It can contain formatting instructions which results in the string that is printed once it is combined with further arguments.
Your first example is an uncontrolled format string vulnerability.
The issue is that in the first case if word contains formatting specs (%d, %f, %s, etc.) then printf() will assume those values are on the stack, but in fact they aren't, which could lead to a crash.
Use puts() or fputs() instead if you don't care about formatting.
I'm writing a program for a school project that is supposed to emulate the Unix shell, in a very basic form. It's basically parsing input, then doing a fork/exec. I need to be able to read arguments in the program (not as arguments passed to the program from the command line) individually. For example, I will prompt:
Please enter a command:
...and I need to be able to parse both...
ls
OR
ls -l
but the trouble is that there seems to be no easy way to do this. scanf() will pull each argument individually, but I see no way to place them into differing slots in a char* array. For example, if I do...
char * user_input[10];
for (int i=0; i<10; i++){
user_input[i] = (char *) malloc(100*sizeof(char));
}
for (int i=0; *(user_input[i]) != '#'; i++)
{
scanf("%s", user_input[index]);
index++;
}
...then user_input[0] will get "ls", then the loop will start over, then user_input[0] will get "-l".
gets and fgets just take the whole line. Obviously this problem can be logically solved by going through and plucking out each individual argument...but I'd like to avoid having to do that if there is an easy way that I'm missing. Is there?
Thanks!
If your use case is simple enough, you can do this with strtok:
char *strtok(char *str, const char *delim);
char *strtok_r(char *str, const char *delim, char **saveptr);
The strtok() function parses a string into a sequence of tokens. On the first call to strtok() the string to be parsed should be specified in str. In each subsequent call that should parse the same string, str should be NULL.
You can use strtok or strtok_r to split the string on spaces.
If you're doing something more complex, where some of the arguments could have (quoted) spaces in them, you're pretty much stuck parsing it yourself - though you could have a look at the source of a shell (e.g. bash) to see how it handles it.
kilanash helpfully reminds me of my obvious omission - GNU getopt. You'll still have to have parsed into separate arguments yourself first, though.
Forget that scanf exists for it rarely does what you want. Get the whole line at once and then write code to split it up. strtok - the second most favored answer to this question - is also problem ridden.
You can use strtok_r to break the string up on whitespace. Note that it is a destructive operation (modifies the input string).
Try to see if anything of this will help you:
ANSI C Command Line Option Parsing Library
The Argtable Homepage
Regards,
Tiho