![]() |
[QUOTE=Dubslow;290698]I think I've got at least part of the problem. I disabled the scanf and hardcoded in a shift value; then the string prompt paused just fine for me without looping or exiting.[/QUOTE]
Immediately after the first scanf, try a getchar() to swallow the newline you entered. |
[QUOTE=Dubslow;290687]
[code and output snipped] Compiled with gcc -Wall. I can provide a plaintext webpage version if you want (will use more screen, easier to read). As I said before, when it couldn't catch blank input, it cycled once then stopped the second time, but not the first time through the while(1) loop. For context, this is evolved from a Java assignment that was due on Monday. I'm trying to fulfill the specifications using C, so that my C doesn't fall behind Java.[/QUOTE] [QUOTE=axn;290716]Immediately after the first scanf, try a getchar() to swallow the newline you entered.[/QUOTE] axn has it right. The problem is that your scanf does not read an entire line. It reads up to the end of the first number it finds, then stops. So when you later call fgets, the first thing it sees is a newline and nothing else. The problem with just calling getchar is that you don't really know if there's anything else on that first line after the number. E.g. if there's a space after it, then you'll have the same problem. The real solution is to let your code match your conception of what the program is doing. That is, you're trying to have your program operate in an inherently line-by-line fashion. So your code should work in a line-by-line way as well. The usual way to do something like that is to always read whole lines (using fgets, or if you're really concerned about truncating lines that are too long, using a function of your own devising which reads a whole line and returns it, as we discussed before). Once you've read the line containing the shift count, use sscanf to read the number out of it. Then, when you go to read the source text you will be ready to read a whole new line of input. And BTW, you should check out the isupper and islower functions, defined in ctype.h. |
Yes, most of that occurred to me while I was in bed trying to sleep. My next question was going to be "Is there a function to clear the stdin, or do I just have to use the getchar() and assume the input is as requested?" Then it occurred to be that an fgets(NULL,...) call will work fine.
I did google sscanf, and got [url=http://crasseux.com/books/ctutorial/sscanf.html]this[/url]. Apparently scanf is deprecated? The read-a-whole-line than search for what you want does seem to be a better method, not only because of the whole-line-ness but also the error catching. Good to know, thanks again. (Edit: What's the difference between fgets and getline?) |
[QUOTE=Dubslow;290758]Then it occurred to be that an fgets(NULL,...) call will work fine.[/QUOTE]
No it won't.... |
I can use fgets and just not use the info, even if that's not the right way to do it.
Scratch that. Just gonna read the whole line than sscanf the string for shift, as suggested above. Edit2: [code] char * scan = (char *)malloc( MAXSTRLEN * sizeof(char)); do { printf("Please enter the shift value (between -25..-1 and 1..25)\n"); fgets( scan, MAXSTRLEN, stdin); badin = (sscanf(scan, "%d", &shift) != 1) || ( !(((-25 <= shift) && (shift <= -1)) || ((1 <= shift) && (shift <= 25))) ); /* A somewhat obfuscated line of code; if shift is not in [-25,-1]U[1,25] OR sscanf didn't assign correctly, then badin is set to true. */ if (shift == 999) { secret = 1; badin = 0; } else if (shift == -999) { usecret = 1; badin = 0; } if (badin) printf("%d is not a valid shift value.\n", shift); } while (badin); if (secret || usecret) printf("Using position shift\n"); else printf("Using shift value of %d\n", shift); if (shift < 0) shift += 26; while (1) { printf("Please enter the source text (empty line to quit)\n"); char * string = (char *)malloc( MAXSTRLEN * sizeof(char)); fgets(string, MAXSTRLEN, stdin); i = (int)strlen(string); if( i == (MAXSTRLEN - 1) ) { // Then the string is longer than MAXSTRLEN - 1, and so the rest is lost. printf("Source is longer than %d characters. The rest is lost.\n", MAXSTRLEN-1); // will add in realloc later once the behavior is correct } if ( string[0]=='\n' ) { // The entire string is null, or rather, the only character was \n, so no input. printf("Bye.\n"); return 7; } printf("Source : ");[/code] This works exactly as intended and exactly how I think it should work. |
[QUOTE=Dubslow;290761]I can use fgets and just not use the info, even if that's not the right way to do it.[/QUOTE]
But you have to put the info somewhere [B][I][U]defined[/U][/I][/B], even if you don't plan to use it. Your above would have unpredictable (and probably fatal) behaviour. |
Seg fault, to be precise :smile:
|
[QUOTE=Dubslow;290758]I did google sscanf, and got [url=http://crasseux.com/books/ctutorial/sscanf.html]this[/url]. Apparently scanf is deprecated? The read-a-whole-line than search for what you want does seem to be a better method, not only because of the whole-line-ness but also the error catching. Good to know, thanks again. (Edit: What's the difference between fgets and getline?)[/QUOTE]
Hmm, never seen that site before, but I'm not a fan: 1) scanf is not deprecated, at least in any official sense that I'm aware of. 2) It doesn't make clear that getline is not part of the standard library, while the other functions mentioned are. I.e. any C implementation will always have things like scanf and fgets available, but some will not have getline, and even worse, some will have getline but have it defined differently. 3) The functions which this site describes as deprecated *can* be used unsafely, but need not be. E.g. it gives an example of how using scanf with a bare %s conversion can be unsafe. However, it is entirely possible to use scanf in safe ways. Similarly, there's nothing unsafe about fgets when used correctly. It can be a pain to use, but it can be used with complete safety. By contrast, gets can *never* be used safely, and the advice to avoid it is good. At any rate, I will reiterate what I said earlier about reading a line at a time. In fact, I'll go further. As an exercise, you should write the implementation of the following function: char *ReadLine(FILE *stream); It should read exactly one line (as delimited by the '\n' character) from the given stream, consuming that '\n' but not placing it in the returned array. The return value will be a pointer to an array exactly long enough to hold the entire line (including a trailing '\0' but minus the '\n'), allocated with malloc. There should be no limit on the size of line that it can handle (other than exhausting the machine's memory). It will be the caller's responsibility to free this array when (s)he is done with it. If there are no characters at all left in the stream when it is called (i.e. it's at EOF), it should return NULL. Compare this to the case where the first character it reads is a newline; what should it return in that case? I think you will find it to be instructive to write this function, and you may also find it very useful for exactly the kind of program you're trying to write now. |
[QUOTE=Dubslow;290761]
This works exactly as intended and exactly how I think it should work.[/QUOTE] Except you still have a memory leak, and you can't handle input strings longer than MAXSTRLEN. |
Yessir, thank you sir, will do sir :smile:
Thanks for pointing out the mem leak, I certainly didn't catch it. However, moving the declaration outside the loop should be sufficient to fix it (right?). Quick question: What does realloc(ptr,n) do if( n<sizeof(ptr) ) ? Does it return ptr? Quick question 2: If I have [code]char arr[80];[/code] and I want to measure the size of arr, can I just use [code]sizeof(arr) // ==80?[/code] or do I have to somehow cast the result of sizeof? I ask because I don't really know how to properly use a size_t. Edit: A quick google makes it seem there's no way to use sizeof to find the size of a chunk of memory; it seems I have to keep track of it myself. Is this correct? Quick question 3: What happens if I get an EOF before \n? Just fill in the \0? (And, further, if the first char is \n, do I return a one-char string "\0" or NULL?) |
[QUOTE=Dubslow;290775]Yessir, thank you sir, will do sir :smile:
[/QUOTE] Hey, it's just a suggestion. Take it or leave it. :smile: [QUOTE=Dubslow;290775] Thanks for pointing out the mem leak, I certainly didn't catch it. However, moving the declaration outside the loop should be sufficient to fix it (right?). [/QUOTE] I don't know which declaration you mean, but the answer is going to be no regardless. You're doing a malloc, which means there needs to be a corresponding free at some point. Moving declarations around won't change that. [QUOTE=Dubslow;290775] Quick question: What does realloc(ptr,n) do if( n<sizeof(ptr) ) ? Does it return ptr?[/QUOTE] I'm not sure what you're trying to ask here. Do you mean if n is less than the size of the allocated space which ptr is pointing to? I'll assume yes, because otherwise your question doesn't really make sense. But be aware that the existing allocated space is quite different from sizeof(ptr), the latter being just the size of ptr itself (probably 4 or 8, depending on your architecture). Anyway, this call to realloc sets the allocated size to n, regardless of how big the allocated space was before.* If that means the allocated space shrinks, then any data you had beyond byte n is lost. Does that answer your question? *This assumes that realloc is actually able to satisfy the request. In practice this will always be true if you're trying to shrink the space. If you're trying to grow it, then it's possible that there's no block of contiguous space of the requested size, in which case realloc will return NULL, leaving the space still allocated. |
| All times are UTC. The time now is 22:24. |
Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2021, Jelsoft Enterprises Ltd.