mersenneforum.org  

Go Back   mersenneforum.org > Extra Stuff > Programming

Reply
 
Thread Tools
Old 2012-02-25, 01:18   #199
Dubslow
Basketry That Evening!
 
Dubslow's Avatar
 
"Bunslow the Bold"
Jun 2011
40<A<43 -89<O<-88

3·29·83 Posts
Default

I meant if you're requesting less space, it will return the pointer you passed it?

Also, I've since edited more questions into my post (before I saw you had replied :P)
Dubslow is offline   Reply With Quote
Old 2012-02-25, 02:09   #200
Dubslow
Basketry That Evening!
 
Dubslow's Avatar
 
"Bunslow the Bold"
Jun 2011
40<A<43 -89<O<-88

3·29·83 Posts
Default

Okay, I've either sidestepped or answered my questions.
Code:
char* ReadLine(FILE * stream) {	
	/* I don't actually have any idea what the argument prototype means, other than that "stdin" and "stdout" are legal ("stderr" as well?).
	 * Also, I don't think there's a way for me to use fgets() without being able to catch a \n, so I've hand coded it with getchar().
	 * This function returns a pointer to the array where the line is stored. The array is guaranteed to be exactly as long as the string.
	 * This requires the inclusion of <stdio.h> and <stdlib.h>.
	 */
	 
	 long int size=20;	// This determines the minumum mem required; if it's too low though, then you have to loop more often to increase dynamically.
	 			// (Use a long in case you have a  >4GiB string :] )
	 int i=1;
	 char* input = (char*)malloc( size*sizeof(char));
	 if( input == NULL ) {
	 	printf("Error, out of memory!\n");	/* I think I should be using some sort of stderr here, but I don't actually know too much about I/O, */
		return NULL;				/* I'm just trying to practice with strings. 	*/
	 }
	if( ((input[0]=getchar()) == EOF) || (input[0]=='\n') )
	 	return NULL;
	 	
	 while(1) {	// This loop is broken when '\n' is read, and then we return out of the function (or mem error returns NULL).
	 	
	 	for(/* The first time through i==1 */ ; i<(size - 1); i++) {
	 		if( (input[i] = getchar()) == '\n' || ( input[i] == EOF ) ) {
				input[i] = 0;
				input = (char*)realloc( input, (i+1)*sizeof(char) );
				if( input == NULL ) {
					printf("Error, out of memory!\n");
					return NULL;
				}
				return input;
			}
		}
		if( ((input[i]=getchar()) != '\n') &&  (input[i] != EOF) ) {
			input = (char*)realloc( input, 2*size*sizeof(char) );	// Follow bsquared's usual practice.
			if( input == NULL ) {
				printf("Error, out of memory!\n");
				return NULL;
			}
			i++;	// We're at i==size, continue reading at i==(size+1)
		} // skip to end while, continue reading in input up above
		else { input[i] = 0; return input; }
	} // end while
} // end function
Edit: To go with it, a re-done cypher.c:
Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* A program to take a string, and create its Ceasar Cypher using a shift value input by the user.
 * (Entering 999 or -999 uses a letter's position as its shift value instead.)
 */

char* ReadLine(FILE * stream);

int isULetter(char c) {	// boolean
	if ('A' <= c && c <= 'Z')
		return 1;
	else
		return 0;
}

int isLLetter(char c) {	// boolean
	if ('a' <= c && c <= 'z')
		return 1;
	else
		return 0;
}

int main(void) {
	int shift, size;
	int badin; 	// boolean
	int secret = 0;	// boolean
	int usecret = 0;// boolean
	int i; // index
	char c;
	char* scan = (char *)malloc( 10 * sizeof(char));
	char* string;
	char* code;
	do {
		printf("Please enter the shift value (between -25..-1 and 1..25)\n");
		fgets( scan, 10, 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);
	free(scan);
	
	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");
		string = ReadLine(stdin);
		if ( string == NULL ) {		// Either there was an error, or blank input. (Error message would be printed if there was one.)
			printf("Bye.\n");
			return 7;
		}
		size = (int)strlen(string);
		
		printf("Source   : ");
		puts(string);
		
		code = (char *)malloc( size * sizeof(char));
		for ( i=0; ((c=string[i])!=0) && (i<size) ; i++) {
			if ( isULetter(c) ) {
				if (secret) {
					c = (char) ('A' + ((c - 'A' + i) % 26));
				} else if (usecret) {
					c = (char) ('A' + ((c - 'A' + (26 - (i % 26))) % 26));
				} else {
					c = (char) ('A' + ((c - 'A' + shift) % 26));
				}
			} else if ( isLLetter(c) ) {
				if (secret) {
					c = (char) ('a' + ((c - 'a' + i) % 26));
				} else if (usecret) {
					c = (char) ('a' + ((c - 'a' + (26 - (i % 26))) % 26));
				} else {
					c = (char) ('a' + ((c - 'a' + shift) % 26));
				}
			}
			code[i] = c;
		}
		
		printf("Processed: ");
		puts(code);
		
	} // while
} // main

char* ReadLine(FILE * stream) {	
	/* I don't actually have any idea what the argument prototype means, other than that "stdin" and "stdout" are legal ("stderr" as well?).
	 * Also, I don't think there's a way for me to use fgets() without being able to catch a \n, so I've hand coded it with getchar().
	 * This function returns a pointer to the array where the line is stored. The array is guaranteed to be exactly as long as the string.
	 * This requires the inclusion of <stdio.h> and <stdlib.h>.
	 */
	 
	 long int size=20;	// This determines the minumum mem required; if it's too low though, then you have to loop more often to increase dynamically.
	 			// (Use a long in case you have a  >4GiB string :] )
	 int i=1;
	 char* input = (char*)malloc( size*sizeof(char));
	 if( input == NULL ) {
	 	printf("Error, out of memory!\n");	/* I think I should be using some sort of stderr here, but I don't actually know too much about I/O, */
		return NULL;				/* I'm just trying to practice with strings. 	*/
	 }
	 if( ((input[0]=getchar()) == EOF) || (input[0]=='\n') )
	 	return NULL;
	 	
	 while(1) {	// This loop is broken when '\n' is read, and then we return out of the function (or mem error returns NULL).
	 	
	 	for(/* The first time through i==1 */ ; i<(size - 1); i++) {
	 		if( (input[i] = getchar()) == '\n' || ( input[i] == EOF ) ) {
				input[i] = 0;
				input = (char*)realloc( input, (i+1)*sizeof(char) );
				if( input == NULL ) {
					printf("Error, out of memory!\n");
					return NULL;
				}
				return input;
			}
		}
		if( ((input[i]=getchar()) != '\n') &&  (input[i] != EOF) ) {
			input = (char*)realloc( input, 2*size*sizeof(char) );	// Follow bsquared's usual practice.
			if( input == NULL ) {
				printf("Error, out of memory!\n");
				return NULL;
			}
			i++;	// We're at i==size, continue reading at i==(size+1)
		} // skip to end while, continue reading in input up above
		else { input[i] = 0; return input; }
	} // end while
} // end function

Last fiddled with by Dubslow on 2012-02-25 at 02:34
Dubslow is offline   Reply With Quote
Old 2012-02-25, 02:37   #201
Dubslow
Basketry That Evening!
 
Dubslow's Avatar
 
"Bunslow the Bold"
Jun 2011
40<A<43 -89<O<-88

1C3516 Posts
Default

Wha-oh.

Code:
bill@Gravemind:~/bin/c∰∂ cypher
Please enter the shift value (between -25..-1 and 1..25)
999
Using position shift
Please enter the source text (empty line to quit)
No one said I had to use English words :)
Source   : No one said I had to use English words :)
Processed: Np rrj zirn U vpt lh pob Dnhnlwm dwand :O
Please enter the source text (empty line to quit)

Bye.
bill@Gravemind:~/bin/c∰∂ cypher
Please enter the shift value (between -25..-1 and 1..25)
-999
Using position shift
Please enter the source text (empty line to quit)
Np rrj zirn fuoi Z auqa rn vuh uxvxnb Qauayjz qjnaq. :)
*** glibc detected *** cypher: realloc(): invalid next size: 0x00000000008b7010 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x76bb6)[0x7f68fb7f1bb6]
/lib/x86_64-linux-gnu/libc.so.6(+0x7b36b)[0x7f68fb7f636b]
/lib/x86_64-linux-gnu/libc.so.6(realloc+0xf9)[0x7f68fb7f7b19]
cypher[0x400d2a]
cypher[0x400940]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xff)[0x7f68fb799eff]
cypher[0x4006e9]
======= Memory map: ========
00400000-00402000 r-xp 00000000 08:16 2625368                            /home/bill/bin/c/cypher
00601000-00602000 r--p 00001000 08:16 2625368                            /home/bill/bin/c/cypher
00602000-00603000 rw-p 00002000 08:16 2625368                            /home/bill/bin/c/cypher
008b7000-008d8000 rw-p 00000000 00:00 0                                  [heap]
7f68f4000000-7f68f4021000 rw-p 00000000 00:00 0 
7f68f4021000-7f68f8000000 ---p 00000000 00:00 0 
7f68fb565000-7f68fb57a000 r-xp 00000000 08:16 8912963                    /lib/x86_64-linux-gnu/libgcc_s.so.1
7f68fb57a000-7f68fb779000 ---p 00015000 08:16 8912963                    /lib/x86_64-linux-gnu/libgcc_s.so.1
7f68fb779000-7f68fb77a000 r--p 00014000 08:16 8912963                    /lib/x86_64-linux-gnu/libgcc_s.so.1
7f68fb77a000-7f68fb77b000 rw-p 00015000 08:16 8912963                    /lib/x86_64-linux-gnu/libgcc_s.so.1
7f68fb77b000-7f68fb905000 r-xp 00000000 08:16 8913140                    /lib/x86_64-linux-gnu/libc-2.13.so
7f68fb905000-7f68fbb04000 ---p 0018a000 08:16 8913140                    /lib/x86_64-linux-gnu/libc-2.13.so
7f68fbb04000-7f68fbb08000 r--p 00189000 08:16 8913140                    /lib/x86_64-linux-gnu/libc-2.13.so
7f68fbb08000-7f68fbb09000 rw-p 0018d000 08:16 8913140                    /lib/x86_64-linux-gnu/libc-2.13.so
7f68fbb09000-7f68fbb0f000 rw-p 00000000 00:00 0 
7f68fbb0f000-7f68fbb30000 r-xp 00000000 08:16 8913137                    /lib/x86_64-linux-gnu/ld-2.13.so
7f68fbd03000-7f68fbd06000 rw-p 00000000 00:00 0 
7f68fbd2b000-7f68fbd2f000 rw-p 00000000 00:00 0 
7f68fbd2f000-7f68fbd30000 r--p 00020000 08:16 8913137                    /lib/x86_64-linux-gnu/ld-2.13.so
7f68fbd30000-7f68fbd32000 rw-p 00021000 08:16 8913137                    /lib/x86_64-linux-gnu/ld-2.13.so
7fff3ccd0000-7fff3ccf1000 rw-p 00000000 00:00 0                          [stack]
7fff3cd56000-7fff3cd57000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
Aborted
bill@Gravemind:~/bin/c∰∂
Wolfram says that 0x00000000008b7010 == 9.138 MB. The string is 56 characters, so based on 20, it would need to reallocate 2wice to a total of 80 bytes. Also, why would ) --> O?

Last fiddled with by Dubslow on 2012-02-25 at 02:50
Dubslow is offline   Reply With Quote
Old 2012-02-25, 03:56   #202
jyb
 
jyb's Avatar
 
Aug 2005
Seattle, WA

2·883 Posts
Default

Quote:
Originally Posted by Dubslow View Post
Wha-oh.
Yowza! Yeah, you've got some pretty bad bugs in your ReadLine function. But don't be discouraged! This was a good effort. I can tell you where some of your problems are, or I can let you debug it yourself. You'll probably learn more by doing the latter, but you might also get very frustrated. So how 'bout this: you see if you can figure out why your realloc calls are going awry. If you're stuck, let me know and I'll help.

BTW, there's only so much debugging you can do by code inspection. I suggest using a debugger to follow through your code in ReadLine. I think you'll quickly discover some of your errors, and you may also find some better ways to structure the code.

To answer some of your other questions from before:

- If you have an array declared as
Code:
char arr[80];
then yes, you can use sizeof to find out its size. The expression 'sizeof(arr)' will evaluate to 80. But be careful! sizeof is giving you a number of bytes, not the number of "slots" in the array. If it's an array of chars, as above, then each char is 1 byte (by definition, in C) so the number of bytes is the same as the number of elements. But if it's
Code:
int arr[80]
then 'sizeof(arr)' will be 80 times the size of an int (4 on most systems).

- The result of the sizeof operator is a type called size_t, as you mentioned. That's just an unsigned integer type. You can use it pretty much anywhere that an integer is needed/wanted (with some complications that we won't worry about here). You don't need to cast it in order to use it. So for example, you can say
Code:
int size;
size = sizeof(arr);

Quote:
Originally Posted by Dubslow View Post
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?
Well, it depends what you mean by "a chunk of memory". Sizeof can be used on declared arrays, like those in the above examples. But it can't be used on dynamic arrays which you allocate with malloc. For chunks of memory like that, you have to keep track yourself. One way to think about it is this: sizeof operates on the declared type of the expression you give it. In the above examples you were giving it something you declared as an array, so it could tell you the size of that array. But when you use malloc, it looks something like this:
Code:
char *ptr;
ptr = malloc(n);
If you say "sizeof(ptr)" what is the type of the expression you're giving to sizeof? It's a char *, which is just a pointer, not an array. So sizeof will dutifully give you a result of 4 or 8 (on most systems), and be completely oblivious to the chunk of memory that ptr is pointing to.

Quote:
Originally Posted by Dubslow View Post
What happens if I get an EOF before \n? Just fill in the \0?
Good question. I assume you mean if you've already read some characters. Then yes, I think that would be the best design. Of course if you see EOF before reading any characters, then it should return NULL.

Quote:
Originally Posted by Dubslow View Post
And, further, if the first char is \n, do I return a one-char string "\0" or NULL?
If you return NULL, then there's no way to distinguish between an empty line and an end-of-file condition. So I would say the former is better.

Last fiddled with by jyb on 2012-02-25 at 03:59
jyb is offline   Reply With Quote
Old 2012-02-25, 04:09   #203
chalsall
If I May
 
chalsall's Avatar
 
"Chris Halsall"
Sep 2002
Barbados

2·67·73 Posts
Default

Quote:
Originally Posted by Dubslow View Post
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?
Dubslow... jyb is giving you some excellent guidance, but I have to interject this point...

When you are interested in a C function or a program, I would recommend (in addition to, or instead of, Google) you leverage on the detailed information available from the Unix command line.

"man [ANY FUNCTION or PROGRAM]" and "info [ANY FUNCTION or PROGRAM]" are your friends.

Try "info info", "info man", "man info" and "man man" to get a feel for what's available (literally) at your fingertips. No Internet required!
chalsall is online now   Reply With Quote
Old 2012-02-25, 04:36   #204
WraithX
 
WraithX's Avatar
 
Mar 2006

25×3×5 Posts
Default

Another very important point that may have been buried in this flurry of activity:

Always free() memory that you malloc()!

*cough* char* string and char* code *cough*
WraithX is online now   Reply With Quote
Old 2012-02-25, 05:38   #205
jyb
 
jyb's Avatar
 
Aug 2005
Seattle, WA

2×883 Posts
Default

Quote:
Originally Posted by Dubslow View Post
Quick question: What does realloc(ptr,n) do if( n<sizeof(ptr) ) ? Does it return ptr?
Quote:
Originally Posted by Dubslow View Post
I meant if you're requesting less space, it will return the pointer you passed it?
Sorry, forgot to answer this before. Technically, the answer is no. Or at least, you can not make such an assumption. All you are guaranteed is that realloc will do one of two things:

1) Return a pointer to space as big as you've asked for, the contents of which will be the same as the memory pointed to by the pointer you passed in (up to the minimum of the old and new sizes, of course), or
2) Return NULL if it can't satisfy the request for some reason.

In case #1, you have no guarantee that the pointer returned is the same as the one you passed, whether you're growing or shrinking.

As a practical matter, it is nearly always the case that if you're shrinking then the memory allocator will not move the block. So most of the time you will in fact get back the same pointer you passed. But you should never write code that relies on this.

Oh, and one other thing. The "stream" argument to ReadLine is there to allow it to read from an arbitrary file, rather than only reading from stdin. Your implementation of ReadLine is using getchar, which *always* reads from stdin, so right now you're just ignoring the stream argument. To fix this, just use getc instead of getchar. getc takes a FILE * as an argument, so you can just pass stream right on through to it and the right thing should happen. In every other respect it's exactly the same as getchar.
jyb is offline   Reply With Quote
Old 2012-02-25, 07:11   #206
Dubslow
Basketry That Evening!
 
Dubslow's Avatar
 
"Bunslow the Bold"
Jun 2011
40<A<43 -89<O<-88

3·29·83 Posts
Default

I feel so loved!
For motivation to continue putting so much effort into me, at the end of this hopefully will be another competent C programmer who can contribute to GIMPS/the world in a not-crappy way. My girlfriend always complains that physicists write the worst code, and hopefully I can change that

Down to business:
Quote:
Originally Posted by jyb View Post
Yowza! Yeah, you've got some pretty bad bugs in your ReadLine function. But don't be discouraged! This was a good effort. I can tell you where some of your problems are, or I can let you debug it yourself. You'll probably learn more by doing the latter, but you might also get very frustrated. So how 'bout this: you see if you can figure out why your realloc calls are going awry. If you're stuck, let me know and I'll help.

BTW, there's only so much debugging you can do by code inspection. I suggest using a debugger to follow through your code in ReadLine. I think you'll quickly discover some of your errors, and you may also find some better ways to structure the code.
I'd like to see how far I can get with printf's and my brain. With the C I've written so far, this has generally sufficed. (I just use nano/gedit and I have a bash alias for 'gcc -Wall -o' I wouldn't know where to look for a debugger.) It's good practice anyways, if ever none is available, and I get that much more understanding out of it.

I guess then that there aren't any major structural flaws? At the time, I'd just spent an hour thinking about/writing/working on it in some way, so I stopped. Debugging always works better when it comes later, and it'll probably wait until tomorrow (maybe later, 'cause of the talent show).

Quote:
Originally Posted by jyb View Post
Good question. I assume you mean if you've already read some characters. Then yes, I think that would be the best design. Of course if you see EOF before reading any characters, then it should return NULL.


If you return NULL, then there's no way to distinguish between an empty line and an end-of-file condition. So I would say the former is better.
For these, my cypher prog doesn't really care if it's EOF or '\n', though I can see in general that's not the case. Thanks for the opinions, I'll implement those.
Quote:
Originally Posted by chalsall View Post
Dubslow... jyb is giving you some excellent guidance, but I have to interject this point...

When you are interested in a C function or a program, I would recommend (in addition to, or instead of, Google) you leverage on the detailed information available from the Unix command line.

"man [ANY FUNCTION or PROGRAM]" and "info [ANY FUNCTION or PROGRAM]" are your friends.

Try "info info", "info man", "man info" and "man man" to get a feel for what's available (literally) at your fingertips. No Internet required!
Oh my good goodness gracious, I thought man was only for things where 'which [command]' isn't blank, i.e. not C functions! Holy crap! I've never used info before, this is so awesome (I admit I'm having trouble discerning the difference between man and info; is it only the formatting (and where's the difference there?)
Quote:
Originally Posted by WraithX View Post
Another very important point that may have been buried in this flurry of activity:

Always free() memory that you malloc()!

*cough* char* string and char* code *cough*
Hmm... Ah yes. I thought that when I went around the loop and reassign them, the old ones get thrown out... I'm almost embarrassed at such a novice mistake, but then again, I am a novice.
Code:
                printf("Processed: ");
		puts(code);
		free(string);
		free(code);

Thank you so much guys!



(In other news, man can be used for just about anything!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! (What/where exactly are the online reference manuals that it duplicates?))

(Edit: One last clarification, is "input[i]=0;" equivalent to "input[i]='\0';" ?)
(I take that back. Question 2:
Code:
fgetc() reads the next character from stream and  returns  it  as  an
       unsigned char cast to an int, or EOF on end of file or error.

       getc()  is equivalent to fgetc() except that it may be implemented as
       a macro which evaluates stream more than once.
What does that mean?)


Holy shit thank you so much Dennis Ritchie and Richard Stallman and everyone else who has ever contributed to all this stuff.

Last fiddled with by Dubslow on 2012-02-25 at 07:24
Dubslow is offline   Reply With Quote
Old 2012-02-25, 10:07   #207
Christenson
 
Christenson's Avatar
 
Dec 2010
Monticello

5·359 Posts
Default

Quote:
Originally Posted by jyb View Post
I.e. he's optimizing programmer time vs. running time.

But let's face it, even the running time difference is negligible. He's doing I/O, which means the extra function call overhead involved in using getchar will be lost in the noise. Not to mention that while getchar may be a macro that expands to getc(stdin), getc itself is pretty much always a macro that doesn't result in a function call.
For what he's working on, programmer time is EVERYTHING and run-time is nothing....why store the line at all, assuming the input and output streams are actually distinct....or his console is in "noecho" mode.
Christenson is offline   Reply With Quote
Old 2012-02-25, 10:28   #208
Christenson
 
Christenson's Avatar
 
Dec 2010
Monticello

5×359 Posts
Default

Quote:
Originally Posted by Dubslow View Post
(Edit: One last clarification, is "input[i]=0;" equivalent to "input[i]='\0';" ?)
(I take that back. Question 2:
Code:
fgetc() reads the next character from stream and  returns  it  as  an
       unsigned char cast to an int, or EOF on end of file or error.

       getc()  is equivalent to fgetc() except that it may be implemented as
       a macro which evaluates stream more than once.
What does that mean?)


Holy shit thank you so much Dennis Ritchie and Richard Stallman and everyone else who has ever contributed to all this stuff.
That bit about a macro means that
getc(streams[i++])
may or may not do what you expect (increment i once as a side effect), but
fgetc(streams[i++])
will do what you expect (increment i once as a side effect)
I'll leave implementing getc as a macro two ways up to you...

The bit about an unsigned char cast to an int is because the implementation usually has
#define EOF -1
(which is outside the domain of unsigned char -- you have to know if you didn't get anything, as opposed to got any particular character from the file, which contains all characters)
Christenson is offline   Reply With Quote
Old 2012-02-25, 18:22   #209
Dubslow
Basketry That Evening!
 
Dubslow's Avatar
 
"Bunslow the Bold"
Jun 2011
40<A<43 -89<O<-88

3×29×83 Posts
Default

But what's a macro? What makes it different from a standard function?

And also re: debuggers, I've finally figured out how to use gdb
Dubslow is offline   Reply With Quote
Reply

Thread Tools


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


Fri Aug 6 15:29:03 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.