vim: filetype=help:readonly:nomodifiable: Objective C help file - pcontreras 23/1/2017 - revision 1 ----------------------------------------------------------------------------------- *what_does_autoreleasepool_do* +------------------------------+~ | What Does autoreleasepool do |~ +------------------------------+~ source: http://stackoverflow.com/questions/14677049/what-is-autoreleasepool-objective-c All Objective-C starting page opens with a default @autoreleasepool{...} statement under the main function declaration. But what is this statement actually doing? The new Objective-C releases automatically objects and deleting the line changes nothing to the program. Is this command really necessary? Answer~ The @autoreleasepool statement is doing the same job as before, instead of using the NSAutoreleasePool class. The way the NSAutoreleasePool worked was a bit weird, as creating it caused an effect throughout the whole application; @autoreleasepool creates a scoped area and makes it clearer what's within the pool and when it drains (when it goes out of scope). It's also more efficient according to Apple. The concept of an autorelease pool is simple, whenever an object instance is marked as autoreleased (for example NSString* str = [[[NSString alloc] initWithString:@"hello"] autorelease];), it will have a retain count of +1 at that moment in time, but at the end of the run loop, the pool is drained, and any object marked autorelease then has its retain count decremented. It's a way of keeping an object around while you prepare whatever will retain it for itself. With ARC, whilst the autorelease keyword isn't used by the developer, the underlying system that manages ARC inserts that for you. (Remember: All ARC is doing is inserting retain, release and autorelease calls for you at the appropriate times). Because of this, the existing AutoreleasePool concept needs to stay around. If you remove the autorelease pool, your objects will start leaking ----------------------------------------------------------------------------------- *c_strings_ie_char_array__arrays_vs_pointers* +-------------------------------------------------------+~ | C Strings - i.e 'char array' - (Arrays vs. Pointers ) |~ +-------------------------------------------------------+~ source: http://www.cs.bu.edu/teaching/cpp/string/array-vs-ptr/ 1. Strings as arrays:~ Before the string class, the abstract idea of a string was implemented with just an array of characters. For example, here is a string: > char label[] = "Single"; What this array looks like in memory is the following: < ------------------------------ | S | i | n | g | l | e | \0 | ------------------------------ where the beginning of the array is at some location in computer memory, for example, location 1000. Note: Don't forget that one character is needed to store the nul character (\0), which indicates the end of the string. A character array can have more characters than the abstract string held in it, as below: > char label[10] = "Single"; < giving an array that looks like: ------------------------------------------ | S | i | n | g | l | e | \0 | | | | ------------------------------------------ (where 3 array elements are currently unused). Since these strings are really just arrays, we can access each character in the array using subscript notation, as in: > cout << "Third char is: " << label[2] << endl; < which prints out the third character, n. A disadvantage of creating strings using the character array syntax is that you must say ahead of time how many characters the array may hold. For example, in the following array definitions, we state the number of characters (either implicitly or explicitly) to be allocated for the array. > char label[] = "Single"; // 7 characters char label[10] = "Single"; < Thus, you must specify the maximum number of characters you will ever need to store in an array. This type of array allocation, where the size of the array is determined at compile-time, is called static allocation. 2. Strings as pointers:~ Another way of accessing a contiguous chunk of memory, instead of with an array, is with a pointer. Since we are talking about strings, which are made up of characters, we'll be using pointers to characters, or rather, char *'s. However, pointers only hold an address, they cannot hold all the characters in a character array. This means that when we use a char * to keep track of a string, the character array containing the string must already exist (having been either statically- or dynamically-allocated). Below is how you might use a character pointer to keep track of a string. > char label[] = "Single"; char label2[10] = "Married"; char *labelPtr; labelPtr = label; < We would have something like the following in memory (e.g., supposing that the array label started at memory address 2000, etc.): label @2000 ------------------------------ | S | i | n | g | l | e | \0 | ------------------------------ label2 @3000 ------------------------------------------ | M | a | r | r | i | e | d | \0 | | | ------------------------------------------ labelPtr @4000 -------- | 2000 | -------- Note: Since we assigned the pointer the address of an array of characters, the pointer must be a character pointer--the types must match. Also, to assign the address of an array to a pointer, we do not use the address-of (&) operator since the name of an array (like label) behaves like the address of that array in this context. Now, we can use labelPtr just like the array name label. So, we could access the third character in the string with: > cout << "Third char is: " << labelPtr[2] << endl; < It's important to remember that the only reason the pointer labelPtr allows us to access the label array is because we made labelPtr point to it. Suppose, we do the following: > labelPtr = label2; < Now, no longer does the pointer labelPtr refer to label, but now to label2 as follows: label2 @3000 ------------------------------------------ | M | a | r | r | i | e | d | \0 | | | ------------------------------------------ labelPtr @4000 -------- | 3000 | -------- So, now when we subscript using labelPtr, we are referring to characters in label2. The following: > cout << "Third char is: " << labelPtr[2] << endl; prints out r, the third character in the label2 array. < ----------------------------------------------------------------------------------- *c_library_function__scanf()* +------------------------------+~ | C library function - scanf() |~ +------------------------------+~ source:~ https://www.tutorialspoint.com/c_standard_library/c_function_scanf.htm see also:~ Description~ The C library function int scanf(const char *format, ...) reads formatted input from stdin. Declaration~ Following is the declaration for scanf() function. > int scanf(const char *format, ...) < Parameters~ format ------ This is the C string that contains one or more of the following items: Whitespace character, Non-whitespace character and Format specifiers. A format specifier will be like [=%[*][width][modifiers]type=] as explained below: argument / Description~ * ----- this is an optional starting asterisk indicates that the data is to be read from the stream but ignored, i.e. it is not stored in the corresponding argument. width ----- This specifies the maximum number of characters to be read in the current reading operation. modifiers --------- Specifies a size different from int (in the case of d, i and n), unsigned int (in the case of o, u and x) or float (in the case of e, f and g) for the data pointed by the corresponding additional argument: h : short int (for d, i and n), or unsigned short int (for o, u and x) l : long int (for d, i and n), or unsigned long int (for o, u and x), or double (for e, f and g) L : long double (for e, f and g) type ----- A character specifying the type of data to be read and how it is expected to be read. See next table. fscanf type specifiers~ type / Qualifying Input / Type of argument ------------------------------------------ c Single character: Reads the next character. If a width different from 1 is specified, the function reads width characters and stores them in the successive locations of the array passed as argument. No null character is appended at the end. char * ----- d Decimal integer: Number optionally preceded with a + or - sign int * ----- e, E, f, g, G Floating point: Decimal number containing a decimal point, optionally preceded by a + or - sign and optionally followed by the e or E character and a decimal number. Two examples of valid entries are -732.103 and 7.12e4 float * ----- o Octal Integer: int * ----- s String of characters. This will read subsequent characters until a whitespace is found (whitespace characters are considered to be blank, newline and tab). char * ----- u Unsigned decimal integer. unsigned int * ----- x, X Hexadecimal Integer int * ----- Additional Arguments~ Depending on the format string, the function may expect a sequence of additional arguments, each containing one value to be inserted instead of each %-tag specified in the format parameter, if any. There should be the same number of these arguments as the number of %-tags that expect a value. Return Value~ If successful, the total number of characters written is returned, otherwise a negative number is returned. Example~ The following example shows the usage of scanf() function. > #include int main() { char str1[20], str2[30]; printf("Enter name: "); scanf("%s", str1); printf("Enter your website name: "); scanf("%s", str2); printf("Entered Name: %s\n", str1); printf("Entered Website:%s", str2); return(0); } < Let us compile and run the above program that will produce the following result in interactive mode: > Enter name: admin Enter your website name: www.tutorialspoint.com Entered Name: admin Entered Website: www.tutorialspoint.com < ----------------------------------------------------------------------------------- *how_do_you_allow_spaces_to_be_entered_using_scanf* +---------------------------------------------------+~ | how_do_you_allow_spaces_to_be_entered_using_scanf |~ +---------------------------------------------------+~ source: http://stackoverflow.com/questions/1247989/how-do-you-allow-spaces-to-be-entered-using-scanf Using the following code: > char *name = malloc(sizeof(char) + 256); printf("What is your name? "); scanf("%s", name); printf("Hello %s. Nice to meet you.\n", name); < A user can enter their name but when they enter a name with a space like Lucas Aardvark, scanf() just cuts off everything after Lucas. How do I make scanf() allow spaces asked Aug 8 '09 at 4:37 Lucas 17k36134186 Note that more idiomatic is 'malloc(sizeof(char) * 256 + 1)', or 'malloc(256 + 1)', or even better (assuming 'name' will be used strictly locally) 'char name[256+1]'. The '+1' can act as a mneumonic for the null terminator, which needs to be included in the allocation. – Barry Kelly Aug 8 '09 at 4:47 @Barry - I suspect sizeof(char) + 256 was a typo. – Chris Lutz Jul 20 '11 at 22:06 -------------------- People (and especially beginners) should never use scanf("%s") or gets() or any other functions that do not have buffer overflow protection, unless you know for certain that the input will always be of a specific format (and perhaps not even then). Remember than scanf stands for "scan formatted" and there's precious little less formatted than user-entered data. It's ideal if you have total control of the input data format but generally unsuitable for user input. Use fgets() (which has buffer overflow protection) to get your input into a string and sscanf() to evaluate it. Since you just want what the user entered without parsing, you don't really need sscanf() in this case anyway: > #include #include #include /* Maximum name size + 1. */ #define MAX_NAME_SZ 256 int main(int argC, char *argV[]) { /* Allocate memory and check if okay. */ char *name = malloc (MAX_NAME_SZ); if (name == NULL) { printf ("No memory\n"); return 1; } /* Ask user for name. */ printf("What is your name? "); /* Get the name, with size limit. */ fgets (name, MAX_NAME_SZ, stdin); /* Remove trailing newline, if there. */ if ((strlen(name)>0) && (name[strlen (name) - 1] == '\n')) name[strlen (name) - 1] = '\0'; /* Say hello. */ printf("Hello %s. Nice to meet you.\n", name); /* Free memory and exit. */ free (name); return 0; } edited Mar 22 '16 at 7:35 answered Aug 8 '09 at 4:59 paxdiablo 508k12310111465 ----- I didn't know about fgets(). It actually looks easier to use then scanf(). +1 – Lucas Aug 8 '09 at 6:37 ----- If you just want to get a line from the user, it is easier. It's also safer since you can avoid buffer overflows. The scanf family is really useful for turning a string into different things (like four chars and an int for example with "%c%c%c%c%d") but, even then, you should be using fgets and sscanf, not scanf, to avoid the possibility of buffer overflow. – paxdiablo Aug 8 '09 at 6:48 3 ----- You can put maximum buffer size in scanf format, you just can't put runtime computed one without building the format at runtime (there isn't the equivalent of * for printf, * is a valid modificator for scanf with another behavior: suppressing assignation). – AProgrammer Aug 8 '09 at 11:55 -------------------- Try > char str[11]; scanf("%10[0-9a-zA-Z ]", str); < Hope that helps. edited Jun 12 '15 at 1:56 Dr Beco 4,05642345 answered Aug 8 '09 at 4:39 Kelly Gendron 5,02412752 ----- I didn't even know scanf() accepted regex's! Thanks!!!!! – Lucas Aug 8 '09 at 4:41 ----- note, it doesn't do general regexes, just character classes – rampion Aug 8 '09 at 4:47 ----- @rampion: Excellent side note (but still that's pretty cool). – Lucas Aug 8 '09 at 4:48 ----- (1) Obviously to accept spaces, you need to put a space in the character class. (2) Note that the 10 is the maximum number of characters which will be read, so str has to point to a buffer of size 11 at least. (3) The final s here isn't a format directive but scanf will try here to match it exactly. The effect will be visible on an entry like 1234567890s where the s will be consumed but put no where. An other letter won't be consumed. If you put another format after the s, it will be read only if there is an s to be matched. – AProgrammer Aug 8 '09 at 11:52 ----- why's there a trailing s in the format string? – ajay Jan 13 '14 at 14:13 This example uses an inverted scanset, so scanf keeps taking in values until it encounters a '\n'-- newline, so spaces get saved as well > #include int main (int argc, char const *argv[]) { char name[20]; scanf("%[^\n]s",name); printf("%s\n", name); return 0; } < Careful with buffer overflows. If the user writes a "name" with 50 characters, the program will probably crash. – brunoais Jan 29 '13 at 15:17 I was looking for something like this.. :) – Saurav Kumar May 21 '14 at 10:03 ----- You can use this > char name[20]; scanf("%20[^\n]", name); < Or this > void getText(char *message, char *variable, int size){ printf("\n %s: ", message); fgets(variable, sizeof(char) * size, stdin); sscanf(variable, "%[^\n]", variable); } char name[20]; getText("Your name", name, 20); < edited May 6 '14 at 17:06 answered Aug 22 '13 at 3:24 Vitim.us 6,90084361 ----- I did not test, but based on other answers in this very page, I believe the correct buffer size for scanf in your example would be: scanf("%19[^\n]", name); (still +1 for the concise answer) – Dr Beco Jun 12 '15 at 1:12 ----- Just as a side note, sizeof(char) is by definition always 1, so there's no need to multiply by it. – paxdiablo Mar 22 '16 at 7:37 -------------------- Don't use scanf() to read strings without specifying a field width. You should also check the return values for errors: > #include #define NAME_MAX 80 #define NAME_MAX_S "80" int main(void) { static char name[NAME_MAX + 1]; // + 1 because of null if(scanf("%" NAME_MAX_S "[^\n]", name) != 1) { fputs("io error or premature end of line\n", stderr); return 1; } printf("Hello %s. Nice to meet you.\n", name); } < Alternatively, use fgets(): > #include #define NAME_MAX 80 int main(void) { static char name[NAME_MAX + 2]; // + 2 because of newline and null if(!fgets(name, sizeof(name), stdin)) { fputs("io error\n", stderr); return 1; } // don't print newline printf("Hello %.*s. Nice to meet you.\n", strlen(name) - 1, name); } < answered Aug 8 '09 at 16:04 Christoph 104k25126188 -------------------- You can use the fgets() function to read a string or use scanf("%[^\n]s",name); so string reading will terminate upon encountering a newline character. edited Sep 17 '12 at 12:3 jonsca 7,75611361 answered Sep 17 '12 at 12:17 Anshul garg 16716 ----- Careful that this does not prevent buffer overflows – brunoais Jan 29 '13 at 15:16 -------------------- > getline() < Now part of POSIX, none-the-less. It also takes care of the buffer allocation problem that you asked about earlier, though you have to take care of freeing the memory. edited Nov 24 '11 at 17:34 answered Aug 8 '09 at 16:39 dmckee 68k17103187 ----- Standard? In the reference you cite: "Both getline() and getdelim() are GNU extensions." – AProgrammer Aug 9 '09 at 8:59 ----- POSIX 2008 adds getline. So GNU wen ahead and changed their headers for glibc around version 2.9, and it is causing trouble for many projects. Not a definitive link, but look here: bugzilla.redhat.com/show_bug.cgi?id=493941 . As for the on-line man page, I grabbed the first one google found. – dmckee Aug 9 -------------------- You may use scanf for this purpose with a little trick. Actually, you should allow user input until user hits Enter (\n). This will consider every character, including space. Here is example: > int main() { char string[100], c; int i; printf("Enter the string: "); scanf("%s", string); i = strlen(string); // length of user input till first space do { scanf("%c", &c); string[i++] = c; // reading characters after first space (including it) } while (c != '\n'); // until user hits Enter string[i - 1] = 0; // string terminating return 0; } < How this works? When user inputs characters from standard input, they will be stored in string variable until first blank space. After that, rest of entry will remain in input stream, and wait for next scanf. Next, we have a for loop that takes char by char from input stream (till \n) and apends them to end of string variable, thus forming a complete string same as user input from keyboard. Hope this will help someone! answered Jan 18 '15 at 11:06 ricardo22 1,00711423 -------------------- While you really shouldn't use scanf() for this sort of thing, because there are much better calls such as gets() or getline(), it can be done: > #include char* scan_line(char* buffer, int buffer_size); char* scan_line(char* buffer, int buffer_size) { char* p = buffer; int count = 0; do { char c; scanf("%c", &c); // scan a single character // break on end of line, string terminating NUL, or end of file if (c == '\r' || c == '\n' || c == 0 || c == EOF) { *p = 0; break; } *p++ = c; // add the valid character into the buffer } while (count < buffer_size - 1); // don't overrun the buffer // ensure the string is null terminated buffer[buffer_size - 1] = 0; return buffer; } #define MAX_SCAN_LENGTH 1024 int main() { char s[MAX_SCAN_LENGTH]; printf("Enter a string: "); scan_line(s, MAX_SCAN_LENGTH); printf("got: \"%s\"\n\n", s); return 0; } < edited Sep 30 '16 at 16:37 Stephen Leppik 2,57341333 answered Sep 29 '16 at 23:52 ----------------------------------------------------------------------------------- *c_library_function__toupper()* +---------------------------------+~ | C library function - toupper() |~ +---------------------------------+~ Description~ The C library function int toupper(int c) converts lowercase letter to uppercase. Declaration~ Following is the declaration for toupper() function. > int toupper(int c); < Parameters~ c ----- This is the letter to be converted to uppercase. Return Value~ This function returns uppercase equivalent to c, if such value exists, else c remains unchanged. The value is returned as an int value that can be implicitly casted to char. Example~ The following example shows the usage of toupper() function. > #include #include int main() { int i = 0; char c; char str[] = "Tutorials Point"; while(str[i]) { putchar (toupper(str[i])); i++; } return(0); } < ----------------------------------------------------------------------------------- *How_to_clear_input_buffer_in_C?* +---------------------------------+~ | How to clear input buffer in C? |~ +---------------------------------+~ source: http://stackoverflow.com/questions/7898215/how-to-clear-input-buffer-in-c I have the following program: > int main(int argc, char *argv[]) { char ch1, ch2; printf("Input the first character:"); // Line 1 scanf("%c", &ch1); printf("Input the second character:"); // Line 2 ch2 = getchar(); printf("ch1=%c, ASCII code = %d\n", ch1, ch1); printf("ch2=%c, ASCII code = %d\n", ch2, ch2); system("PAUSE"); return 0; } < As the author of the above code have explained: The program will not work properly because at Line 1, when the user presses Enter, it will leave in the input buffer 2 character: Enter key (ASCII code 13) and \n (ASCII code 10). Therefore, at Line 2, it will read the \n and will not wait for the user to enter a character. OK, I got this. But my first question is: Why the second getchar() (ch2 = getchar();) does not read the Enter key (13), rather than \n character? Next, the author proposed 2 ways to solve such probrems: use fflush() write a function like this: > void clear (void) { while ( getchar() != '\n' ); } < This code worked actually. But I cannot explain myself how it works? Because in the while statement, we use getchar() != '\n', that means read any single character except '\n'? if so, in the input buffer still remains the '\n' character? -------------------- > The program will not work properly because at Line 1, when the user presses Enter, it will leave in the input buffer 2 character: Enter key (ASCII code 13) and \n (ASCII code 10). Therefore, at Line 2, it will read the \n and will not wait for the user to enter a character. < The behavior you see at line 2 is correct, but that's not quite the correct explanation. With text-mode streams, it doesn't matter what line-endings your platform uses (whether carriage return (0x0D) + linefeed (0x0A), a bare CR, or a bare LF). The C runtime library will take care of that for you: your program will see just '\n' for newlines. If you typed a character and pressed enter, then that input character would be read by line 1, and then '\n' would be read by line 2. See I'm using scanf %c to read a Y/N response, but later input gets skipped. from the comp.lang.c FAQ. As for the proposed solutions, see (again from the comp.lang.c FAQ): - How can I flush pending input so that a user's typeahead isn't read at the next prompt? Will fflush(stdin) work? - If fflush won't work, what can I use to flush input? which basically state that the only portable approach is to do: > while ((c = getchar()) != '\n' && c != EOF) { } < Your getchar() != '\n' loop works because once you call getchar(), the returned character already has been removed from the input stream. Also, I feel obligated to discourage you from using scanf entirely: |Why_does_everyone_say_not_to_use_scanf__What_should_I_use_instead?| -------------------- You can do it (also) this way: > fseek(stdin,0,SEEK_END); shareimprove this answer answered Mar 17 '12 at 13:36 < Ramy Al Zuhouri 14.4k1771129 ----- Thanks, works perfect! – Shail May 25 '13 at 6:54 Wow... btw, does standard say fseek is available for stdin? – ikh May 22 '14 at 11:03 ----- I don't know, I think it doesn't mention it, but stdin is FILE* and fseek accepts a FILE* parameter. I tested it and it works on Mac OS X but not on Linux. – Ramy Al Zuhouri May 22 '14 at 11:07 ----- not portable - see docu – A. Binzxxxxxx Oct 20 '15 at 12:49 ------ @EvAlex: there are many issues with this. If it works on your system, great; if not, then it is not surprising as nothing guarantees that it will work when standard input is an interactive device (or a non-seekable device like a pipe or a socket or a FIFO, to name but a few other ways in which it can fail). – Jonathan Leffler Sep 15 '16 at 5:08 -------------------- The lines: > int ch; while ((ch = getchar()) != '\n' && ch != EOF) ; < doesn't read only the characters before the linefeed ('\n'). It reads all the characters in the stream (and discards them) up to and including the next linefeed (or EOF is encountered). For the test to be true, it has to read the linefeed first; so when the loop stops, the linefeed was the last character read, but it has been read. As for why it reads a linefeed instead of a carriage return, that's because the system has translated the return to a linefeed. When enter is pressed, that signals the end of the line... but the stream contains a line feed instead since that's the normal end-of-line marker for the system. That might be platform dependent. Also, using fflush() on an input stream doesn't work on all platforms; for example it doesn't generally work on Linux. edited Sep 15 '16 at 5:10 ----- Note: while ( getchar() != '\n' ); is an infinite loop should getchar() return EOF due to end-of-file. – chux Sep 10 '15 at 15:14 ----- To check for EOF as well, int ch; while ((ch = getchar()) != '\n' && ch != EOF); can be used – Dmitri Sep 11 '15 at 5:45 -------------------- A portable way to clear up to the end of a line that you've already tried to read partially is: > int c; while ( (c = getchar()) != '\n' && c != EOF ) { } < This reads and discards characters until it gets \n which signals the end of the file. It also checks against EOF in case the input stream gets closed before the end of the line. The type of c must be int (or larger) in order to be able to hold the value EOF. There is no portable way to find out if there are any more lines after the current line (if there aren't, then getchar will block for input). -------------------- > But I cannot explain myself how it works? Because in the while statement, we use getchar() != '\n', that means read any single character except '\n'?? if so, in the input buffer still remains the '\n' character??? Am I misunderstanding something?? < The thing you may not realize is that the comparison happens after getchar() removes the character from the input buffer. So when you reach the '\n', it is consumed and then you break out of the loop. --------------------- you can try > scanf("%c%*c", &ch1); where %*c accepts and ignores the newline < one more method instead of fflush(stdin) which invokes undefined behaviour you can write > while((getchar())!='\n'); < don't forget the semicolon after while loop ----- 1) "%*c" scans any character ( and does not save it), be it a newline or something else. Code is relying on that the 2nd character is a new line. 2) while((getchar())!='\n'); is an infinite loop should getchar() return EOF due to end-of-file. – chux Sep 10 '15 at 15:12 ----- the second method depends on the condition like newline,null character,EOF etc(above it was newline) – kapil -------------------- > unsigned char a=0; if(kbhit()){ a=getch(); while(kbhit()) getch(); } cout<(a) & 0xFF)< and only available as standard on Windows. They can be emulated on Unix-like machines, but doing so requires some care. – Jonathan Leffler Sep 15 '16 at 5:42 ----------------------------------------------------------------------------------- *Why_does_everyone_say_not_to_use_scanf__What_should_I_use_instead?* +--------------------------------------------------------------------+~ | Why does everyone say not to use scanf? What should I use instead? |~ +--------------------------------------------------------------------+~ Q: Why does everyone say not to use scanf? What should I use instead? A: scanf has a number of problems--see questions 12.17, 12.18a, and 12.19. Also, its %s format has the same problem that gets() has (see question 12.23)--it's hard to guarantee that the receiving buffer won't overflow. [footnote] More generally, scanf is designed for relatively structured, formatted input (its name is in fact derived from ``scan formatted''). If you pay attention, it will tell you whether it succeeded or failed, but it can tell you only approximately where it failed, and not at all how or why. You have very little opportunity to do any error recovery. Yet interactive user input is the least structured input there is. A well-designed user interface will allow for the possibility of the user typing just about anything--not just letters or punctuation when digits were expected, but also more or fewer characters than were expected, or no characters at all (i.e. just the RETURN key), or premature EOF, or anything. It's nearly impossible to deal gracefully with all of these potential problems when using scanf; it's far easier to read entire lines (with fgets or the like), then interpret them, either using sscanf or some other techniques. (Functions like strtol, strtok, and atoi are often useful; see also questions 12.16 and 13.6.) If you do use any scanf variant, be sure to check the return value to make sure that the expected number of items were found. Also, if you use %s, be sure to guard against buffer overflow. Note, by the way, that criticisms of scanf are not necessarily indictments of fscanf and sscanf. scanf reads from stdin, which is usually an interactive keyboard and is therefore the least constrained, leading to the most problems. When a data file has a known format, on the other hand, it may be appropriate to read it with fscanf. It's perfectly appropriate to parse strings with sscanf (as long as the return value is checked), because it's so easy to regain control, restart the scan, discard the input if it didn't match, etc. Additional links: |longer_explanation_why_not_to_use_scanf_by_Chris_Torek| |longer_explanation_why_not_to_use_scanf_by_Steve_Summit__fflush_vs_gets| ----------------------------------------------------------------------------------- *longer_explanation_why_not_to_use_scanf_by_Chris_Torek* +--------------------------------------------------------+~ | longer explanation why not to use scanf by Chris Torek |~ +--------------------------------------------------------+~ Peter S. Shenkin wrote: >I know I'm being dense here, but could someone explain to me >what problem this person is trying to solve? I've read this >and the FAQ section posted by Dann Corbitt, and I still don't >get it. > >Why would you possibly want to discard the user's input, and >how in the world would you know what part to discard? The short answers are: “You don't, and you don't.” What is going on here is a kludge piled on top of an already “bad” (in some sense) program. Instead of fixing the actual problem, certain books that purport to teach C suggest fixing the symptoms. This is a bit like going in to the doctor with incipient pneumonia and being given a cough suppressant. The root of the problem is the use of scanf(). The scanf() function is a large and complex beast that often does something almost but not quite entirely unlike what you desired. The entire scanf() family works by interpreting “directives”. These directives are not well suited to interactive (“talking to a human”) input. In particular, a directive like “ ” or “\n” means: “skip as much input white space as you can find, INCLUDING NEWLINES.” Most conversion directives (including %d and %f) have an implicit skip as well. This means that if you print a prompt: > printf("please enter a number: "); fflush(stdout); < and then ask for input using `scanf("%d", &var)', and the human enters a blank line, the computer simply sits there, rather than re-prompting. The next problem is that the scanf() family tend to leave unconsumed input. Anything that does not “meet the requirements” is left in place. If the user, who is supposed to enter a number, enters “three” instead of “3”, the “t” does not meet the requirements for “%d”. The entire line (“three\n”) is left in the input stream. If the user does enter a number, such as “3”, only the newline is left in the stream. If the user enters a number followed by a blank (or tab or other whitespace), the blank and newline are both left in the stream. This characteristic (of leaving “extra” input behind as a trap to the unwary) leads people to write the “discard user's input” code. Unfortunately, they often use implementation-specific constructs like fflush(stdin), or broken ones like an unadorned getchar() or a scanf format like “%*[^\n]%*c”. To see why this last format is broken, read the next paragraphs. Another substantial problem with the scanf() functions is that they interpret directives sequentially, and stop as soon as they get a “matching failure”. This seems often to surprise people. In particular, consider the format directive “%*[^\n]”. This consists of several parts. The “%” introduces the conversion. The asterisk “*” suppresses assignment of the result of the conversion, so that no additional buffer is required. The “[” specifies that the conversion is to do a character-class match, the initial “^” inverts the class, and the class itself consists only of a single character, “\n”. The “]” terminates the class and is the end of that directive. This directive thus means “match things that are not newlines”. The tricky bit here is that any %[ directive MUST MATCH AT LEAST ONE CHARACTER. If it fails to match at least one character, the scan terminates. The call returns without looking at any further directives. Thus, if the next input character is a newline, this “%*[” directive fails, and the “%*c” NEVER OCCURS. The format sequence “%*[^\n]%*c” only clears out the rest of a line if there is at least one character before the newline. This problem can be fixed (as others noted) by using two separate calls. An initial scanf() with “%*[^\n]” will either eat everything up to but not including a newline, or fail. A subsequent “%*c” (or plain old getchar()) will consume the newline, if there was one. That last “if” matters too: perhaps the user signalled EOF. In this case, the getchar() or scanf("%*c") might -- this decision is left to the people who write your compiler -- either immediately return EOF, or go back to the user for more input. If the implementors choose the latter, the user might have to click on “end this thing” (^D, ^Z, mouse button, front panel switch, or whatever) one extra time. This is annoying, if nothing else. (Incidentally, offhand, I think %[ and %c are the only two directives that do not immediately skip whitespace, including newlines.) So what is the “right” answer? There are various ways to do this. You can write horrendously complicated code using getchar, ungetc, and scanf, carefully checking all the return values. You can call fgets() to read a complete line, then -- having “sandboxed” it, as it were, use sscanf() and not worry too much about bad input. You can call fgets() and use strtol() and other string-parsing functions. The simpler approaches all share one common characteristic, though: they first read a complete line (including the terminating newline), and only then try to pick it apart. That gives users time to mull over their answer, type something in, erase it, type something else, erase that, think a bit more, and then give Regis Philbin their “final answers” by pressing ENTER or RETURN. :-) You then get the whole thing at once, and can dissect it as needed. -- In-Real-Life: Chris Torek, Berkeley Software Design Inc El Cerrito, CA, USA http://claw.bsdi.com/torek/ (not always up) I report spam to abuse@ ----------------------------------------------------------------------------------- *longer_explanation_why_not_to_use_scanf_by_Steve_Summit__fflush_vs_gets* +-------------------------------------------------------------------------+~ | longer_explanation_why_not_to_use_scanf_by_Steve_Summit__fflush_vs_gets |~ +-------------------------------------------------------------------------+~ From: Steve Summit Subject: Re: fflush vs gets Date: 2000/02/12 Message-ID: Newsgroups: comp.lang.c,comp.lang.c.moderated Peter S. Shenkin wrote: > Why would you possibly want to discard the user's input, > and how in the world would you know what part to discard? It's likely that you've never tried to call scanf and gets in the same program. If you haven't, you're blissfully unaware of this messy little problem. Suppose you write this trivial program: > #include int main() { int i; char string[80]; printf("enter an integer:\n"); scanf("%d", &i); printf("enter a string:\n"); gets(string); printf("You typed %d and \"%s\"\n", i, string); return 0; } < Looks perfectly straightforward, right? But if you compile and run it (which I encourage you to do, if you're still unfamiliar with this problem), you'll see something weird, and you will find yourself (I guarantee it) asking question 12.18 in the comp.lang.c FAQ list: “I'm reading a number with scanf %d and then a string with gets(), but the compiler seems to be skipping the call to gets()!” (We'll have more to say later about using gets at all, but hold that thought.) Let's look very carefully at what happens. The first printf call prints the first prompt, and we type “123” and hit the return key. The input stream now contains 1 2 3 \n Now we hit the scanf call, and scanf sees the format string %d indicating that we've asked it to read an int. It reads the character '1' from the input stream and says to itself “okay, that's a digit, so it can be part of an int.” It reads the characters '2' and '3', and they're digits, too. The next character is '\n', which is not a digit. So scanf does two things: It terminates processing of the %d directive; it now knows that the complete integer it has read is 123; it stores this value as requested into the location of the variable i. (This is the key point.) It pushes the \n character, which terminated the digit string but which it didn't otherwise use, back onto the input stream. So after the first scanf call, the input stream contains \n Now the second printf call prints the second prompt. Suppose we type “test” and hit the enter key. The input stream now contains \n t e s t \n So now we come to the gets call. gets's job, of course, is to read one line of input, up to the next newline. But the very first character gets sees is a \n, so as far as it's concerned it's just read a blank line. It returns that blank line (an empty string, since gets always deletes the newline from the line before returning it to you), and the input stream is left containing t e s t \n The third printf call prints the (somewhat surprising) results of the two inputs, and the program terminates, with the string “test” and the final newline unconsumed. If this still isn't quite making sense, try running the program again, and typing something more than a number in response to the first prompt. That is, try typing “123 abc” or “123abc”, and then hitting the return key, when asked to “enter an integer”. (Actually, the above description isn't quite right. No matter what you type on the first line, the input stream after the first scanf call still contains a \n, so the gets call reads it right away, without pausing for you to enter anything more. So you don't really get a chance to type “test” at all. To answer the FAQ list's question another way, the problem is not that the compiler somehow “skips” the gets call, the problem is that the gets call satisfies its need for input in an unexpected way, and skips the part about pausing the program to wait for you to type anything more.) With the scenario above as background, we can now answer your question, “Why would you possibly want to discard the user's input?” For better or worse, many beginning programmers use scanf to read numbers and gets to read strings. This is in large part, of course, because these functions are taught early in many books and programming classes. And this, in turn, is because these functions are superficially and seductively attractive; they seem very easy and convenient to use. But they don't play at all well together (plus they have some other problems, which we'll get to). When the beginning programmer writes a program like the above and discovers that it doesn't work quite right, he is likely to receive the handwaving explanation (from the instructor or the textbook author) that there is some “garbage left behind on the input stream by scanf”. (We, who understand the situation more accurately, now know that the “garbage” is, in the example we walked through, simply the \n that resulted from our hitting the return key after entering the requested number.) To allow further input to proceed as expected, these instructors and authors go on to explain, the “garbage” must be “discarded”. One all-too-popular (and, again, superficially attractive) way of doing this is to call fflush(stdin), despite the fact that this is a misguided application of the standard fflush function, an application that is not guaranteed to (and in fact most certainly does not) work everywhere. But it “works” under a large number of popular PC C compilers, so the “idiom” is, unfortunately, widespread. What's the right solution? It's extremely easy to get stuck on the fact that fflush(stdin), for some presumably stupid and pedantic reason, is not guaranteed to work everywhere. One then starts casting about looking for a “portable” replacement. The problem is that, depending on precisely what one is trying to do, there are quite a few different tacks one might take in attempting to write some well-defined or portable code to “discard garbage from stdin”. (In the general case, as you correctly ask, “How in the world would [one] know what part to discard?”) If the definition of the “garbage from stdin” that we're trying to discard is “input from the previous line which wasn't consumed by scanf”, it turns out that there are a couple of not entirely unreasonable approaches. We could write the loop > while((c = getchar()) != '\n' && c != EOF) /* discard the character */; < to read and discard characters up to the next newline. (Notice that the comment “/* discard the character */” in this fragment does not stand in for some code I didn't write yet -- it stands in for some code I deliberately didn't write at all. The body of the loop is empty; we do nothing with the characters we're reading, thus discarding them. The \n which terminates the loop is discarded, too.) Since that loop would clutter our code pretty badly if we had to interpose it after every scanf call, we might encapsulate it into a function we could call, perhaps called “flushline” or something. Or, recognizing that “read characters up to a newline” is precisely what the Standard functions gets and fgets already do, we might simply interpose calls to gets or fgets, reading into a dummy buffer which we ignore (and hence discard), perhaps accompanied by comments explaining that these dummy calls are to “get rid of the garbage left behind by scanf”. But these are still ugly, unclean, unsatisfying solutions. It won't be long before one of our scanf calls, for some reason, does consume a newline character after all, such that our compensating “read and discard characters up to the next newline” code will read and discard the next line of input, a real line of input, which will then be lost to the input-reading code which expected it. We could try to predict which scanf calls will and which scanf calls won't leave “garbage behind”, and sprinkle “flushline” calls after only those scanf calls which need them, but this is a hit-or-miss proposition, and a later reader will never be able to understand precisely what we're up to. There's got to be a better way. The “better way”, as indicated in the FAQ list, is either to abandon scanf entirely, or to use it exclusively. If your input is intended to be line-based, you can read all lines of input as strings, using fgets or the like, and for those that were supposed to be numeric, convert the strings to numbers using functions like atoi, strtol, atof, or maybe even sscanf. (This is the general approach I recommend.) Or, since the problem is that it's scanf that does Not Play Well With Others, you can switch to a scheme where you use scanf for everything, using it to read your strings, too (with %s or the like). Finally, I should add a couple of postscripts. It turns out that scanf has other problems besides the fact that it tends to leave little undigested “surprises” on the input stream, so there are other reasons to consider abandoning it. And, of course, as discussed at length in comp.lang.c of late, gets has a fatal problem which counterindicates its use for much of anything. Steve Summit scs@eskimo.com Programming Challenge #5: Love your abstractions. See http://www.eskimo.com/~scs/challenge/.