Reputation: 29
how would you use only the scanf("%s",...)
not scanf("%[^,]s")
,to take white space strings as input and also print it as an output with spaces
example:
input: hi my name is..
output: hi my name is..
I believe i would have to use malloc and realloc to constant resize the array but I'm still not sure how to put it all together
Upvotes: 0
Views: 158
Reputation: 15052
"How to use only
scanf(“%s”)
to input print out strings with white space?"
Short answer:
There is no way to do that. At least not with one call to scanf()
on its own. The %s
conversion specifier reads strings only up to the first white space.
You only can use the [
format specifier to fetch strings with white space in it, when you want to explicitly use scanf()
for that task, although fgets()
would be probably more appropriate.
"to input print out strings"
scanf()
can't print out. It is input only.
Furthermore, The trailing s in scanf("%[^,]s")
is redundant and might even cause some trouble. %[
is not a suboperator of %s
. It is a conversion specifier on its own.
Upvotes: 1
Reputation: 84569
You can read words with scanf
using the "%s"
format specifier and concatenate them into a line using a loop (adding spaces where needed). You can use a fixed size buffer if you have some reasonable maximum number of characters you anticipate, or you can allocate and reallocate using malloc
and realloc
-- that is up to you. In either case the logic is the same, you have to track the number of characters available and how many you have used to know whether the next word will fit. The only difference being when dynamically allocating memory you have the option to reallocate additional storage and keep going, while in the case of the fixed buffer you simply have to handle the error of the line being too long to fit.
In either case when using scanf
with the "%s"
conversion specifier, you must also use the field-width modifier to ensure you don't read more characters than will fit into the storage for the word. For example if your word buffer is 128
characters, you must use "%127s"
to limit the number of characters you can store to 127
plus 1
for the nul-terminating character. Otherwise your use of scanf
is no safer than using gets
, see Why gets() is so dangerous it should never be used!
A simple example addressing your input and output could be:
#include <stdio.h>
#include <string.h>
#define MAXC 1024 /* max chars per-word and line */
int main (void) {
char buf[MAXC + 1] = "", word[MAXC]; /* line and word buffers */
size_t remain = MAXC; /* available space that remains */
fputs ("input : ", stdout); /* prompt for input */
for (;;) { /* loop continually */
char c; /* char following word */
int rtn = scanf ("%1023s%c", word, &c); /* read word & c, save return */
if (rtn > 0) { /* if word read */
size_t len = strlen(word); /* get word length */
if ((remain - len) > 0) { /* if space remains */
if (remain < MAXC) { /* if not 1st word */
strcat (buf, " "); /* add space between words */
remain--; /* decrement remains */
}
strcat (buf, word); /* add word to buf */
remain -= len; /* reduce remain by len */
}
else { /* handle line too long */
fputs ("error: line too long.\n", stderr);
return 1;
}
}
if (rtn == EOF || c == '\n') { /* if EOF or end of line */
printf ("output: %s\n", buf); /* output line */
break; /* break */
}
}
}
Example Use/Output
$ ./bin/scanf_words_buf
input : hi my name is..
output: hi my name is..
The key is to put your accountants hat on and ensure you do not write beyond the storage available.
Upvotes: 1
Reputation: 2188
If you know the maximum line length, you could use fgets
for that. But to be more flexible, then yes, malloc
and realloc
is the way to go. Here is an example, just remember to free
the string after use. You may also want to modify the error handling to your needs.
/* Return new string, or NULL on error*/
char *my_readline(FILE *f)
{
/* empty string must at least have place for zero termination */
char *str = malloc(1);
if (!str)
return NULL;
/* Length of string, not including zero termination */
size_t str_len = 0;
int ch;
while ( (ch=fgetc(f)) != EOF )
{
if (ch == '\n')
{
/* zero terminate string, and return */
str[str_len] = 0;
return str;
}
/*
increase buffer space for new character and zero termination
We must use a temporary pointer, so that we still have access to the old
pointer in case of error
*/
char *tmp = realloc(str, str_len + 2);
if (!tmp)
{
free(str);
return NULL;
}
str = tmp;
str[str_len] = ch;
str_len++;
}
/*
If we reach this line, there was en error reading the file, or the last
line was not terminated by a newline. In any case we signal an error
*/
free(str);
return NULL;
}
Some people prefer to increase the buffer in larger steps to gain some efficiency. But if this function is not your bottleneck, the extra complexity is not worth it.
Upvotes: 1