UPDATE:
Okay, I'm going about this entirely the wrong way. The reason I'm not geting the result I want is because I'm reading from the terminal and awaiting an enter keypress before the program continues to execute. What I actually need to do is program a "screen" or x11 window to read real-time inputs. Therefore my question is now redundant. Thanks for everyone's suggestions.
Is there a better way to program this which would allow me to capture
keyPress time? And, why is the BUFFERSIZE conditional in the while loop not
breaking out of the loop?
#define BUFFERSIZE 100
int main(void) {
int terminalInput;
int keyPress = 0;
int inputArrayBuffer[BUFFERSIZE];
int bufferExceptionFlag = 0;
printf("\n\t\t\t->"); /* Prompt */
while((terminalInput = getchar()) != '\n' && keyPress < BUFFERSIZE) {
inputArrayBuffer[keyPress] = terminalInput;
++keyPress;
if (keyPress >= BUFFERSIZE) {
bufferExceptionFlag = 1;
}
}
return 0;
}
A few issues. For one, your inputArrayBuffer should be a char array, not an int array. Secondly, there are standard C libraries that include the functionality of what you want to do.
Question 1: "Is there a better way to program this which would allow me to capture keyPress time?"
Yes. For reading stdin until either a newline is encountered or a max length is encountered, the fgets function from stdio.h works nicely (although alternatives may exist). Something like,
fgets(inputArrayBuffer, BUFFERSIZE, stdin)
I understand you want to know the number of keys the user entered, not including the newline key. This is essentially the string length. An easier way to achieve this is to simply determine the length of the string entered by the user. Something like,
keyPress = strlen(inputArrayBuffer) - 1; // -1 because the newline '\n' is included in strlen if you use fgets
If you must capture a single character at a time, then the original code you proposed should work, just be certain to define inputArrayBuffer as char inputArrayBuffer[BUFFERSIZE];
Question 2: "And, why is the BUFFERSIZE conditional in the while loop not breaking out of the loop?"
It definitely should be breaking out of the loop. But don't confuse bufferExceptionFlag equaling the value 1 with signifying that keyPress < BUFFERSIZE didn't cause the loop to break. Clearly, when you ++keyPress inside the loop, if keyPress had the value of 99, it would then become 100, which would cause bufferExceptionFlag to be set. However, on the next loop iteration keyPress < BUFFERSIZE would be false and the loop would break.
Here is a more simple and appropriate solution in my opinion.
#include <stdio.h>
#include <string.h>
#define BUFFERSIZE 100
int main(void) {
char inputArrayBuffer[BUFFERSIZE];
unsigned long keyPress = 0;
printf("\n\t\t\t->"); /* Prompt */
fgets(inputArrayBuffer, BUFFERSIZE, stdin);
keyPress = strlen(inputArrayBuffer) - 1; // -1 because the newline '\n' is included in strlen if you use fgets
printf("User entered: %s\n", inputArrayBuffer);
printf("Input length: %lu\n", keyPress);
return 0;
}
Note that fgets includes the newline character on the string it reads. To remove this character you can do something like inputArrayBuffer[keyPress] = '\0';
Related
So far I have been using if statements to check the size of the user-inputted strings. However, they don't see to be very useful: no matter the size of the input, the while loop ends and it returns the input to the main function, which then just outputs it.
I don't want the user to enter anything greater than 10, but when they do, the additional characters just overflow and are outputted on a newline. The whole point of these if statements is to stop that from happening, but I haven't been having much luck.
#include <stdio.h>
#include <string.h>
#define SIZE 10
char *readLine(char *buf, size_t sz) {
int true = 1;
while(true == 1) {
printf("> ");
fgets(buf, sz, stdin);
buf[strcspn(buf, "\n")] = 0;
if(strlen(buf) < 2 || strlen(buf) > sz) {
printf("Invalid string size\n");
continue;
}
if(strlen(buf) > 2 && strlen(buf) < sz) {
true = 0;
}
}
return buf;
}
int main(int argc, char **argv) {
char buffer[SIZE];
while(1) {
char *input = readLine(buffer, SIZE);
printf("%s\n", input);
}
}
Any help towards preventing buffer overflow would be much appreciated.
When the user enters in a string longer than sz, your program processes the first sz characters, but then when it gets back to the fgets call again, stdin already has input (the rest of the characters from the user's first input). Your program then grabs another up to sz characters to process and so on.
The call to strcspn is also deceiving because if the "\n" is not in the sz chars you grab than it'll just return sz-1, even though there's no newline.
After you've taken input from stdin, you can do a check to see if the last character is a '\n' character. If it's not, it means that the input goes past your allowed size and the rest of stdin needs to be flushed. One way to do that is below. To be clear, you'd do this only when there's been more characters than allowed entered in, or it could cause an infinite loop.
while((c = getchar()) != '\n' && c != EOF)
{}
However, trying not to restructure your code too much how it is, we'll need to know if your buffer contains the newline before you set it to 0. It will be at the end if it exists, so you can use the following to check.
int containsNewline = buf[strlen(buf)-1] == '\n'
Also be careful with your size checks, you currently don't handle the case for a strlen of 2 or sz. I would also never use identifier names like "true", which would be a possible value for a bool variable. It makes things very confusing.
In case that string inside the file is longer that 10 chars, your fgets() reads only the first 10 chars into buf. And, because these chars doesn't contain the trailing \n, function strcspn(buf, "\n") returns 10 - it means, you are trying to set to 0 an buf[10], so it is over buf[] boundaries (max index is 9).
Additionally, never use true or false as the name of variable - it totally diminishes the code. Use something like 'ok' instead.
Finally: please clarify, what output is expected in case the file contains string longer than 10 characters. It should be truncated?
I have written a small script to detect the full value from the user input with the getchar() function in C. As getchar() only returns the first character i tried to loop through it... The code I have tried myself is:
#include <stdio.h>
int main()
{
char a = getchar();
int b = strlen(a);
for(i=0; i<b; i++) {
printf("%c", a[i]);
}
return 0;
}
But this code does not give me the full value of the user input.
You can do looping part this way
int c;
while((c = getchar()) != '\n' && c != EOF)
{
printf("%c", c);
}
getchar() returns int, not char. And it only returns one char per iteration. It returns, however EOF once input terminates.
You do not check for EOF (you actually cannot detect that instantly when getchar() to char).
a is a char, not an array, neither a string, you cannot apply strlen() to it.
strlen() returns size_t, which is unsigned.
Enable most warnings, your compiler wants to help you.
Sidenote: char can be signed or unsigned.
Read a C book! Your code is soo broken and you confused multiple basic concepts. - no offense!
For a starter, try this one:
#include <stdio.h>
int main(void)
{
int ch;
while ( 1 ) {
ch = getchar();
x: if ( ch == EOF ) // done if input terminated
break;
printf("%c", ch); // %c takes an int-argument!
}
return 0;
}
If you want to terminate on other strings, too, #include <string.h> and replace line x: by:
if ( ch == EOF || strchr("\n\r\33", ch) )
That will terminate if ch is one of the chars listed in the string literal (here: newline, return, ESCape). However, it will also match ther terminating '\0' (not sure if you can enter that anyway).
Storing that into an array is shown in good C books (at least you will learn how to do it yourself).
Point 1: In your code, a is not of array type. you cannot use array subscript operator on that.
Point 2: In your code, strlen(a); is wrong. strlen() calculates the length of a string, i.e, a null terminated char array. You need to pass a pointer to a string to strlen().
Point 3: getchar() does not loop for itself. You need to put getchar() inside a loop to keep on reading the input.
Point 4: getchar() retruns an int. You should change the variable type accordingly.
Point 5: The recommended signature of main() is int main(void).
Keeping the above points in mind,we can write a pesudo-code, which will look something like
#include <stdio.h>
#define MAX 10
int main(void) // nice signature. :-)
{
char arr[MAX] = {0}; //to store the input
int ret = 0;
for(int i=0; i<MAX; i++) //don't want to overrrun array
{
if ( (ret = getchar())!= EOF) //yes, getchar() returns int
{
arr[i] = ret;
printf("%c", arr[i]);
}
else
;//error handling
}
return 0;
}
See here LIVE DEMO
getchar() : get a char (one character) not a string like you want
use fgets() : get a string or gets()(Not recommended) or scanf() (Not recommended)
but first you need to allocate the size of the string : char S[50]
or use a malloc ( #include<stdlib.h> ) :
char *S;
S=(char*)malloc(50);
It looks like you want to read a line (your question mentions a "full value" but you don't explain what that means).
You might simply use fgets for that purpose, with the limitation that you have to provide a fixed size line buffer (and handle - or ignore - the case when a line is larger than the buffer). So you would code
char linebuf[80];
memset (linebuf, 0, sizeof(linbuf)); // clear the buffer
char* lp = fgets(linebuf, sizeof(linebuf), stdin);
if (!lp) {
// handle end-of-file or error
}
else if (!strchr(lp, '\n')) {
/// too short linebuf
}
If you are on a POSIX system (e.g. Linux or MacOSX), you could use getline (which dynamically allocates a buffer). If you want some line edition facility on Linux, consider also readline(3)
Avoid as a plague the obsolete gets
Once you have read a line into some buffer, you can parse it (e.g. using manual parsing, or sscanf -notice the useful %n conversion specification, and test the result count of sscanf-, or strtol(3) -notice that it can give you the ending pointer- etc...).
I am just a beginner in programming. And I am learning the K&R's book, the C Programming Language. While I am reading, I become more and more curious about this question --
when there is a loop to get characters one by one from the input and I put an outputing function in the loop, whose result I thought would be like print each character right after it had been entered. However, the result seems like the computer will only print out a whole package of characters after I tap a key.
Such as the answer of exercise 1-22 from K&R's book:
/* K&R Exercise 1-22 p.34
*
* Write a program to "fold" long input lines into two or more
* shorter lines after the last non-blank character that occurs before the n-th
* column of input. Make sure your program does something intelligent with very
* long lines, and if there are no blanks or tabs before the specified column.
*/
#include <stdio.h>
#define LINE_LENGTH 80
#define TAB '\t'
#define SPACE ' '
#define NEWLINE '\n'
void entab(int);
int main()
{
int i, j, c;
int n = -1; /* The last column with a space. */
char buff[LINE_LENGTH + 1];
for ( i=0; (c = getchar()) != EOF; ++i )
{
/* Save the SPACE to the buffer. */
if ( c == SPACE )
{
buff[i] = c;
}
/* Save the character to the buffer and note its position. */
else
{
n = i;
buff[i] = c;
}
/* Print the line and reset counts if a NEWLINE is encountered. */
if ( c == NEWLINE )
{
buff[i+1] = '\0';
printf("%s", buff);
n = -1;
i = -1;
}
/* If the LINE_LENGTH was reached instead, then print up to the last
* non-space character. */
else if ( i == LINE_LENGTH - 1 )
{
buff[n+1] = '\0';
printf("%s\n", buff);
n = -1;
i = -1;
}
}
}
I supposed the program would turn out to be like, it would print out only one line of characters, whose length is 80, right after I entered just 80 characters (and I haven't tapped an ENTER key yet). However, it doesn't show up that way! I can totally enter the whole string no matter how many characters there are. When I finally decide to finish the line, I just tap ENTER key, and it will give me the right outputs: the long string is cut into several short pieces/lines, which have 80 characters (and of course the last one may contain less than 80 characters).
I wonder WHY does that happened?
Usually (and in your case), stdin is line-buffered, so your programme doesn't receive the characters as they are typed, but in chunks, when the user enters a newline (Return), or, possibly, when the system buffer is full.
So when the user input is finally sent to your programme, it is copied into the programme's input buffer. That's where getchar() reads the characters from to fill buff.
If the input is long enough, buff will be filled with LINE_LENGTH characters from the input buffer and then printed several times (until the entire contents of the input buffer have been consumed).
On Linux (methinks generally on Unix-ish systems, but I'm not sure), you can also send the input to the programme without entering a newline by typing Ctrl+D on a non-empty line (as the first input on a line, that closes stdin; at a later point in an input line, you can close stdin by typing it twice), so if you type Ctrl+D after entering LINE_LENGTH [or more] characters without a newline, [at least the initial part of] the input is printed immediately then.
I'm very glad to see you here because I also come from China. Actually, my English is poor. And, I am a beginner in programming, too. So, I have not understand your purpose very well.
However, I found a problem in your codes. The loop may not stop. EOF is end of file, but you didn't open any files.
What I knew about getchar() is getting a standard input into butter cache. getchar() is often used to stop the input(or loop).
I hope my answer could help you.
This question already has answers here:
How to read a line from the console in C?
(14 answers)
Closed 5 years ago.
I want to read a string from the console.
Using scanf or fgets however, it seems to me that it's only possible to read a string of a fixed maximum size. Even worse, there seems to be no way of checking how many characters were entered in case the user enters too much (in that case I could simply realloc the array in order for the string to fit into the array).
I read that I'm supposed to read one character at a time in the answer to this question, however I don't know how to read one character at a time without having the user press enter after each character.
How can I do it?
The GCC documentation says that:
Standard C has functions to do this, but they aren't very safe: null characters and even (for gets) long lines can confuse them. So the GNU library provides the nonstandard getline function that makes it easy to read lines reliably.
and that
[getline] is a GNU extension, but it is the recommended way to read lines from a stream. The alternative standard functions are unreliable.
So if you're using GCC, I'd say you should use getline. If you're not using GCC, you should see if your compiler offers a similar feature. If it doesn't — or if you really prefer to use something standard — then you need to read one character at a time.
I don't know how to read one character at a time without having the user press enter after each character.
Yes, you do. The user enters a sequence of characters, and then presses Enter. Your first fgetc call will block until the user presses Enter, but after that, subsequent fgetc calls will return immediately, up until you read the newline. (Then it will block again, until the user presses Enter again.) Reading "one character at a time" doesn't mean that you have to read each character before the user types the next one; it just means that, once the user is done typing a line, you read that line one character at a time.
Try running this..
#include <stdio.h>
int main(){
char next;
while((next=getchar())!=EOF)
printf("%c\n",next);
}
then check out the man page for getchar() to see what's really at hand.
char c = NULL;
while (c != 0x0D)
{
scanf("%c", &c);
// do stuffs with c
}
You can use fgets() in a loop and realloc if the last character is not a \n
/* UNTESTED: MAY HAVE OFF-BY-ONE ERRORS */
char *buffer;
size_t bufsiz = 100;
size_t buflen = 100;
size_t bufcur = 0;
buffer = malloc(bufsiz);
for (;;) {
fgets(buffer + bufcur, bufsiz, stdin);
buflen = bufcur + strlen(buffer + bufcur);
if (buffer[buflen - 1] == '\n') break;
tmp = realloc(buffer, bufsiz * 2);
if (tmp == NULL) /* deal with error */;
buffer = tmp;
bufcur = buflen - 1;
bufsiz *= 2;
}
/* use buffer (and bufsiz and buflen) */
free(buffer);
The accepted answer should note that getchar() returns an int. The char data type is not big enough to hold EOF.
We could read a predetermined amount of text and then discard the rest of the input. That approach has more than its share of critics (how dare we presume to know what to discard). The other option is to use getline or write a custom function. I thought I'd try the latter.
This does not prevent users from filling up memory with cat large_file.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#define MAX 50
#define JUSTDO(a) if (!(a)) {perror(#a);exit(1);}
/** char *get_line FILE *f
* reads an arbitrarily long line of text or until EOF
* caller must free the pointer returned after use
*/
char *get_line (FILE *f) {
int len=MAX;
char buf[MAX],*e=NULL,*ret;JUSTDO (ret=calloc(MAX,1));
while (fgets (buf,MAX,f)) {
if (len-strlen(ret)<MAX) JUSTDO (ret=realloc(ret,len*=2));
strcat (ret,buf) ;if ((e=strrchr (ret,'\n'))) break;
} if (e) *e='\0';
return ret;
}
/* main */
int main (void) {
char *s;
printf ("enter a line of text:\n");
printf ("line was '%s'\n",s=get_line(stdin)) ;free (s);
return 0;
}
Hello i'm practising C and i have a little problem with the following code. First of all, my program just reads the input from the user and if there is memory availble, it stores it, otherwise it makes nothing.
I have an array of pointers to char called "lines" and an array of chars for the temporary storage of the input called "line".
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXWIDTH 81
#define MAXLINES 100
int main ()
{
char* lines [MAXLINES];
char line[MAXWIDTH];
int i ;
int n ;
Then i will check if my array of pointers has space and the input is non-zero. I do it in a for-loop to fill the array and normally the for-loop should stop when i type in nothing and just press enter or when the array is full.
If there is space i will check if there is enough memory in the space where the pointer is pointing to. If that's ok (!= NULL), the program copies the input from gets(line) in the memory.
for (n = 0; n < MAXLINES && gets(line) != NULL; n++)
{
if ((lines[n] = malloc(strlen(line) + 1)) == NULL)
exit (1);
strcpy(lines[n], line);
}
The rest of the code is just for the output and freeing of the memory.
for (i = 0; i < n; i++)
{
puts(lines[n-i-1]);
free(lines[n-i-1]);
}
return 0;
}
Now the problemis , that the program runs without any errors, but it's not working as i want.
It is just performing a infinte loop where i can type in as long as i want, what i want without any reaction.
gets doesn't return NULL when you type an empty line, if that's what you tried to check for. It will still be an empty string. You'll need to check if the first character is a \0 if you want to look for empty lines.
On a side note, gets is extremely unsafe since it will overrun your buffer if your line is too long and cause evil bugs. Use fgets instead, it lets you specify the size of your buffer. (Note that fgets will add a \n to the end of your string, even if it's an empty line.)
Well for a start, I suggest reading the following about why you should avoid using gets(). I suggest using scanf() or fgets() instead...
http://www.gidnetwork.com/b-56.html
then note that you're doing a loop to 100 taking input, and only after all 100 are you outputting. So you'll need to enter 100 lines of input currently before you see anything...
You're not checking for an empty line.
You need something like:
if('\0' == line[0])
{
break;
}
And use fgets() not gets(). It's safer. However you then need to do:
if('\n' == line[0] || '\r' == line[0])
{
break;
}
Well, how do you terminate your input? Entering an empty line won't help because line will be "" not NULL. Have you tried pressing Ctrl+Z in the console (if it's windows)?