mersenneforum.org  

Go Back   mersenneforum.org > Extra Stuff > Programming

Reply
 
Thread Tools
Old 2012-02-24, 12:48   #188
axn
 
axn's Avatar
 
Jun 2003

117378 Posts
Default

Quote:
Originally Posted by Dubslow View Post
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.
Immediately after the first scanf, try a getchar() to swallow the newline you entered.
axn is offline   Reply With Quote
Old 2012-02-24, 17:39   #189
jyb
 
jyb's Avatar
 
Aug 2005
Seattle, WA

2·883 Posts
Default

Quote:
Originally Posted by Dubslow View Post

[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:
Originally Posted by axn View Post
Immediately after the first scanf, try a getchar() to swallow the newline you entered.
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.
jyb is offline   Reply With Quote
Old 2012-02-24, 22:48   #190
Dubslow
Basketry That Evening!
 
Dubslow's Avatar
 
"Bunslow the Bold"
Jun 2011
40<A<43 -89<O<-88

3×29×83 Posts
Default

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 this. 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?)

Last fiddled with by Dubslow on 2012-02-24 at 22:57
Dubslow is offline   Reply With Quote
Old 2012-02-24, 22:56   #191
chalsall
If I May
 
chalsall's Avatar
 
"Chris Halsall"
Sep 2002
Barbados

978210 Posts
Default

Quote:
Originally Posted by Dubslow View Post
Then it occurred to be that an fgets(NULL,...) call will work fine.
No it won't....
chalsall is online now   Reply With Quote
Old 2012-02-24, 22:57   #192
Dubslow
Basketry That Evening!
 
Dubslow's Avatar
 
"Bunslow the Bold"
Jun 2011
40<A<43 -89<O<-88

3×29×83 Posts
Default

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   : ");
This works exactly as intended and exactly how I think it should work.

Last fiddled with by Dubslow on 2012-02-24 at 23:13
Dubslow is offline   Reply With Quote
Old 2012-02-24, 23:08   #193
chalsall
If I May
 
chalsall's Avatar
 
"Chris Halsall"
Sep 2002
Barbados

2·67·73 Posts
Default

Quote:
Originally Posted by Dubslow View Post
I can use fgets and just not use the info, even if that's not the right way to do it.
But you have to put the info somewhere defined, even if you don't plan to use it. Your above would have unpredictable (and probably fatal) behaviour.
chalsall is online now   Reply With Quote
Old 2012-02-24, 23:25   #194
Dubslow
Basketry That Evening!
 
Dubslow's Avatar
 
"Bunslow the Bold"
Jun 2011
40<A<43 -89<O<-88

3×29×83 Posts
Default

Seg fault, to be precise
Dubslow is offline   Reply With Quote
Old 2012-02-25, 00:34   #195
jyb
 
jyb's Avatar
 
Aug 2005
Seattle, WA

2×883 Posts
Default

Quote:
Originally Posted by Dubslow View Post
I did google sscanf, and got this. 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?)
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.
jyb is offline   Reply With Quote
Old 2012-02-25, 00:36   #196
jyb
 
jyb's Avatar
 
Aug 2005
Seattle, WA

2×883 Posts
Default

Quote:
Originally Posted by Dubslow View Post
This works exactly as intended and exactly how I think it should work.
Except you still have a memory leak, and you can't handle input strings longer than MAXSTRLEN.
jyb is offline   Reply With Quote
Old 2012-02-25, 00:45   #197
Dubslow
Basketry That Evening!
 
Dubslow's Avatar
 
"Bunslow the Bold"
Jun 2011
40<A<43 -89<O<-88

3·29·83 Posts
Default

Yessir, thank you sir, will do sir

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];
and I want to measure the size of arr, can I just use
Code:
sizeof(arr) // ==80?
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?)

Last fiddled with by Dubslow on 2012-02-25 at 01:38
Dubslow is offline   Reply With Quote
Old 2012-02-25, 01:12   #198
jyb
 
jyb's Avatar
 
Aug 2005
Seattle, WA

176610 Posts
Default

Quote:
Originally Posted by Dubslow View Post
Yessir, thank you sir, will do sir
Hey, it's just a suggestion. Take it or leave it.

Quote:
Originally Posted by Dubslow View Post
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?).
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:
Originally Posted by Dubslow View Post
Quick question: What does realloc(ptr,n) do if( n<sizeof(ptr) ) ? Does it return ptr?
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.
jyb is offline   Reply With Quote
Reply

Thread Tools


All times are UTC. The time now is 15:29.


Fri Aug 6 15:29:02 UTC 2021 up 14 days, 9:58, 1 user, load averages: 2.60, 2.93, 2.92

Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2021, Jelsoft Enterprises Ltd.

This forum has received and complied with 0 (zero) government requests for information.

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation.
A copy of the license is included in the FAQ.