The a modifier to scanf won't work if you are compiling with the -std=c99 flag; make sure you aren't using that.
If you have at least version 2.7 of glibc, you can and should use the m modifier in place of a.
Also, it is your responsibility to free the buffer.
Answer from Nietzche-jou on Stack OverflowThe a modifier to scanf won't work if you are compiling with the -std=c99 flag; make sure you aren't using that.
If you have at least version 2.7 of glibc, you can and should use the m modifier in place of a.
Also, it is your responsibility to free the buffer.
Do you have GNU extensions enabled? Standard C doesn't have a modifier at all.
Given a user input of unknown length (consisting of words with maximum length 100) is there a way to read it dynamically string by string?
Building your own function, instead of scanf would help to achieve this
Here, I've created a function
scanwhich would dynamically take in the string by increasing it's size over each iterationI've use the additional header files
string.handstdlib.hfor the following reasons :functions in stdlib.h (click to know more) library file are useful for dynamic allocation of memory.
functions in string.h (click to know more) library file are useful to handle strings.
Note: the input from the user stops when he enters the string
end.
#include <stdio.h> //the standard library file
#include <stdlib.h> //library file useful for dynamic allocation of memory
#include <string.h> //library file with functions useful to handle strings
//the function
char* scan(char *string)
{
int c; //as getchar() returns `int`
string = malloc(sizeof(char)); //allocating memory
string[0]='\0';
for(int i=0; i<100 && (c=getchar())!='\n' && c != EOF ; i++)
{
string = realloc(string, (i+2)*sizeof(char)); //reallocating memory
string[i] = (char) c; //type casting `int` to `char`
string[i+1] = '\0'; //inserting null character at the end
}
return string;
}
int main(void)
{
char *buf; //pointer to hold base address of string
while( strcmp((buf=scan(buf)),"end") ) //this loop will continue till you enter `end`
{
//do something with the string
free(buf); //don't forget to free the buf at the end of each iteration
}
free(buf); //freeing `buf` for last input i.e, `end`
}
let's just
//do something with the stringto see whether the above code works or not :)
I change the following while loop in main function :
while( strcmp((buf=scan(buf)),"end") )
{
//do something with the string
}
to
while( strcmp((buf=scan(buf)),"end") )
{
printf("you entered : %s\n",buf);
printf("size : %u\n",strlen(buf));
printf("reversing : %s\n",strrev(buf));
printf("\n-------------------\n");
free(buf);
}
and now,
input :
hall
of
fame
stay in it
end
output :
you entered : hall
size : 4
reversing : llah
-------------------
you entered : of
size : 2
reversing : fo
-------------------
you entered : fame
size : 4
reversing : emaf
-------------------
you entered : stay in it
size : 10
reversing : ti ni yats
-------------------
I found a solution!
while (scanf("%s%c", buf, &c))
{
//do something with the string
if (c == '\n') break;
}
Standard versions of scanf() do not allocate memory for any of the variables it reads into.
If you've been hoodwinked into using a non-standard extension in some version of scanf(), you've just had your first lesson in how to write portable code - do not use non-standard extensions. You can nuance that to say "Do not use extensions that are not available on all the platforms of interest to you", but realize that the set of platforms may change over time.
Must you absolutely use scanf ? Aren't std::string s; std::cin >> s; or getline( std::cin, s ); an option for you?
char* in;
while(scanf("%s", in) != EOF) {
This tells the computer to read from standard input into the char buffer that in points to.
Which does not exist, because in is not initialised to anything (let alone a valid buffer).
I would not use scanf only fgets.
You need to allocate memory dor the arr and for every line referenced by elements of arr
char** readScores(size_t *count) {
size_t lines = 0;
char** arr = NULL, **tmp;
char* in = malloc(MAXLINE), *result;
size_t len;
if(in)
{
do{
result = fgets(in, MAXLINE, stdin);
if(result)
{
len = strlen(in);
tmp = realloc(arr, sizeof(*tmp) * (lines + 1));
if(tmp)
{
arr = tmp;
len = strlen(in);
arr[lines] = malloc(len + (len == 0));
if(arr[lines])
{
if(len) memcpy(arr[lines], in, len - 1);
arr[lines++][len] = 0;
}
else
{
// error handling
}
}
else
{
// error handling
}
}
}while(result);
free(in);
}
*count = lines;
return arr;
}
Basic answer
There isn't an analog to the printf() format specifier * in scanf().
In The Practice of Programming, Kernighan and Pike recommend using snprintf() to create the format string:
size_t sz = 64;
char format[32];
snprintf(format, sizeof(format), "%%%zus", sz);
if (scanf(format, buffer) != 1) { …oops… }
Extra information
Upgrading the example to a complete function:
int read_name(FILE *fp, char *buffer, size_t bufsiz)
{
char format[16];
snprintf(format, sizeof(format), "%%%zus", bufsiz - 1);
return fscanf(fp, format, buffer);
}
This emphasizes that the size in the format specification is one less than the size of the buffer (it is the number of non-null characters that can be stored without counting the terminating null). Note that this is in contrast to fgets() where the size (an int, incidentally; not a size_t) is the size of the buffer, not one less. There are multiple ways of improving the function, but it shows the point. (You can replace the s in the format with [^\n] if that's what you want.)
Also, as Tim Čas noted in the comments, if you want (the rest of) a line of input, you're usually better off using fgets() to read the line, but remember that it includes the newline in its output (whereas %63[^\n] leaves the newline to be read by the next I/O operation). For more general scanning (for example, 2 or 3 strings), this technique may be better — especially if used with fgets() or getline() and then sscanf() to parse the input.
Also, the TR 24731-1 'safe' functions, implemented by Microsoft (more or less) and standardized in Annex K of ISO/IEC 9899-2011 (the C11 standard), require a length explicitly:
if (scanf_s("%[^\n]", buffer, sizeof(buffer)) != 1)
...oops...
This avoids buffer overflows, but probably generates an error if the input is too long. The size could/should be specified in the format string as before:
if (scanf_s("%63[^\n]", buffer, sizeof(buffer)) != 1)
...oops...
if (scanf_s(format, buffer, sizeof(buffer)) != 1)
...oops...
Note that the warning (from some compilers under some sets of flags) about 'non-constant format string' has to be ignored or suppressed for code using the generated format string.
There is indeed no variable width specifier in the scanf family of functions. Alternatives include creating the format string dynamically (though this seems a bit silly if the width is a compile-time constant) or simply accepting the magic number. One possibility is to use preprocessor macros for specifying both the buffer and format string width:
#define STR_VALUE(x) STR(x)
#define STR(x) #x
#define MAX_LEN 63
char buffer[MAX_LEN + 1];
fscanf(file, "%" STR_VALUE(MAX_LEN) "[^\n]", buffer);
It would be wise to check if the reallocation of the memory worked.
Also, this:
copy=malloc(strlen(output)+1); /* allocate memory for copy of output +1 for \0 char */
if(copy==NULL)
return NULL;
strcpy(copy, output); /* strcpy output to copy */
free(output); /* free memory taken by output */
return copy;
Why making a copy of output, freeing output, and then returning copy? Why not just returning output?
Here is a chunk of code I wrote a few years ago, which I find a bit simpler than your code:
char * read_string(void) {
char *big = NULL, *old_big;
char s[11] = {0};
int len = 0, old_len;
do {
old_len = len;
old_big = big;
scanf("%10[^\n]", s);
if (!(big = realloc(big, (len += strlen(s)) + 1))) {
free(old_big);
fprintf(stderr, "Out of memory!\n");
return NULL;
}
strcpy(big + old_len, s);
} while (len - old_len == 10);
return big;
}
This was just a learning example, which I have never really used. In practice, I'd suggest working with a larger s (char s[1025], %1024[^\n] in scanf, and len - old_len == 1024 in the condition of the do...while loop) to reduce the number of realloc calls which can be very slow if the user gets unlucky. This also answers your last question: char-by-char might get very slow and is in no way better than chunks.
Here are a few comments on your function:
Firstly,
read_lineseems a more accurate name, as you read up until the next \n.Reading 10 chars at a time is an odd. Unless that is part of the requirement I think you should allocate a bigger buffer and read as many chars as fit, extending the buffer each time round the loop by doubling its size (instead of adding 11).
As you have it, your
fgetscall overwrites the char after the end of the buffer with \0. You should pass the actual size of the buffer tofgets.Your fgets/strcat/strlen sequence is inefficient. You should be reading directly into the target buffer rather than reading and then copying. And the strcat call has to traverse the whole length of the accumulated string to concatenate the new part.
char *p = buf; size_t len = 0; while (fgets(p, size - len, stdin) != NULL) { len += strlen(p); if (buf[len-1] == '\n') { buf[len-1] = '\0'; break; } ... }Your reallocation call leaks memory if it fails to allocate - you need a temporary variable to hold the return value from realloc:
size *= 2; if ((p = realloc(buf, size)) == NULL) { break; // and then return an error if `p == NULL` or `ferror` } buf = p; p += len;Your loop exits when
fgetsreturns NULL, but you do not check for an error.
You must callferrorto be sure that an error did not occur.And your looping at the end to find the \n seems wasteful when you have already located the end of line/string in the main loop.
From the task statement you posted, copying the dynamic string is not required.
Note that reading character at a time is not necessarily a slower solution. As you are doing it (with all that the copying and string traversal), I would expect a well written character-at-a-time function to be faster. I encourage you to try both and compare the execution speed (using a very big test file as input).