This piece of code is acting a bit strange to my taste. Please, anyone care to explain why? And how to force '\n' to be interpreted as a special char?
beco#raposa:~/tmp/user/foo/bar$ ./interpretastring.x "2nd\nstr"
1st
str
2nd\nstr
beco#raposa:~/tmp/user/foo/bar$ cat interpretastring.c
#include <stdio.h>
int main(int argc, char **argv)
{
char *s="1st\nstr";
printf("%s\n", s);
printf("%s\n", argv[1]);
return 0;
}
Bottom line, the intention is that the 2nd string to be printed in two lines, just like the first. This program is a simplification. The real program has problems reading from a file using fgets (not a S.O. argument to argv like here), but I think solving here will also solve there.
It seems the shell doesn't recognize and convert the "escape sequence". Use a shell software that supports \n escape sequence.
For all purposes, this just take care of \n and no other characters get special treatment.
This answer here does the job with lower complexity. It does not change "2 chars" into "one single special \n". It just changes <\><n> to "<space><newline>". That's fine. It would be better if there were a C Standard Library to interpret special chars in a string (as I know it has for RegExp for instance).
/* change '\\n' into ' \n' */
void changebarn(char *nt)
{
while(nt!=NULL)
if((nt=strchr(nt,'\\')))
if(*++nt=='n')
{
*nt='\n';
*(nt-1)=' ';
}
}
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.
I am trying to search a string in a text file,when the text file is like what given below :
"Naveen; Okies
PSG; Diploma
SREC; BECSE"
When output console ask for input string and when i type naveen it will result in printing Okies, when i typed PSG it will print Diploma. This works fine as I am using the below code :
fscanf(fp, "%[^;];%s\n", temp, Mean);
However below text file is not working,
"Naveen; Okies Is it working
PSG; Diploma Is it working
SREC; BECSE Is it working"
My code still gives me Okies as output for Naveen, where i need "Okies Is it working" as output.
So i changed my code to fscanf(fp, "%[^;];%[^\n]s", temp, Mean); where i am getting 'Okies Is it working' as output. But for searching string it's not searching next line. When i search PSG, I dont get any ouput.
Kindly help me to understand my issue.
Side-bar
Note that you should check the return value from fscanf().
You say you tried:
fscanf(fp, "%[^;];%[^\n]s", temp, Mean);
This is probably a confused format. The s at the end is looking for a literal s in the input, but it will never be found and you'll have no way of knowing that it is not found. The %[^\n] scan set conversion specification looks for a sequence of 'non-newlines'. It will only stop when the next character is a newline, or EOF. The s therefore is a literal s that will never be matched. But the return values from fscanf() is the number of successful conversions, which would probably be 2. You have no way of spotting whether that s was read. It should be removed from the format string.
Main answer
To address your main question, the %s format stops at the first blank. If you want to process the whole line, don't use %s. Use either POSIX getline() or standard C fgets() to read the line, and then analyze it.
You can analyze it with strtok(). I wouldn't do that in any library code because any library function that calls strtok() cannot be used from code that might also be using strtok(), nor can it call any function where that function, or one of the functions it calls directly or indirectly, uses strtok(). The strtok() function is poisonous — you can only use it in one function at a time. These comments do not apply to
strtok_r() or the analogous Microsoft-provided variant strtok_s() — which is similar to but different from the strtok_s() defined in optional Annex K of C11. The variants with a suffix are reentrant and do not poison the system like strtok() does.
I'd probably use strchr() in this context; you could also look at
strstr(),
strpbrk(),
strspn(),
strcpsn(). All of these are standard C functions, and have been since C89/C90.
I think Jonathan has explained it pretty well, however, I am adding a sample to show how to deal with your example for learning purposes. Bear in mind you might wanna change some functions as I used the deprecated (insecure) ones, probably this could be an exercise for you.
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
int main(int argc, char *argv[]) {
FILE *fp = NULL;
char szBuffer[1024] = { '\0' };
char szChoice[256] = { '\0' };
char szResult[256] = { '\0' };
if ((fp = fopen("test.txt", "r")) == NULL) {
printf("Error opening file\n");
return EXIT_FAILURE;
}
printf("Enter your choice: ");
scanf("%s", &szChoice);
while (fgets(szBuffer, sizeof(szBuffer), fp) != NULL) {
if (!strncmp(szBuffer, szChoice, strlen(szChoice))) {
char *pch = szBuffer;
pch += (strlen(szChoice) + 1);
printf("Result: %s", pch);
}
}
getchar();
return EXIT_SUCCESS;
}
I've wanted to learn more about the C standard library, so I decided to implement printf using only the putchar function. I'd barely started when something odd happened. All I'd done was write a loop to print a verbatim copy of the format string, and then I realized that all the escape sequences, (\n, \t, etc.) had already been parsed and "properly" output.
Here's the minimal code:
int my_printf(const char* s){
size_t i;
char c;
for (i = 0; (c = *(s + i)) != '\0'; ++i){
putchar(c);
}
return 0;
}
int main(void){
my_printf("Here\t1\n0\n");
return 0;
}
I was expecting a literal Here\t1\n0\n to be output, but I instead got:
Here 1
0
Any idea why this happening? My first thought was that the compiler I'm using, (gcc), was trying to help by pre-analyzing the format string, but that seems odd, since it would cause a lot of problems, since it would break any char array. So, does anyone know why this is happening? And is this behavior defined in the standard? Thank you for any help!
Edit: As mafso stated in their answer, the replacements are done at compile time, and it is standard. Section 5.1.1.2.1.5 of the standard has the actual text.
The escape sequences are replaced at compile time, not at runtime by printf. "\n" is a string starting with a literal new-line character (it’s the only way to put a literal new-line character into a string).
The only part of the string printf interprets are conversion specification, which always start with a % sign, (and the 0-terminator, of course), every other character is printed literally. You don’t need to do anything further.
./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'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