|  | K&R Ex 1-22 |  | |
| | | Andrew C. |  |
| Posted: Tue Aug 19, 2008 5:36 am Post subject: K&R Ex 1-22 |  |
| |  | |
I'm trying to complete excercise 1-23 in the K&R book, which calls for a program to wrap input lines at a given column, making sure to handle lines that wrap twice or don't contain whitespace. This is what I have so far*: LINK *Insert is a function which shifts the contents of the string right by one character and inserts another character in its place.
I'm sure there's probably a completely better way to do this, but I'm too far into it to rewrite it a different way.
Anyway, what I really want to know is why the variable "search_state" always equals zero (at least according to the printf statement I put in there and the fact that it never wraps) even though the if statement before "search_state = 1" resolves to be true. It's almost as though search_state was losing its value at the end of the for loop. If it doesn't get set to 1, no wrapping will happen.
I feel really stupid for having this much trouble with an excercise so early in the book, but this has me baffled.
- You can get everything in life you want, if you will help enough other people get what they want. |
| |
| | | Richard Heathfield |  |
| Posted: Tue Aug 19, 2008 5:57 am Post subject: Re: K&R Ex 1-22 |  |
| |  | |
Andrew C. said:
| Quote: | I'm trying to complete excercise 1-23 in the K&R book, which calls for a program to wrap input lines at a given column, making sure to handle lines that wrap twice or don't contain whitespace. This is what I have so far*: LINK
|
I haven't much time right now, but I will have, later on. For me (or indeed for anyone else) to look at your problem in sufficient detail to help you, it would be handy if you could post the complete, compilable source code that you are using, preferably right here on Usenet rather than on a Web site. Also, it would be very useful to know what test data you're using.
My first glance (and it *is* only a quick glance) suggests that, when you pass a string of fewer than 80 characters, your value for 'next' will be 0, which looks like it could be problematic. (That might not be the problem - it's just a first impression.)
No doubt someone else will be able to help you more, but I really do recommend that you post the full source here, together with your test data.
HTH. HAND.
-- Richard Heathfield <http://www.cpax.org.uk> Email: -http://www. +rjh@ Google users: <http://www.cpax.org.uk/prg/writings/googly.php> "Usenet is a strange place" - dmr 29 July 1999 |
| |
| | | Andrew C. |  |
| Posted: Tue Aug 19, 2008 7:34 am Post subject: Re: K&R Ex 1-22 |  |
| |  | |
On 2008-08-19, Richard Heathfield <rjh@see.sig.invalid> wrote:
| Quote: | Andrew C. said:
I'm trying to complete excercise 1-23 in the K&R book, which calls for a program to wrap input lines at a given column, making sure to handle lines that wrap twice or don't contain whitespace. This is what I have so far*: LINK
I haven't much time right now, but I will have, later on. For me (or indeed for anyone else) to look at your problem in sufficient detail to help you, it would be handy if you could post the complete, compilable source code that you are using, preferably right here on Usenet rather than on a Web site. Also, it would be very useful to know what test data you're using.
My first glance (and it *is* only a quick glance) suggests that, when you pass a string of fewer than 80 characters, your value for 'next' will be 0, which looks like it could be problematic. (That might not be the problem - it's just a first impression.)
No doubt someone else will be able to help you more, but I really do recommend that you post the full source here, together with your test data.
HTH. HAND.
You're right, I should have posted the full source code. I used |
pastebin because I figured it would have been a bigger breach of ettiquette to post a sizeable source file directly to usenet, long lines and all, but here goes:
#include <stdio.h> #include <string.h>
#define MAXCOLS 80 /*Column to wrap at*/ #define MAXLINE 1000 /*Maximum string length*/ #define NEXT(current) ((current/MAXCOLS+1)*MAXCOLS) /*macro to calculate next*/
void wrap(char s[], int len); void insert(char s[], int at, char c); int getline(char s[], int lim);
main() { char line[MAXLINE]; int len;
int i; for(i = 0; i<=80; ++i) putchar(' '); printf("|\n");
while((len = getline(line, MAXLINE)) > 0) { wrap(line,len); printf("%s",line); }
return 0; }
/*wrap: word wrap a string at the desired length */ void wrap(char s[], int len) { int search_state = 0; /*0 = looking for next, 1 = looking for whitespace*/ int i = len-1; int next = ((i/MAXCOLS))*MAXCOLS; /*next column to wrap at*/
for(i = len-1; i > MAXCOLS-1; --i) { next = ((i/MAXCOLS))*MAXCOLS; printf(" %d ",search_state); /*debug*/ if(search_state == 1) { if(s[i] == ' ') { /*all is well*/ s[i] = '\n'; /*place a newline in the whitespace*/ search_state = 0; /*reset the state*/ } else if(i == next && s[i] != ' ') { /*there wasn't any whitespace*/ insert(s,i,'\n'); /*insert a newline at the wrap point*/ search_state = 0; /*reset the state*/ } } else if(next >= MAXCOLS && i == next) /*if there is a next, and i equals it, start wrapping*/ search_state = 1; } }
/*insert: insert a character into the middle of a character string*/ void insert(char s[], int at, char c) { int i;
for(i = strlen(s)-1; i>=at; --i) s[i+1] = s[i]; s[i] = c; }
/* getline: read a line into s, return length */ int getline(char s[], int lim) { int c, i; for (i = 0; i<lim-1 && (c=getchar()) != EOF && c!='\n'; ++i) s[i] = c; if (c == '\n') { s[i] = c; ++i; } if (i >= lim-1) { while((c = getchar()) != EOF && c!='\n') ++i; /*increment length anyway in case of overflow*/ s[lim-1] = '\0'; } else s[i] = '\0'; return i; }
By the way, with any input line less than 80 characters, absolutely nothing should happen to it, which is indeed the correct behavior because no word wrapping is needed.
As for test data, any input (I either mashed the keyboard or typed in song lyrics) does the exact same thing: spit the input out unchanged.
Thanks for your help, and sorry for being a noob. -- You can get everything in life you want, if you will help enough other people get what they want. |
| |
| | | Richard Heathfield |  |
| Posted: Tue Aug 19, 2008 12:30 pm Post subject: Re: K&R Ex 1-22 |  |
| |  | |
Andrew C. said:
| Quote: | On 2008-08-19, Richard Heathfield <rjh@see.sig.invalid> wrote:
No doubt someone else will be able to help you more, but I really do recommend that you post the full source here, together with your test data.
You're right, I should have posted the full source code. I used pastebin because I figured it would have been a bigger breach of ettiquette to post a sizeable source file directly to usenet, long lines and all,
|
Your concern for etiquette makes a welcome change! Nevertheless, a hundred lines or so is no big deal in Usenet nowadays, at least not for most people, and we can hope that the first couple of articles in this thread will warn modem-users off. :-)
Okay, my first step was to compile it:
gcc -W -Wall -ansi -pedantic -Wformat-nonliteral -Wcast-align -Wpointer-arith -Wbad-function-cast -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations -Winline -Wundef -Wnested-externs -Wcast-qual -Wshadow -Wconversion -Wwrite-strings -ffloat-store -fno-builtin -O2 -g -pg -c -o kr123.o kr123.c kr123.c:14: warning: return-type defaults to `int' kr123.c:14: warning: function declaration isn't a prototype kr123.c: In function `wrap': kr123.c:50: warning: passing arg 3 of `insert' with different width due to prototype kr123.c: In function `getline': kr123.c:75: warning: `c' might be used uninitialized in this function
So let's go fix those things.
On line 14, I changed:
main()
to:
int main(void)
On line 50, '\n' is actually of type int, would you believe? But we know its value must fit in a char (for several reasons, one of which is that it is a mandatory member of the source character set, so it must have a value in the range 1 to CHAR_MAX), so it's okay to pass it to a function expecting a char. No fix required (although changing insert() to take int rather than char would at least silence the warning).
By far the most serious warning is the one about 'c' possibly being used uninitialised. But as far as I can see, this is actually impossible, given that there is only one call to getline, and it specifies a large-ish value for lim, so i<lim-1 must be true first time round, so the getchar is definitely called.
So much for the compiler. Let's look at the behaviour.
To make matters a little less long-winded, I changed MAXCOLS to 12 and recompiled. I gave your program an input of abcdefghijklmnop, and it printed a bunch of spaces and a vertical bar, as expected. (I don't know why you do that, but hey, it's your program!) It then spat out what look like some debugging numbers, followed by abcdefghijklmnop again, with no wrap.
Then I gave it lots and lots of junk, and (remembering that we changed MAXCOLS to 12) look what happened!
fkjslvnfdlskjvnfsdkjlvnfdskjvnfsdkjvnfksldjnvjksldfnvjdskfvnfdjsvnjkdfls jfks vjksfdvjkfsdhvjksdfvhjksdfv 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 fkjslvnfdls jjvnfsdkjlvnfdskjvnfsdkj nnfksldjnvjksldfnvjdskfv ffdjsvnjkdfls jfks vjksf vvjkfsdhvjksdfvhjksdfv #1 Wed Mar 27 13:57:05 UTC 2002
WOW! I have no idea where that timestamp came from... :-)
So it looks like you *are* getting wrap, but not how and when you want it. It also looks like you have an unterminated "string". (That's the usual cause of utterly off-the-wall output.)
Time to read the code.
The first few lines in main just print out a bunch of spaces and a |, for no apparent reason - although no doubt you know why. Nothing illegal there, so let's move on.
You have a nice simple loop, consisting of getline, wrap, and printf. The printf prints 'line', so we have a good idea of which "string" isn't getting terminated. I checked to see whether it is constructed properly, by looking at getline, and getline seems fine.
So the problem of failure to terminate is either in wrap() or in insert(), and my money is on insert(), so let's take a look:
void insert(char s[], int at, char c) { int i;
for(i = strlen(s)-1; i>=at; --i) s[i+1] = s[i]; s[i] = c; }
Consider the following string: "ABCDEF\n\0" (I've made the \0 explicitly visible, but it isn't part of the count given by strlen.)
i = strlen(s) - 1; Since strlen(s) is 7 (A-F is 6, + \n), i takes the value 6.
s[i+1] = s[i];
so we're doing s[7] = s[6]. Now, s[7] /was/ the null terminator, but we just overwrote that. Not good. Let's fix it.
Whilst strlen yields the length of a string (not including the null), we can think of it in another way, i.e. as returning the offset of the null terminator.
void insert(char s[], int at, char c) { size_t nullpos = strlen(s); size_t pos = nullpos; while(pos > 0 && pos > at) { s[pos] = s[pos - 1]; --pos; } s[pos] = c; s[nullpos + 1] = '\0'; }
That's fixed our null termination problem. Now for the logic bug, which is clearly in the wrap() function. Experimentation quickly revealed that your code *is* wrapping, albeit rather bizarrely - for example, the first wrap seems to occur at 2*MAXCOLS, rather than at MAXCOLS.
It appears that what you're trying to do is replace a space with a newline if possible, but if necessary you'll shift a long string's tail over by one character to insert a newline. A perfectly reasonable approach, although of course you have to be careful with lines close to your buffer's size limit.
It strikes me that it would be much easier to do this as follows:
void wrap(char s[], size_t len) { char *t = s; while(len >= MAXCOLS) { t += MAXCOLS; while(t > s && *t != ' ') { --t; } if(*t == ' ') { *t = '\n'; } else { t += MAXCOLS; insert(t, 0, '\n'); } len -= (t - s); s = t; } }
Dropping that - and the insert() update - into your program (and making appropriate type-changes from int to size_t, which is a more appropriate type for describing buffer sizes), for input like this:
That's fixed our null termination problem. Now for the logic bug, which is clearly in the wrap() function. Experimentation quickly revealed that your code *is* wrapping, albeit rather bizarrely - for example, the first wrap seems to occur at 2*MAXCOLS, rather than at MAXCOLS.
I get output like this:
That's fixed our null termination problem. Now for the logic bug, which is clearly in the wrap() function. Experimenta tion quickly revealed that your code *is* wrapping, albeit rather bizarrely - for example, the first wrap seems to occur at 2*MAXCOLS, rather than at MAXCOLS.
and that seems to be working nicely.
-- Richard Heathfield <http://www.cpax.org.uk> Email: -http://www. +rjh@ Google users: <http://www.cpax.org.uk/prg/writings/googly.php> "Usenet is a strange place" - dmr 29 July 1999 |
| |
| | | Andrew C. |  |
| Posted: Tue Aug 19, 2008 5:20 pm Post subject: Re: K&R Ex 1-22 |  |
| |  | |
Thanks much for your help. First, let me go ahead and explain myself on that one segment of code involving spaces and a pipe - that's just a ruler I was printing to see if I had typed enough input to warrant wrapping. I noticed it was hardcoded to use 80 columns so I fixed it to use MAXCOLS instead. I guess I should have commented that.
Thank you for pointing out the problem with insert(), i probably wouldn't have noticed it otherwise.
Your solution for wrap is amazingly more elegant than mine:
On 2008-08-19, Richard Heathfield <rjh@see.sig.invalid> wrote:
| Quote: | It strikes me that it would be much easier to do this as follows:
void wrap(char s[], size_t len) { char *t = s; while(len >= MAXCOLS) { t += MAXCOLS; while(t > s && *t != ' ') { --t; } if(*t == ' ') { *t = '\n'; } else { t += MAXCOLS; insert(t, 0, '\n'); } len -= (t - s); s = t; } }
|
However, I'm having trouble understanding it because I can see it uses pointers, and having not reached that chapter in the book I don't really understand what pointers do. I'm sure this section can be written without pointers though, so I'll just set out to rewrite the function using the logic I think I'm seeing above.
-- You can get everything in life you want, if you will help enough other people get what they want. |
| |
| | | Andrew C. |  |
| Posted: Tue Aug 19, 2008 5:55 pm Post subject: Re: K&R Ex 1-22 |  |
| |  | |
On 2008-08-19, mdh <mdeh@comcast.net> wrote:
| Quote: | On Aug 19, 12:20 pm, "Andrew C." <sumguy231+n...@gmail.com> wrote:
However, I'm having trouble understanding it because I can see it uses pointers, and having not reached that chapter in the book I don't really understand what pointers do. I'm sure this section can be written without pointers though, so I'll just set out to rewrite the function using the logic I think I'm seeing above.
Andrew...like you, I have gone through K&R and done just about every exercise. I would make one recommendation. There is a book called "The C Answer book" by Tondo and Gimpel , that works through each question, in order of learning ie it would not talk about pointers before you have studied them. I have found this to be immensely helpful, as their solutions are elegant ( which you apparently like) and explained. The other thing is doing what you are doing ie asking clc. As long as you do not want your homework done.. . the clc is wonderfully... actually amazingly helpful, by the best minds on C.
|
Thanks for the recommendation, that book looks very helpful. I'm a little short on cash at the moment, but I'll try to pick it up if I can because it would help me immensely to be able to check my answers.
....And I promise not to ask you guys to do my homework for me, even though I'm not taking any classes involving C (yet). :-)
-- You can get everything in life you want, if you will help enough other people get what they want. |
| |
| | | mdh |  |
| Posted: Tue Aug 19, 2008 7:34 pm Post subject: Re: K&R Ex 1-22 |  |
| |  | |
On Aug 19, 12:20 pm, "Andrew C." <sumguy231+n...@gmail.com> wrote:
| Quote: | However, I'm having trouble understanding it because I can see it uses pointers, and having not reached that chapter in the book I don't really understand what pointers do. I'm sure this section can be written without pointers though, so I'll just set out to rewrite the function using the logic I think I'm seeing above.
|
Andrew...like you, I have gone through K&R and done just about every exercise. I would make one recommendation. There is a book called "The C Answer book" by Tondo and Gimpel , that works through each question, in order of learning ie it would not talk about pointers before you have studied them. I have found this to be immensely helpful, as their solutions are elegant ( which you apparently like) and explained. The other thing is doing what you are doing ie asking clc. As long as you do not want your homework done.. . the clc is wonderfully... actually amazingly helpful, by the best minds on C. |
| |
| | | Ron Ford |  |
| Posted: Tue Aug 19, 2008 11:26 pm Post subject: Re: K&R Ex 1-22 |  |
On Tue, 19 Aug 2008 07:57:04 +0000, Richard Heathfield posted:
| Quote: | http://pastebin.com/f61c6cfc
I haven't much time right now, but I will have, later on. For me (or indeed for anyone else) to look at your problem in sufficient detail to help you, it would be handy if you could post the complete, compilable source code that you are using, preferably right here on Usenet rather than on a Web site. Also, it would be very useful to know what test data you're using.
|
Richard errs that everyone else prefers source posting in clc as opposed to a link. Are you solving 22 or 23? -- When a new source of taxation is found it never means, in practice, that the old source is abandoned. It merely means that the politicians have two ways of milking the taxpayer where they had one before. 8 H. L. Mencken |
| |
| | | Andrew C. |  |
| Posted: Tue Aug 19, 2008 11:41 pm Post subject: Re: K&R Ex 1-22 |  |
On 2008-08-20, Ron Ford <ron@example.invalid> wrote:
| Quote: | On Tue, 19 Aug 2008 07:57:04 +0000, Richard Heathfield posted:
LINK
I haven't much time right now, but I will have, later on. For me (or indeed for anyone else) to look at your problem in sufficient detail to help you, it would be handy if you could post the complete, compilable source code that you are using, preferably right here on Usenet rather than on a Web site. Also, it would be very useful to know what test data you're using.
Richard errs that everyone else prefers source posting in clc as opposed to a link. Are you solving 22 or 23? I'm solving 22. I already finished 23, it was actually quite easy. |
-- Let us never negotiate out of fear, but let us never fear to negotiate. -- John F. Kennedy |
| |
| | | Richard Heathfield |  |
| Posted: Wed Aug 20, 2008 2:24 am Post subject: Re: K&R Ex 1-22 |  |
Andrew C. said:
<snip>
| Quote: | However, I'm having trouble understanding it because I can see it uses pointers,
|
Oops! Sorry about that.
void wrap(char s[], size_t len) { size_t basepos = 0; size_t curpos = 0;
while(len >= MAXCOLS) { curpos += MAXCOLS; while(curpos > basepos && s[curpos] != ' ') { --curpos; } if(s[curpos] == ' ') { s[curpos] = '\n'; } else { curpos += MAXCOLS; insert(s, curpos, '\n'); } len -= (curpos - basepos); basepos = curpos; } }
I haven't actually tested this, but I'm reasonably sure I got the translation right.
-- Richard Heathfield <http://www.cpax.org.uk> Email: -http://www. +rjh@ Google users: <http://www.cpax.org.uk/prg/writings/googly.php> "Usenet is a strange place" - dmr 29 July 1999 |
| |
| Page 1 of 3 .:. Goto page 1, 2, 3 Next | |
|
|