redirecting shell command output to C program - c

I have the following program :
/* a.c */
#include <stdio.h>
int
main(int argc, char* argv[]){
size_t size=0;
char* lineptr;
while(getline(&lineptr, &size, stdin)){
fprintf(stderr, "line = %s\n", lineptr);
if(lineptr){
free(lineptr);
lineptr = NULL;
}
}
return 0;
}
I redirected the output of shell command "ls" to this program using the
following line :
ls | ./a.out
Expected output :
program should print the name of all files in the current directory
and terminate.
Actual output :
The program prints the name of all the files but does not terminate,
instead it loops infinitely and prints the last entry infinitely.
Thanks

GNU's getline function returns -1 upon end-of-file (or error). Use
while(-1 != getline(&lineptr, &size, stdin))
...and set lineptr to NULL before the first call to getline.
Also, you don't have to free the pointer in every iteration of the loop; you can reuse the previous pointer and free once at the end:
size_t size = 0;
char* lineptr = NULL;
while(-1 != getline(&lineptr, &size, stdin)){
fprintf(stderr, "line = %s", lineptr);
}
free(lineptr);
getline will use realloc internally as needed. Note that you have to make sure that lineptr and size are not changed between calls to getline for this to work (although you may change the string to which lineptr points).

Related

C: How do I properly free the memory when lineptr == NULL in getline

From the man page: https://linux.die.net/man/3/getline
ssize_t getline(char **lineptr, size_t *n, FILE *stream);
If *lineptr is NULL, then getline() will allocate a buffer for storing the line, which should be freed by the user program. (In this case, the value in *n is ignored.)
Since is a school project I CAN NOT USE MALLOC by teacher instructions, I don't care about the contents of the line (I just want to skip it easily). How can I free the memory? in which buffer it is allocated?
Note: Since it is a more theoretical question I do not add any code
Here's an example usage:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) {
char *line = NULL;
size_t line_size = 0;
while (1) {
ssize_t line_char_count = getline(&line, &line_size, stdin);
if (line_char_count == -1) break;
// Use your line string, e.g. printing it:
printf("Echo: %s", line);
}
free(line);
}
What you'll notice is that the string line is NULL to start. As the documentation explains, the first invocation of getline will make it allocate a buffer for you (as if it called malloc internally). Subsequent calls to getline in the loop will reuse the same buffer.
Once you send end-of-input with ctrl-d, the loop will exit, and free will be called to free the line.
I don't care about the contents of the line (I just want to skip it easily).
Instead of getline(), code could use a simply loop. No allocation worries.
int ch;
while ((ch = fgetc(stream)) != '\n' && ch != EOF) {
;
}

Write a program that reads strings and writes them to a file

Here's my task, below is most of the code done and finally my specific question
Write a program that reads strings and writes them to a file. The string must be dynamically allocated and the string can be of arbitrary length. When the string has been read it is written to the file. The length of the string must be written first then a colon (‘:’) and then the string. The program stops when user enters a single dot (‘.’) on the line.
For example:
User enters: This is a test
Program writes to file: 14:This is a test
Hint: fgets() writes a line feed at the end of the string if it fits in the string. Start with a small length, for example 16 characters, if you don’t see a line feed at the end then realloc the string to add more space and keep on adding new data to the string until you see a line feed at the end. Then you know that you have read the whole line. Then remove any ‘\r’ or ‘\n’ from the string and write the string length and the string to the file. Free the string before asking for a new string.
MY CODE:
#pragma warning(disable: 4996)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_NAME_SZ 256
int main()
{
char key[] = ".\n";
char* text;
text = (char*)malloc(MAX_NAME_SZ);
if (text == NULL)
{
perror("problem with allocating memory with malloc for *text");
return 1;
}
FILE* fp;
fp = fopen("EX13.txt", "w");
if (fp == NULL)
{
perror("EX13.txt not opened.\n");
return 1;
}
printf("Enter text or '.' to exit: ");
while (fgets(text, MAX_NAME_SZ, stdin) && strcmp(key, text))
{
fprintf(fp, "%ld: %s", strlen(text) - 1, text);
printf("Enter text or '.' to exit: ");
}
free((void*)text);
fclose(fp);
puts("Exit program");
return 0;
}
SPECIFIC QUESTION:
How can I make the program to allow arbitrarily long lines so there shouldn't be no limit at all for line length? Thanks
You could declare a pointer to char, read char by char and keep using reallocating the pointer until you get to the '\n':
int main()
{
char key[] = "."; //Excluded the \n since I'm not using fget
char* text;
FILE* fp;
fp = fopen("EX13.txt", "w");
if (fp == NULL)
{
perror("EX13.txt not opened.\n");
return 1;
}
printf("Enter text or '.' to exit: ");
int cont = 0;
while (1) //read all chars
{
if(!cont) //if it is the first, allocate space for 1
text = (char*) malloc(sizeof (char));
else //otherwise increase the space allocated by 1
text = (char*) realloc(text, (cont + 1) * sizeof(char));
scanf("%c", &text[cont]); //read a single char
if(text[cont] == '\n') //see if it is the end of line
{
text[cont] = 0; //if it is the end of line, then it is the end of the string
if(!strcmp(key, text)) //if the string is just a dot, end the loop
break;
fprintf(fp, "%ld: %s\n", cont, text);
printf("Enter text or '.' to exit: ");
cont = 0; //restarting the counter for the next input
free(text); // freeing after each iteration. you can optimize to maintain the space and only increase after getting to a bigger string than the previous you had so far
}
else //if it is not the end of the string, increase its size by 1
cont++;
}
free((void*)text);
fclose(fp);
puts("Exit program");
return 0;
}
Suggest using getline()
This seems to be a class room assignment, so I will not be writing the code for you.
Note: for the getline() function to be visible in linux, at the beginning of your code, you will need a statement similar to:
#define _GNU_SOURCE
or
#define _POSIX_C_SOURCE 200809L
getline(3)
NAME
getdelim, getline -- get a line from a stream
LIBRARY
Standard C Library (libc, -lc)
SYNOPSIS
#include <stdio.h>
ssize_t
getdelim(char ** restrict linep, size_t * restrict linecapp,
int delimiter, FILE * restrict stream);
ssize_t
getline(char ** restrict linep, size_t * restrict linecapp,
FILE * restrict stream);
DESCRIPTION
The getdelim() function reads a line from stream, delimited by the char-
acter delimiter. The getline() function is equivalent to getdelim() with
the newline character as the delimiter. The delimiter character is
included as part of the line, unless the end of the file is reached.
The caller may provide a pointer to a malloced buffer for the line in
*linep, and the capacity of that buffer in *linecapp. These functions
expand the buffer as needed, as if via realloc(). If linep points to a
NULL pointer, a new buffer will be allocated. In either case, *linep and
*linecapp will be updated accordingly.
RETURN VALUES
The getdelim() and getline() functions return the number of characters
written, excluding the terminating NUL character. The value -1 is
returned if an error occurs, or if end-of-file is reached.
EXAMPLES
The following code fragment reads lines from a file and writes them to
standard output. The fwrite() function is used in case the line contains
embedded NUL characters.
char *line = NULL;
size_t linecap = 0;
ssize_t linelen;
while ((linelen = getline(&line, &linecap, fp)) > 0)
fwrite(line, linelen, 1, stdout);
ERRORS
These functions may fail if:
[EINVAL] Either linep or linecapp is NULL.
[EOVERFLOW] No delimiter was found in the first SSIZE_MAX characters.
These functions may also fail due to any of the errors specified for
fgets() and malloc().
Note: you will need to pass to free() the line, when the code is through with it, to avoid a memory leak.
Note: to remove any trailing '\n' you can use:
line[ strcspn( line, "\n" ) ] = '\0';
Note: after removing any trailing '\n' you can use:
size_t length = strlen( line );
To get the length of the line in bytes.
Then print that length and the line using:
printf( "%zu:%s", length, line );

C: strtok delivers segmentation fault

I am trying to read a file line by line, and tokenize each line, which have strings separated by spaces and tabs. However, when I run my program, I get the a Segmentation Fault error when I try to print the token. I don't understand why this is happening, as I am using a buffer as the string to tokenize and checking if the token is null. Below is my code:
#include <stdio.h>
#include <stdlib.h>
#define MAX_LINE_LENGTH 70
int main(void)
{
FILE * testFile;
char buf[MAX_LINE_LENGTH];
testFile = fopen("test_file.txt", "r");
if (testFile == NULL)
{
printf("Cannot open test_file.txt.\n");
exit(0);
}
while (fgets(buf, sizeof(buf), testFile) != NULL) {
char *token = strtok(buf," \t");
while (token != NULL)
{
token = strtok(NULL, " \t");
if (token != NULL) {
printf("%s\n", token);
}
}
}
exit(1);
}
Below is the contents of test_file.txt:
String1 String2 String3
String4 String5 String6
String7 String8 String9
Two helpful tips -- (1) enable compiler warnings, e.g. minimum -Wall -Wextra -pedantic for gcc/clang or /W3 for VS (any other compiler will have similar options), and do not accept code until it compiles without warning; (2) #include <string.h> where strtok is defined.
In addition to the lack of validation pointed out by #dreamer, you must be using an implicit definition for strtok. You should receive a compiler warning along those lines. Don't ignore any warning, instead go fix it, it will generally tell you the exact line the problem code is on.
Next, don't hardcode filenames. It is just as simple to pass the filename as the first argument to your program (or read from stdin by default). Your second option is to take the filename as input to your program.
Putting those together, you could do something simple like:
#include <stdio.h>
#include <string.h>
#define MAX_LINE_LENGTH 70
#define DELIM " \t\n"
int main (int argc, char **argv) {
char buf[MAX_LINE_LENGTH];
/* use filename provided as 1st argument (stdin by default) */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
perror ("file open failed");
return 1;
}
while (fgets (buf, sizeof buf, fp))
for (char *p = strtok(buf, DELIM); p; p = strtok(NULL, DELIM))
puts (p);
if (fp != stdin) /* close file if not stdin */
fclose (fp);
return 0;
}
(note: you need to include '\n' as a delimiter character to prevent the additional '\n' from being part of the last token in each line)
Example Use/Output
$ ./bin/strtokfile test_file.txt
String1
String2
String3
String4
String5
String6
String7
String8
String9
Look things over and let me know if you have questions.
Looks like you are printing without checking for NULL for token pointer.
If you need to print all tokens you also need to print inside while loop after strtok system call with addition to non-NULL check for token.

C file compiling but not running [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Closed 6 years ago.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
This question does not appear to be about a specific programming problem, a software algorithm, or software tools primarily used by programmers. If you believe the question would be on-topic on another Stack Exchange site, you can leave a comment to explain where the question may be able to be answered.
Improve this question
So my program takes a file as input and parses out spaces. Tokens are saved into an array. I have a function to print out the contents of the array to test if the parser works. The code compiles with gcc -o filename filename.c . But when I run the program and give it a filepath, I get a pop up window indicating filename.exe has stopped working : A problem caused the program to stop working correctly. Windows will close the program and notify you if a solution is available.
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
char file_name[100];
char *token_array[256];
int main()
{
char ch;
FILE *fp;
int n=0;
char *str;
printf("Enter filepath\n");
gets(file_name);
fp = fopen(file_name,"r");
if( fp == NULL )
{
perror("Error opening the file.\n");
exit(EXIT_FAILURE);
}
int i = 0;
char *p;
while( ( ch = fgetc(fp) ) != EOF )
{
char *fgets(char *str, int n, FILE *stream);
p = strtok(str, " ");
i=0;
while(p!=NULL)
{
strcpy(token_array[i], p);
}
i++;
}
for(n=0;n<256;n++)
{
printf("%s", &token_array[n]);
}
return 0;
}
You can try this code instead. I changed your program so that it can read and tokenize the file.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *trim(char *s) {
int i = strlen(s) - 1;
if (s[i] == '\n')
s[i] = '\0';
return s;
}
#define BUFFER_SIZE 100
char *token_array[256];
int main( int argc, char** argv ){
const char *delimiter_characters = " ";
char *filename = malloc(BUFFER_SIZE);
int i = 0;
printf("Enter filepath\n");
fgets(filename, 100, stdin);
FILE *input_file = fopen( trim(filename), "r" );
char buffer[ BUFFER_SIZE ];
char *last_token;
if( input_file == NULL ){
fprintf( stderr, "Unable to open file %s\n", filename );
}else{
// Read each line into the buffer
while( fgets(buffer, BUFFER_SIZE, input_file) != NULL ){
// Write the line to stdout
//fputs( buffer, stdout );
// Gets each token as a string and prints it
last_token = strtok( buffer, delimiter_characters );
while( last_token != NULL ){
//printf( "%s\n", last_token );
token_array[i] = malloc(100);
strcpy(token_array[i], last_token);
i++;
last_token = strtok( NULL, delimiter_characters );
}
}
if( ferror(input_file) ){
perror( "The following error occurred" );
}
fclose( input_file );
}
int n;
for(n=0;token_array[n] != NULL && n<256;n++)
{
printf("%s", token_array[n]);
free(token_array[n]);
}
free(filename);
return 0;
}
data.txt
Hello Foo Bar
How are you?
Test
Debug/gnu
Enter filepath
data.txt
HelloFooBar
Howareyou?
Process finished with exit code 0
The contents of the array are
n[0] Hello
n[1] Foo
n[2] Bar
n[3] How
n[4] are
n[5] you?
You can see the contents of the array if you add debug info:
printf("n[%d] %s\n", n, token_array[n]);
This line does nothing:
char *fgets(char *str, int n, FILE *stream);
As written, that line is nothing but a declaration of a function, probably not what you want.
If you're going to use fgets(), use fgets() alone and don't mix it with fgetc():
char str[1024];
while ( fgets( str, sizeof( str ), fp )
{
.
.
.
fgets() returns NULL upon EOF or an error condition. And note that str is not a char *, it's a char array. An even better solution would be to use getline() because fgets() with a fixed-length buffer can only read entire lines that fit into the buffer. Longer lines will be split.
fgetc() returns int, not char. But you don't shouldn't use fgetc() when reading lines from a file with fgets(). Pick one and use that. But if you use fgetc(), you'll need to write code to put together each line as you read it character-by-character.
And what does token_array[i] point to? You declare token_array as an array of pointers:
char *token_array[256];
But you never allocate any memory for each pointer in the array to point to.
The easiest solution is to change
strcpy(token_array[i], p);
to
token_array[i] = strdup(p);
assuming your platform has strdup(), which is equivalent to a malloc() and strcpy() to the memory returned by malloc(), so you need to call free() on the string you get from strdup().
Your use of strtok() is wrong. See How does strtok() split the string into tokens in C? for examples of proper strtok() usage.
And since token_array is an array of char * pointers, this
printf("%s", &token_array[n]);
will take the address of the actual pointer itself, and not the string it's supposed to point to. It will then try to print out a "string" in the memory containing the pointer variable. That's won't work well. Since it's already a char *, all you need is this:
printf("%s", token_array[n]);

How to read a line from the console in C?

What is the simplest way to read a full line in a C console program
The text entered might have a variable length and we can't make any assumption about its content.
You need dynamic memory management, and use the fgets function to read your line. However, there seems to be no way to see how many characters it read. So you use fgetc:
char * getline(void) {
char * line = malloc(100), * linep = line;
size_t lenmax = 100, len = lenmax;
int c;
if(line == NULL)
return NULL;
for(;;) {
c = fgetc(stdin);
if(c == EOF)
break;
if(--len == 0) {
len = lenmax;
char * linen = realloc(linep, lenmax *= 2);
if(linen == NULL) {
free(linep);
return NULL;
}
line = linen + (line - linep);
linep = linen;
}
if((*line++ = c) == '\n')
break;
}
*line = '\0';
return linep;
}
Note: Never use gets ! It does not do bounds checking and can overflow your buffer
If you are using the GNU C library or another POSIX-compliant library, you can use getline() and pass stdin to it for the file stream.
A very simple but unsafe implementation to read line for static allocation:
char line[1024];
scanf("%[^\n]", line);
A safer implementation, without the possibility of buffer overflow, but with the possibility of not reading the whole line, is:
char line[1024];
scanf("%1023[^\n]", line);
Not the 'difference by one' between the length specified declaring the variable and the length specified in the format string. It is a historical artefact.
So, if you were looking for command arguments, take a look at Tim's answer.
If you just want to read a line from console:
#include <stdio.h>
int main()
{
char string [256];
printf ("Insert your full address: ");
gets (string);
printf ("Your address is: %s\n",string);
return 0;
}
Yes, it is not secure, you can do buffer overrun, it does not check for end of file, it does not support encodings and a lot of other stuff.
Actually I didn't even think whether it did ANY of this stuff.
I agree I kinda screwed up :)
But...when I see a question like "How to read a line from the console in C?", I assume a person needs something simple, like gets() and not 100 lines of code like above.
Actually, I think, if you try to write those 100 lines of code in reality, you would do many more mistakes, than you would have done had you chosen gets ;)
getline runnable example
getline was mentioned on this answer but here is an example.
It is POSIX 7, allocates memory for us, and reuses the allocated buffer on a loop nicely.
Pointer newbs, read this: Why is the first argument of getline a pointer to pointer "char**" instead of "char*"?
main.c
#define _XOPEN_SOURCE 700
#include <stdio.h>
#include <stdlib.h>
int main(void) {
char *line = NULL;
size_t len = 0;
ssize_t read = 0;
while (1) {
puts("enter a line");
read = getline(&line, &len, stdin);
if (read == -1)
break;
printf("line = %s", line);
printf("line length = %zu\n", read);
puts("");
}
free(line);
return 0;
}
Compile and run:
gcc -ggdb3 -O0 -std=c99 -Wall -Wextra -pedantic -o main.out main.c
./main.out
Outcome: this shows on therminal:
enter a line
Then if you type:
asdf
and press enter, this shows up:
line = asdf
line length = 5
followed by another:
enter a line
Or from a pipe to stdin:
printf 'asdf\nqwer\n' | ./main.out
gives:
enter a line
line = asdf
line length = 5
enter a line
line = qwer
line length = 5
enter a line
Tested on Ubuntu 20.04.
glibc implementation
No POSIX? Maybe you want to look at the glibc 2.23 implementation.
It resolves to getdelim, which is a simple POSIX superset of getline with an arbitrary line terminator.
It doubles the allocated memory whenever increase is needed, and looks thread-safe.
It requires some macro expansion, but you're unlikely to do much better.
You might need to use a character by character (getc()) loop to ensure you have no buffer overflows and don't truncate the input.
As suggested, you can use getchar() to read from the console until an end-of-line or an EOF is returned, building your own buffer. Growing buffer dynamically can occur if you are unable to set a reasonable maximum line size.
You can use also use fgets as a safe way to obtain a line as a C null-terminated string:
#include <stdio.h>
char line[1024]; /* Generously large value for most situations */
char *eof;
line[0] = '\0'; /* Ensure empty line if no input delivered */
line[sizeof(line)-1] = ~'\0'; /* Ensure no false-null at end of buffer */
eof = fgets(line, sizeof(line), stdin);
If you have exhausted the console input or if the operation failed for some reason, eof == NULL is returned and the line buffer might be unchanged (which is why setting the first char to '\0' is handy).
fgets will not overfill line[] and it will ensure that there is a null after the last-accepted character on a successful return.
If end-of-line was reached, the character preceding the terminating '\0' will be a '\n'.
If there is no terminating '\n' before the ending '\0' it may be that there is more data or that the next request will report end-of-file. You'll have to do another fgets to determine which is which. (In this regard, looping with getchar() is easier.)
In the (updated) example code above, if line[sizeof(line)-1] == '\0' after successful fgets, you know that the buffer was filled completely. If that position is proceeded by a '\n' you know you were lucky. Otherwise, there is either more data or an end-of-file up ahead in stdin. (When the buffer is not filled completely, you could still be at an end-of-file and there also might not be a '\n' at the end of the current line. Since you have to scan the string to find and/or eliminate any '\n' before the end of the string (the first '\0' in the buffer), I am inclined to prefer using getchar() in the first place.)
Do what you need to do to deal with there still being more line than the amount you read as the first chunk. The examples of dynamically-growing a buffer can be made to work with either getchar or fgets. There are some tricky edge cases to watch out for (like remembering to have the next input start storing at the position of the '\0' that ended the previous input before the buffer was extended).
How to read a line from the console in C?
Building your own function, is one of the ways that would help you to achieve reading a line from console
I'm using dynamic memory allocation to allocate the required amount of memory required
When we are about to exhaust the allocated memory, we try to double the size of memory
And here I'm using a loop to scan each character of the string one by one using the getchar() function until the user enters '\n' or EOF character
finally we remove any additionally allocated memory before returning the line
//the function to read lines of variable length
char* scan_line(char *line)
{
int ch; // as getchar() returns `int`
long capacity = 0; // capacity of the buffer
long length = 0; // maintains the length of the string
char *temp = NULL; // use additional pointer to perform allocations in order to avoid memory leaks
while ( ((ch = getchar()) != '\n') && (ch != EOF) )
{
if((length + 1) >= capacity)
{
// resetting capacity
if (capacity == 0)
capacity = 2; // some initial fixed length
else
capacity *= 2; // double the size
// try reallocating the memory
if( (temp = realloc(line, capacity * sizeof(char))) == NULL ) //allocating memory
{
printf("ERROR: unsuccessful allocation");
// return line; or you can exit
exit(1);
}
line = temp;
}
line[length] = (char) ch; //type casting `int` to `char`
length++;
}
line[length + 1] = '\0'; //inserting null character at the end
// remove additionally allocated memory
if( (temp = realloc(line, (length + 1) * sizeof(char))) == NULL )
{
printf("ERROR: unsuccessful allocation");
// return line; or you can exit
exit(1);
}
line = temp;
return line;
}
Now you could read a full line this way :
char *line = NULL;
line = scan_line(line);
Here's an example program using the scan_line() function :
#include <stdio.h>
#include <stdlib.h> //for dynamic allocation functions
char* scan_line(char *line)
{
..........
}
int main(void)
{
char *a = NULL;
a = scan_line(a); //function call to scan the line
printf("%s\n",a); //printing the scanned line
free(a); //don't forget to free the malloc'd pointer
}
sample input :
Twinkle Twinkle little star.... in the sky!
sample output :
Twinkle Twinkle little star.... in the sky!
I came across the same problem some time ago, this was my solutuion, hope it helps.
/*
* Initial size of the read buffer
*/
#define DEFAULT_BUFFER 1024
/*
* Standard boolean type definition
*/
typedef enum{ false = 0, true = 1 }bool;
/*
* Flags errors in pointer returning functions
*/
bool has_err = false;
/*
* Reads the next line of text from file and returns it.
* The line must be free()d afterwards.
*
* This function will segfault on binary data.
*/
char *readLine(FILE *file){
char *buffer = NULL;
char *tmp_buf = NULL;
bool line_read = false;
int iteration = 0;
int offset = 0;
if(file == NULL){
fprintf(stderr, "readLine: NULL file pointer passed!\n");
has_err = true;
return NULL;
}
while(!line_read){
if((tmp_buf = malloc(DEFAULT_BUFFER)) == NULL){
fprintf(stderr, "readLine: Unable to allocate temporary buffer!\n");
if(buffer != NULL)
free(buffer);
has_err = true;
return NULL;
}
if(fgets(tmp_buf, DEFAULT_BUFFER, file) == NULL){
free(tmp_buf);
break;
}
if(tmp_buf[strlen(tmp_buf) - 1] == '\n') /* we have an end of line */
line_read = true;
offset = DEFAULT_BUFFER * (iteration + 1);
if((buffer = realloc(buffer, offset)) == NULL){
fprintf(stderr, "readLine: Unable to reallocate buffer!\n");
free(tmp_buf);
has_err = true;
return NULL;
}
offset = DEFAULT_BUFFER * iteration - iteration;
if(memcpy(buffer + offset, tmp_buf, DEFAULT_BUFFER) == NULL){
fprintf(stderr, "readLine: Cannot copy to buffer\n");
free(tmp_buf);
if(buffer != NULL)
free(buffer);
has_err = true;
return NULL;
}
free(tmp_buf);
iteration++;
}
return buffer;
}
There is a simple regex like syntax that can be used inside scanf to take whole line as input
scanf("%[^\n]%*c", str);
^\n tells to take input until newline doesn't get encountered. Then, with %*c, it reads newline character and here used * indicates that this newline character is discarded.
Sample code
#include <stdio.h>
int main()
{
char S[101];
scanf("%[^\n]%*c", S);
printf("%s", S);
return 0;
}
On BSD systems and Android you can also use fgetln:
#include <stdio.h>
char *
fgetln(FILE *stream, size_t *len);
Like so:
size_t line_len;
const char *line = fgetln(stdin, &line_len);
The line is not null terminated and contains \n (or whatever your platform is using) in the end. It becomes invalid after the next I/O operation on stream.
Something like this:
unsigned int getConsoleInput(char **pStrBfr) //pass in pointer to char pointer, returns size of buffer
{
char * strbfr;
int c;
unsigned int i;
i = 0;
strbfr = (char*)malloc(sizeof(char));
if(strbfr==NULL) goto error;
while( (c = getchar()) != '\n' && c != EOF )
{
strbfr[i] = (char)c;
i++;
strbfr = (void*)realloc((void*)strbfr,sizeof(char)*(i+1));
//on realloc error, NULL is returned but original buffer is unchanged
//NOTE: the buffer WILL NOT be NULL terminated since last
//chracter came from console
if(strbfr==NULL) goto error;
}
strbfr[i] = '\0';
*pStrBfr = strbfr; //successfully returns pointer to NULL terminated buffer
return i + 1;
error:
*pStrBfr = strbfr;
return i + 1;
}
The best and simplest way to read a line from a console is using the getchar() function, whereby you will store one character at a time in an array.
{
char message[N]; /* character array for the message, you can always change the character length */
int i = 0; /* loop counter */
printf( "Enter a message: " );
message[i] = getchar(); /* get the first character */
while( message[i] != '\n' ){
message[++i] = getchar(); /* gets the next character */
}
printf( "Entered message is:" );
for( i = 0; i < N; i++ )
printf( "%c", message[i] );
return ( 0 );
}
Here is a minimal implementation to do it, the nice thing is that it will not keep the '\n', however you have to give it a size to read for security:
#include <stdio.h>
#include <errno.h>
int sc_gets(char *buf, int n)
{
int count = 0;
char c;
if (__glibc_unlikely(n <= 0))
return -1;
while (--n && (c = fgetc(stdin)) != '\n')
buf[count++] = c;
buf[count] = '\0';
return (count != 0 || errno != EAGAIN) ? count : -1;
}
Test with:
#define BUFF_SIZE 10
int main (void) {
char buff[BUFF_SIZE];
sc_gets(buff, sizeof(buff));
printf ("%s\n", buff);
return 0;
}
NB: You are limited to INT_MAX to find your line return, which is more than enough.

Resources