![]() |
|
|
#199 |
|
Basketry That Evening!
"Bunslow the Bold"
Jun 2011
40<A<43 -89<O<-88
3·29·83 Posts |
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) |
|
|
|
|
|
#200 |
|
Basketry That Evening!
"Bunslow the Bold"
Jun 2011
40<A<43 -89<O<-88
3·29·83 Posts |
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
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 |
|
|
|
|
|
#201 |
|
Basketry That Evening!
"Bunslow the Bold"
Jun 2011
40<A<43 -89<O<-88
1C3516 Posts |
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∰∂ Last fiddled with by Dubslow on 2012-02-25 at 02:50 |
|
|
|
|
|
#202 | |
|
Aug 2005
Seattle, WA
2·883 Posts |
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]; Code:
int arr[80] - 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:
Code:
char *ptr; ptr = malloc(n); 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. Last fiddled with by jyb on 2012-02-25 at 03:59 |
|
|
|
|
|
|
#203 | |
|
If I May
"Chris Halsall"
Sep 2002
Barbados
2·67·73 Posts |
Quote:
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!
|
|
|
|
|
|
|
#204 |
|
Mar 2006
25×3×5 Posts |
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*
|
|
|
|
|
|
#205 | ||
|
Aug 2005
Seattle, WA
2×883 Posts |
Quote:
Quote:
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. |
||
|
|
|
|
|
#206 | ||||
|
Basketry That Evening!
"Bunslow the Bold"
Jun 2011
40<A<43 -89<O<-88
3·29·83 Posts |
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:
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:
Quote:
(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:
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.
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 |
||||
|
|
|
|
|
#207 | |
|
Dec 2010
Monticello
5·359 Posts |
Quote:
|
|
|
|
|
|
|
#208 | |
|
Dec 2010
Monticello
5×359 Posts |
Quote:
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) |
|
|
|
|
|
|
#209 |
|
Basketry That Evening!
"Bunslow the Bold"
Jun 2011
40<A<43 -89<O<-88
3×29×83 Posts |
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
|
|
|
|