|
|
#1 |
|
User input in C
I'm after a way to read user input in C, ideally as whitespace-separated strings.
Basically, I'm after something that works exactly the same way *argv[] works when launching the program, but using it for prompting/interaction. eg. Code:
$ ./program new 2 green but what about when my program is running and I need user input: Code:
Enter command: save /file.txt Code:
Enter command: set strength 10 Thanks |
|
|
|
0
|
|
|
#2 |
|
If you don't want to do a full-on parser that will handle things like quoted strings, perhaps use the strtok function.
Start with a call to fgets to read in the whole line. Then call strtok with the whole line as the first argument and a string of separators as the second argument. The returned result will be a string containing the first "word" in the input. Call strtok again repeatedly but with NULL as the first parameter to get the rest of the "words". It will return NULL when there's no more words. References: strtok http://developer.apple.com/library/m.../strtok.3.html fgets http://developer.apple.com/library/m...3/fgets.3.html |
|
|
|
0
|
|
|
#3 |
|
__________________
24" iMac, 13" MacBook, iPod Touch. iPod mini and PowerPC Mac Mini gathering dust somewhere. |
|
|
|
0
|
|
|
#4 | |
|
Quote:
One point no one seems to address is that fgets will only accept up to int n characters. If your user inputs more, you won't have the entire string read in. You need to check that the last character inputted is \n. If it's not, you need to grow your buffer and read in the rest of the string. While you may think that static value of 1024 you supply is long enough for anyone, someone trying to deliberately mangle your program's input in search of buffer overflows could cause harm. Better just be ready. You should read up on malloc/realloc to dynamically manage your input buffer and make sure to call fgets multiple times if needed.
__________________
"What you leave behind is not what is engraved in stone monuments, but what is woven into the lives of others." -- Pericles |
||
|
|
0
|
|
|
#5 |
|
Thanks for the replies.
I found exactly what I was after: http://www.lemoda.net/c/split-on-whitespace/index.html However, I can't use that, because it's not my work and it's way more than a snippet. I settled on fgets(), and instead of tokenising (which has far too many pitfalls), I'm just incrementing a pointer on whitespace to find each word in the string. At the moment, it's a fixed buffer, but I may need to make a *while char is not '\n', + 1. malloc that*. |
|
|
|
0
|
|
|
#6 | |
|
Quote:
The last paragraph can be done by strlen(). |
||
|
|
0
|
|
|
#7 |
|
You mean getline() right ? That is a POSIX function, not an ANSI one though. And it basically uses... realloc() on your buffer in order to read the entire line.
His last paragraph is a reference to my reference of fgets()'s problematic use of a fixed-sized buffer. EDIT : Working on server maintenance so trying to pass the time, so here's my over-engineered unoptimized solution : Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFFER_SIZE 5
int main(int argc, char ** argv)
{
char * buffer = NULL;
int buffersize = BUFFER_SIZE * sizeof(char);
char * tempbuffer = malloc(BUFFER_SIZE * sizeof(char));
do
{
if(!buffer)
{
buffer = malloc(buffersize);
printf("Input string : ");
fflush(stdout);
}
else
{
buffersize += (BUFFER_SIZE * sizeof(char));
printf("Buffer was not long enough, reallocating to %d bytes\n", buffersize);
buffer = realloc(buffer, buffersize);
}
fgets(tempbuffer, BUFFER_SIZE * sizeof(char), stdin);
buffer = strcat(buffer, tempbuffer);
printf("We got : \"%s\"\n", buffer);
} while(buffer[strlen(buffer) - 1] != '\n');
return EXIT_SUCCESS;
}
Code:
$ ./test Input string : Hello Macrumors, this string is too long ! We got : "Hell" Buffer was not long enough, reallocating to 10 bytes We got : "Hello Ma" Buffer was not long enough, reallocating to 15 bytes We got : "Hello Macrum" Buffer was not long enough, reallocating to 20 bytes We got : "Hello Macrumors," Buffer was not long enough, reallocating to 25 bytes We got : "Hello Macrumors, thi" Buffer was not long enough, reallocating to 30 bytes We got : "Hello Macrumors, this st" Buffer was not long enough, reallocating to 35 bytes We got : "Hello Macrumors, this string" Buffer was not long enough, reallocating to 40 bytes We got : "Hello Macrumors, this string is " Buffer was not long enough, reallocating to 45 bytes We got : "Hello Macrumors, this string is too " Buffer was not long enough, reallocating to 50 bytes We got : "Hello Macrumors, this string is too long" Buffer was not long enough, reallocating to 55 bytes We got : "Hello Macrumors, this string is too long ! "
__________________
"What you leave behind is not what is engraved in stone monuments, but what is woven into the lives of others." -- Pericles Last edited by KnightWRX; Mar 13, 2011 at 03:39 PM. |
|
|
|
0
|
|
|
#8 |
|
Thanks Knight, that's basically the same as what I ended up working out yesterday.
Mine makes an initial buffer of 5 chars, then if a '\n' isn't found, it gives the buffer another 5 chars and writes SIX characters into the new buffer (to overwrite the '\0' at the end of the old block). Edit: Basically that means your statement to check for null isn't needed in mine, and I guess I did strcat manually by overlapping on the terminator. Last edited by iEdd; Mar 13, 2011 at 04:31 PM. |
|
|
|
0
|
|
|
#9 |
|
|
0
|
|
|
#10 | ||
|
Quote:
![]() You could go larger than 5 chars at a time to make less iterations at the cost of additional memory use on the last iteration. You could also read in 1 char by 1 to make sure to never use up too much memory. A compromise on what you want your function to cost. Of course, this being 2011 and both CPU and RAM being available in mass quantities makes these kind of optimizations quite useless. Quote:
getline() of course solves that on Posix systems. Other systems require the type of code me and iEdd wrote using fgets() and realloc(). Of course, if you're doing fgets() input on a string itself (which is technically possible if not completely useless... strncpy() anyone ?), then you can just pass the 2nd parameter as a strlen() of the 3rd parameter.
__________________
"What you leave behind is not what is engraved in stone monuments, but what is woven into the lives of others." -- Pericles Last edited by KnightWRX; Mar 13, 2011 at 06:00 PM. |
|||
|
|
0
|
|
|
#11 |
|
What are you talking about? This is the sentence I referred to:
"At the moment, it's a fixed buffer, but I may need to make a *while char is not '\n', + 1. malloc that*" Being able to scan through it looking for '\n' is assuming it's in a buffer. Even if you use fgets with a fair buffer size say 1024 then you can re-write that buffer on each pass. Having an upper bound is normal, infinite length input is not possible anyway, so why not just use BUFSIZ as an upper bound, then beyond that assume the program is being used in a non legitimate way and issue an error. |
|
|
|
0
|
|
|
#12 | |
|
Quote:
PM me if you need this explained further or read my post and code, I think I have been clear enough and iEdd has too. Again, read my post, we're talking about stdin as the buffer specifically.
__________________
"What you leave behind is not what is engraved in stone monuments, but what is woven into the lives of others." -- Pericles |
||
|
|
0
|
|
|
#13 |
|
Im not referring to stdin, I'm referring to a buffer used by fgets() it needs one. I don't need to get this explained, this is a bit ridiculous don't you think? I mean it's such a trivial problem after all.
|
|
|
|
0
|
|
|
#14 |
|
PM sent. No need to carry this on in this thread at this point.
__________________
"What you leave behind is not what is engraved in stone monuments, but what is woven into the lives of others." -- Pericles |
|
|
|
0
|
|
|
#15 |
|
I'm giving an advise, you are disputing the validity of it. I don't see why it can't be discussed here as it's clearly on topic. I'm not talking about stdin, as I said you can use a buffer that you over write on each pass.
|
|
|
|
0
|
|
|
#16 | |||
|
Quote:
Quote:
Quote:
Lets keep this in PM for now, this is derailing the thread.
__________________
"What you leave behind is not what is engraved in stone monuments, but what is woven into the lives of others." -- Pericles |
||||
|
|
0
|
|
|
#17 |
|
Look, if your simply counting characters one by one from stdin, even though that is possible. Once you have the length it's useless, since your input string is gone. You need at least a temporary buffer.
Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char buf[3] = {0};
size_t length = 0;
while( fgets(buf, 3, stdin) != 0 ) {
length = strlen(buf);
// allocate here
printf("%lu\n", length);
}
return 0;
}
|
|
|
|
0
|
|
|
#18 | |
|
Quote:
Code:
Zaphod Beeblebrox is a really cool cat who always knows where his towel is It seems like the desired behavior here is to terminate at the first EOL, and simply looking at strlen doesn't seem to let you find that. For lines that don't have an exact multiple of 3 characters you would be able to detect the EOL by when length != 3, but otherwise... B
__________________
MBA (13" 1.7 GHz 128GB), UMBP (15" SD 2.8 GHz), UMB (13" 2.4 GHz), iMac (17" Yonah), 32GB iPad 3 WiFi+LTE, 64 GB iPad WiFi, 32 GB iPhone 5, Airport Extreme |
||
|
|
0
|
|
|
#19 |
|
I guess so, but assuming it's used as a live interpreter it would not be possible to enter more than one line at a time. But yeah, if not, you would have to use something like strchr() or similar I guess.
|
|
|
|
0
|
|
|
#20 | |
|
I lol'd though. Thankyou both for the contributions, even if there was some confusion. I also apologise for my atrocious pseudo code (the sentence in question).
To clear things up though, I'm referring to two buffers - stdin and the one that I continually realloc (buffer in KnightWRX's code). Couple of questions though, KnightWRX: - What does flushing the output stream [fflush(stdout)] do in this code? (I don't have that entire if statement in my code because I start with an initial buffer anyway.) Quote:
Thanks again. |
||
|
|
0
|
|
|
#21 | ||
|
Quote:
This usually works fine on Borland's runtime, but on GNU libc, I've found they use the other approach of waiting to flush the buffer and thus the prompt would not show up. fflush(stdout) forces the output to happen regardless. Quote:
__________________
"What you leave behind is not what is engraved in stone monuments, but what is woven into the lives of others." -- Pericles |
|||
|
|
0
|
|
|
#22 |
|
This is a diversion of the thread but I've just got to comment and recount about this references to Borland's runtime.
I'm surprised anyone knows or remembers how the Borland runtime behaved. My first compiler was Borland C++ 4.5 on Win 3.1. It was so big (or my hard disk was so small) that I had to choose between installing it or installing anything else. I'm a nerd, so it wasn't too hard of a choice. But I haven't thought about Borland since going to Java around 1997! When I came back to C++ years later, it was gcc on linux. No IDE, I'd matured into make and vim. ![]() Thanks for jogging the memory. |
|
|
|
0
|
|
|
#23 |
|
Cheers KnightWRX. I appreciate all the time you (and others) have spent in this thread.
![]() As for going off-topic, it's all good - it's all related to learning more about C, which is sort of what this thread is about. I'll lookup Borland. |
|
|
|
0
|
|
|
#24 |
|
I just looked it up myself to see where it had gone. There was no mention of any programming tools at borland.com! Then I read the Borland Wikipedia page. In 2008, Borland's programming tools were sold to Embarcadero. C++ Builder (the evolution of Borland C++) now lives here: http://www.embarcadero.com/products/cbuilder
|
|
|
|
0
|
|
|
#25 |
|
I spent most of my time in the late 90s on the blue and grey screens of Turbo C++ for DOS (version 3.0 ?). Cheap, small and "good enough" to learn straight ANSI C on. Now that you mention it, I've just had a bit of nostalgia, I had to look it up :
![]() (OMG conio.h and clrscr()! What an abomination!) It seems Borland eventually gave it away free : http://www.top4download.com/turbo-c-/aklqwuba.html. Now I'm just going to have to see if that runs in DOSBox. ![]() I migrated to VI and Makefiles on Linux too after a quick dabble in the darkside of Win32 (read Charles Petzold's work and worked on OpenGL stuff using Microsoft's then slow as molasse opengl32.dll). All this time writing out code and I never made anything worthwhile in C. I think the only actual piece of code I finished beyond assignments was a daemon that could run a few network diagnostics, which was part of a web app I was writing to run traceroutes/pings to gather statistics at an earlier ISP gig I had. Good luck iEdd! My terminal based ANSI-C game I'm still working on moved on to OpenGL on Windows, to SDL/Mesa on Linux to GTKGLArea on X11 and now to iOS using Quartz 2D (sad to see the GL code go, but the Quartz versions now does about 3 times more than any GL code I managed to make work).
__________________
"What you leave behind is not what is engraved in stone monuments, but what is woven into the lives of others." -- Pericles |
|
|
|
0
|
![]() |
|
«
Previous Thread
|
Next Thread
»
| Thread Tools | Search this Thread |
| Display Modes | |
|
|
Similar Threads
|
||||
| thread | Thread Starter | Forum | Replies | Last Post |
| Array size base on user input in C | icoigo | Mac Programming | 2 | Oct 27, 2010 02:23 PM |
| osx user input | Nonnus3G | Mac Programming | 5 | Oct 31, 2008 11:33 PM |
| Slow to respond to user input | deniser | iPhone Tips, Help and Troubleshooting | 7 | Jul 15, 2008 02:09 PM |
| User Input | ghking | Web Design and Development | 0 | Oct 11, 2007 02:03 PM |
| is there a security mode where user input requires a password but is not sleep? | motulist | Mac Applications and Mac App Store | 6 | Jun 10, 2004 11:04 PM |
All times are GMT -5. The time now is 09:00 PM.









But I haven't thought about Borland since going to Java around 1997! When I came back to C++ years later, it was gcc on linux. No IDE, I'd matured into make and vim. 

Linear Mode

