473,320 Members | 2,098 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,320 software developers and data experts.

input word

We have discussed this program a lot. Only two problems have remained with
this code:

/* a function written in ANSI C, that takes a word from stdin and manages the memory dynamically
*
* Since there is no generally agreed definition of what a 'word' is. I have taken a very simple
* approach:
*
* A word is a contiguous collection of non-whitespace characters. A whitespace means anyone of
* a single apace, a newline or a tab.
*
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
enum { WORD_SIZE = 28 };
enum { GSW_OK, GSW_ENOMEM, GSW_ENORESIZE } ;
int get_single_word( char** );

int main( void )
{
char* pword;
while( (GSW_OK == get_single_word(&pword)) && ( *pword != 0) )
{
printf("You entered: [%s]\n", pword);
free( pword );
}
return 0;
}


int get_single_word( char** ppc )
{
unsigned ele_num = 0;
int ch;
size_t word_length = WORD_SIZE;
size_t word_length_interval = 2;

char* word_begin;
char* new_mem;

*ppc = malloc(word_length * sizeof(**ppc));
word_begin = *ppc;
if( NULL == ppc )
{
return GSW_ENOMEM;

}
while( (EOF != (ch = getchar())) && isspace(ch) )
{
continue; /* Leading whitespace */
}
if( EOF != ch )
{
*word_begin++ = ch;
ele_num = 1;
}
while( (EOF != (ch = getchar())) && (! isspace(ch)) )
{
if( (word_length - 1) == ele_num++ )
{
new_mem = realloc( *ppc, (word_length_interval * word_length * sizeof *new_mem) );

if( new_mem )
{
word_begin = new_mem + (word_begin - *ppc);
word_length *= word_length_interval;
*ppc = new_mem;
}
else
{
*word_begin = '\0';
return GSW_ENORESIZE;
}
}

*word_begin++ = ch;
}
*word_begin = '\0';

return GSW_OK;
}

1) the get_single_word program is 60 lines long when there is
general agreement that no function should be longer than 40
lines.

2) distinguishing between real EOF and the error.


For (1) all I can think of is to take while() loop (from
get_single_word) out into a new function which will require passing 6
variables as pointer (or pointer to pointer) arguments: new_mem,
word_begin, word_length, word_length_interval, ppc and ele_num. I think
that will be messy solution.
Regarding (2) I have to use feof() and ferror() which are little
confusing.

--
www.lispmachine.wordpress.com
my email is @ the above blog.
Gooogle Groups is Blocked. Reason: Excessive Spamming

Oct 3 '08 #1
57 2532
On Fri, 03 Oct 2008 11:24:02 +0500, arnuld wrote:
We have discussed this program a lot. Only two problems have remained with
this code:
..SNIP...

I have tried it but it Segfaults:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
enum { WORD_SIZE = 28 };
enum { GSW_OK, GSW_ENOMEM, GSW_ENORESIZE } ;
int get_single_word( char** );
void save_word( char**, size_t*, size_t*);
int main( void )
{
char* pword;
while( (GSW_OK == get_single_word(&pword)) && ( *pword != 0) )
{
printf("You entered: [%s]\n", pword);
free( pword );
}
return 0;
}


int get_single_word( char** ppc )
{
unsigned ele_num = 0;
int ch;
size_t word_length = WORD_SIZE;

char* word_begin;

*ppc = malloc(word_length * sizeof(**ppc));
word_begin = *ppc;
if( NULL == ppc )
{
return GSW_ENOMEM;

}
while( (EOF != (ch = getchar())) && isspace(ch) )
{
continue; /* Leading whitespace */
}
if( EOF != ch )
{
*word_begin++ = ch;
ele_num = 1;
}
save_word( &word_begin, &ele_num, &word_length );
*word_begin = '\0';

return GSW_OK;
}


void save_word( char** word_begin, size_t* ele_num, size_t* word_length )
{
int ch = EOF;
size_t word_length_interval = 2;
char* new_mem = NULL;

char* pc = *word_begin;
while( (EOF != (ch = getchar())) && (! isspace(ch)) )
{
if( (*word_length - 1) == (*ele_num)++ )
{
new_mem = realloc( pc, (word_length_interval * (*word_length) * sizeof *new_mem) );

if( new_mem )
{
*word_begin = new_mem + (*word_begin - pc);
(*word_length) *= word_length_interval;
pc = new_mem;
}
else
{
*word_begin = '\0';
return;
}
}

**word_begin = ch;
*word_begin++;

}
}
--
www.lispmachine.wordpress.com
my email is @ the above blog.
Gooogle Groups is Blocked. Reason: Excessive Spamming

Oct 3 '08 #2
arnuld wrote:
>On Fri, 03 Oct 2008 11:24:02 +0500, arnuld wrote:
>We have discussed this program a lot. Only two problems have remained with
this code:
>..SNIP...


I have tried it but it Segfaults:
Have you checked with a debugger to see why?

--
Ian Collins.
Oct 3 '08 #3
arnuld wrote:
>On Fri, 03 Oct 2008 21:18:17 +1300, Ian Collins wrote:
>Have you checked with a debugger to see why?


I thought using a Debugger (for such small programs) kills one's
understanding of language, thats why I never used any debugger.
do you understand why your program fails without using debugger? Do you even
know where it fails?

Bye, Jojo
Oct 3 '08 #4
arnuld wrote:
>On Fri, 03 Oct 2008 21:18:17 +1300, Ian Collins wrote:
>Have you checked with a debugger to see why?


I thought using a Debugger (for such small programs) kills one's
understanding of language, thats why I never used any debugger.
Which do you prefer, stumbling around in the dark, or turning on the light?

--
Ian Collins.
Oct 3 '08 #5
On Fri, 03 Oct 2008 11:11:02 +0200, Joachim Schmitz wrote:
do you understand why your program fails without using debugger?
yes, some problem with the pointer passed as first argument. It is
pointing somewhere out of bounds.

Do you even know where it fails?
yes, I guess so. **word_begin++ = ch; (in save_word fucntion)
it does not go in to the while loop. It never goes in there till I
enter more than 1 character.

--
www.lispmachine.wordpress.com
my email is @ the above blog.
Gooogle Groups is Blocked. Reason: Excessive Spamming

Oct 3 '08 #6
On Fri, 03 Oct 2008 23:22:03 +1300, Ian Collins wrote:
Which do you prefer, stumbling around in the dark, or turning on the light?
Using debugger means shutting down your brain. Thats what I think because
If I can't understand what I wrote in just 24 lines, I better throw the
code and start again.


--
www.lispmachine.wordpress.com
my email is @ the above blog.
Gooogle Groups is Blocked. Reason: Excessive Spamming

Oct 3 '08 #7

"arnuld" <su*****@invalid.addresswrote in message
news:pa****************************@invalid.addres s...
1) the get_single_word program is 60 lines long when there is
general agreement that no function should be longer than 40
lines.
Sounds like nonsense to me.

Some functions perhaps could do with breaking up, but it all depends.

I've just been working on one with 3000 lines.

60 lines will anyway fit nicely printed on one page.

--
Bartc

Oct 3 '08 #8
arnuld <su*****@invalid.addresswrote:
On Fri, 03 Oct 2008 23:22:03 +1300, Ian Collins wrote:
Which do you prefer, stumbling around in the dark, or turning on the light?

Using debugger means shutting down your brain. Thats what I think because
If I can't understand what I wrote in just 24 lines, I better throw the
code and start again.
This is quite true, but it does require that you start from the
beginning _correctly_. Clear the room, _then_ start again in daylight.
Don't continue to grope around half-understanding. IOW, first formulate
_what_ you want to do, then _how_ you think you're going to do it, and
only then start coding. And check your code _while_ you're coding, don't
write it all in a lump and expect to be able to sort the bugs out
afterwards.

Richard
Oct 3 '08 #9
In article <pa****************************@invalid.address> ,
arnuld <su*****@invalid.addresswrote:
1) the get_single_word program is 60 lines long when there is
general agreement that no function should be longer than 40
lines.
No there isn't.

-- Richard
--
Please remember to mention me / in tapes you leave behind.
Oct 3 '08 #10
Bartc wrote:
>
"arnuld" <su*****@invalid.addresswrote in message
news:pa****************************@invalid.addres s...
> 1) the get_single_word program is 60 lines long when there is
general agreement that no function should be longer than 40
lines.

Sounds like nonsense to me.
Yes, 40 lines is too long.
Some functions perhaps could do with breaking up, but it all depends.
Of course. But just because it all depends doesn't mean that
long functions are good.
I've just been working on one with 3000 lines.
/That/ is too long, absent very Special Circumstances.
60 lines will anyway fit nicely printed on one page.
What is this "page" of which you speak?

--
'It changed the future .. and it changed us.' /Babylon 5/

Hewlett-Packard Limited registered office: Cain Road, Bracknell,
registered no: 690597 England Berks RG12 1HN

Oct 3 '08 #11

"Chris Dollin" <ch**********@hp.comwrote in message
news:gc**********@news-pa1.hpl.hp.com...
Bartc wrote:
>>
"arnuld" <su*****@invalid.addresswrote in message
news:pa****************************@invalid.addre ss...
>> 1) the get_single_word program is 60 lines long when there is
general agreement that no function should be longer than 40
lines.

Sounds like nonsense to me.

Yes, 40 lines is too long.
What would code look like if you imposed a limit of perhaps 6 lines per
function?

Have you ever tried reading a web document, by itself fairly short, but
presented a paragraph per page (and buried amongst advertising)? It's
exasperating. Or an online book where you have to navigate by hyperlinks.
You quickly get fed up.
>
>Some functions perhaps could do with breaking up, but it all depends.

Of course. But just because it all depends doesn't mean that
long functions are good.
>I've just been working on one with 3000 lines.

/That/ is too long, absent very Special Circumstances.
Well, that one was mostly a large 'switch' with some 200 cases. Maybe a set
of functions would have been better, but speed was critical here. The magic
of suitable comments and editor help ensured that each case was as readable
as an independent function.
>
>60 lines will anyway fit nicely printed on one page.

What is this "page" of which you speak?
Last time I printed out any code, a printer could put 66 lines on one page.
With the right font and using A4 paper, that's probably still about right.

--
Bartc

Oct 3 '08 #12
Bartc wrote:
>
"Chris Dollin" <ch**********@hp.comwrote in message
news:gc**********@news-pa1.hpl.hp.com...
>Bartc wrote:
>>>
"arnuld" <su*****@invalid.addresswrote in message
news:pa****************************@invalid.addr ess...

1) the get_single_word program is 60 lines long when there is
general agreement that no function should be longer than 40
lines.

Sounds like nonsense to me.

Yes, 40 lines is too long.

What would code look like if you imposed a limit of perhaps 6 lines per
function?
Mine.

(Maybe 10 rather than 6.)
Have you ever tried reading a web document, by itself fairly short, but
presented a paragraph per page (and buried amongst advertising)? It's
exasperating. Or an online book where you have to navigate by hyperlinks.
You quickly get fed up.
The paragraphs don't have names that are supposed to be meaningful
to people. Code doesn't have advertising in it. Code is denser than
text. Code has structure whereby things closer tend to have more
immediate relevance. You don't have to flip pages at function
boundaries.
>>Some functions perhaps could do with breaking up, but it all depends.

Of course. But just because it all depends doesn't mean that
long functions are good.
>>I've just been working on one with 3000 lines.

/That/ is too long, absent very Special Circumstances.

Well, that one was mostly a large 'switch' with some 200 cases.
That counts as SC; my biggest C function was also a switch, some 800
lines before macro-expansion.
>>60 lines will anyway fit nicely printed on one page.

What is this "page" of which you speak?

Last time I printed out any code, a printer could put 66 lines on one page.
With the right font and using A4 paper, that's probably still about right.
I've discovered that whenever I print out code, I look at it
for five minutes, write some red [1] lines [2] on it, go back
to the computer, and ignore the paper thereafter. So "pages"
aren't interesting to me as a measure of code size [3].

[1] Depending on the pen to hand.

[2] Some of the lines are supposed to be words.

[3] More as a contribution to profit ...

--
'It changed the future .. and it changed us.' /Babylon 5/

Hewlett-Packard Limited registered office: Cain Road, Bracknell,
registered no: 690597 England Berks RG12 1HN

Oct 3 '08 #13
On Oct 3, 2:24 am, arnuld <sunr...@invalid.addresswrote:
We have discussed this program a lot. Only two problems have remained with
this code:
[snip]
1) the get_single_word program is 60 lines long when there is
general agreement that no function should be longer than 40
lines.
"General agreement"? Sorry, but no.

However, I'll buy it as "development standard" in your shop (assuming
that
this is code written for a company, and the code-writing group has
standards wrt function body length).

/If/ you want to reduce the length of the get_single_word() *function*
(not
*program*, unless you've not given us all the information), there are
several techniques that you can use:

1) Reduce statements to their most compact form
For example, the 5 line
if ( NULL == ppc )
{
return GSW_ENOMEM;

}
would become the one line
if (NULL == ppc ) return GSW_ENOMEM;
eliminating four lines, and the 4 line
while( (EOF != (ch = getchar())) && isspace(ch) )
{
continue; /* Leading whitespace */
}
would lose three lines to become
while( (EOF != (ch = getchar())) && isspace(ch) ) ;

2) Combine commonalities into single elements. The two while() loops
have some common test elements; you could combine the two loops
into
one, and distinguish the differences within the loop body

3) Create new functions from old logic. Your get_single_word()
function
works in four phases:
1 - sanity check,
2 - skip leading whitespace,
3 - empty word handler,
4 - word string handler
Break one or more of these out into it's own function, and modify
get_single_word() to utilize the new function instead of its own
inline code. A good candidate might be the word string handler
logic.

2) distinguishing between real EOF and the error.
To what purpose? Would you handle a getchar() error different from a
getchar() EOF? I suppose that you /could/ change your enum from
enum { GSW_OK, GSW_ENOMEM, GSW_ENORESIZE};
to
enum { GSW_OK, GSW_ENOMEM, GSW_ENORESIZE, GSW_ESTDIO_ERROR};
and your final
return GSW_OK;
to
if (feof(stdin))
return GSW_OK;
else
return GSW_ESTDIO_ERROR;
but how would your main() function logic change when it encounters a
GSW_ESTDIO_ERROR? From what I can see, your main() only looks for a
GSW_OK; /all/ other returns cause a silent program termination.

[snip]

HTH
--
Lew
(posted from google groups due to failure with my regular nntp
service)

Oct 3 '08 #14
arnuld wrote:
>On Fri, 03 Oct 2008 23:22:03 +1300, Ian Collins wrote:
>Which do you prefer, stumbling around in the dark, or turning on the light?

Using debugger means shutting down your brain. Thats what I think because
If I can't understand what I wrote in just 24 lines, I better throw the
code and start again.
Then test as you go. Write a simple test, write the code to pass it,
check in. Repeat until done.

Then if you add come code that breaks, just revert the change and do it
again.

--
Ian Collins.
Oct 3 '08 #15
Chris Dollin wrote:
Bartc wrote:
>"Chris Dollin" <ch**********@hp.comwrote in message
news:gc**********@news-pa1.hpl.hp.com...
>>Bartc wrote:

"arnuld" <su*****@invalid.addresswrote in message
news:pa****************************@invalid.add ress...

1) the get_single_word program is 60 lines long when there is
general agreement that no function should be longer than 40
lines.
Sounds like nonsense to me.
Yes, 40 lines is too long.
What would code look like if you imposed a limit of perhaps 6 lines per
function?

Mine.

(Maybe 10 rather than 6.)
Also mine, I aim for about 10 lines per function.
>>>60 lines will anyway fit nicely printed on one page.
120 lines fit on one screen, but I hardly ever create functions that long.

--
Ian Collins.
Oct 3 '08 #16
Lew Pitcher wrote:
arnuld <sunr...@invalid.addresswrote:
>We have discussed this program a lot. Only two problems have
remained with this code:

[snip]
> 1) the get_single_word program is 60 lines long when there
is general agreement that no function should be longer
than 40 lines.

"General agreement"? Sorry, but no.

However, I'll buy it as "development standard" in your shop
(assuming that this is code written for a company, and the
code-writing group has standards wrt function body length).
This thread is missing the major purpose of limiting function
length. The point is to make things readable and understandable to
the poor programmer, especially the one who is fixing the code five
years later. Which may be you.

Humans can normally handle something up to seven items. So the
routine should have no more than that many parameters and local
variables. Larger things can be handled by calling an
appropriately named subroutine. This combines quite nicely with
the objective of keeping the source of a routine small enough to
fit on a single CRT screen.

I can usually easily read code I wrote thirty years ago, because I
have adhered to this principle [1]. Forty year old code is another
matter, because I hadn't yet learned the key facts. Forty-five is
even worse. The age matters, but not the language.

[1] Or should that be principal?

--
[mail]: Chuck F (cbfalconer at maineline dot net)
[page]: <http://cbfalconer.home.att.net>
Try the download section.
Oct 3 '08 #17
On 3 Oct 2008 at 21:51, CBFalconer wrote:
This combines quite nicely with the objective of keeping the source of
a routine small enough to fit on a single CRT screen.
Another glimpse into CBF's stone-age existence. How many clc'ers really
still use a CRT screen, I wonder?

Oct 3 '08 #18
On Fri, 03 Oct 2008 11:24:02 +0500, arnuld <su*****@invalid.address>
wrote:
>We have discussed this program a lot. Only two problems have remained with
this code:

/* a function written in ANSI C, that takes a word from stdin and manages the memory dynamically
*
* Since there is no generally agreed definition of what a 'word' is. I have taken a very simple
* approach:
*
* A word is a contiguous collection of non-whitespace characters. A whitespace means anyone of
* a single apace, a newline or a tab.
You use isspace to detect whitespace. isspace will return true for
several other characters besides these three.
*
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
enum { WORD_SIZE = 28 };
enum { GSW_OK, GSW_ENOMEM, GSW_ENORESIZE } ;
int get_single_word( char** );

int main( void )
{
char* pword;
while( (GSW_OK == get_single_word(&pword)) && ( *pword != 0) )
{
printf("You entered: [%s]\n", pword);
free( pword );
}
return 0;
}


int get_single_word( char** ppc )
{
unsigned ele_num = 0;
int ch;
size_t word_length = WORD_SIZE;
size_t word_length_interval = 2;

char* word_begin;
char* new_mem;

*ppc = malloc(word_length * sizeof(**ppc));
word_begin = *ppc;
if( NULL == ppc )
Surely this has been mentioned before. ppc contains the address of
pword in main. It can never be NULL. You probably meant *ppc.
{
return GSW_ENOMEM;
And I know your excessive vertical white space has been discussed.
}
while( (EOF != (ch = getchar())) && isspace(ch) )
{
continue; /* Leading whitespace */
}
if( EOF != ch )
{
*word_begin++ = ch;
ele_num = 1;
}
while( (EOF != (ch = getchar())) && (! isspace(ch)) )
{
if( (word_length - 1) == ele_num++ )
{
new_mem = realloc( *ppc, (word_length_interval * word_length * sizeof *new_mem) );

if( new_mem )
{
word_begin = new_mem + (word_begin - *ppc);
word_length *= word_length_interval;
*ppc = new_mem;
}
else
{
*word_begin = '\0';
return GSW_ENORESIZE;
}
}

*word_begin++ = ch;
}
*word_begin = '\0';

return GSW_OK;
}

1) the get_single_word program is 60 lines long when there is
63 actually
general agreement that no function should be longer than 40
Only among mental midgets.
lines.

2) distinguishing between real EOF and the error.


For (1) all I can think of is to take while() loop (from
Vertical white space is a matter of style but, to be blunt, yours
sucks. I count at least 9 lines of inappropriate or excessive
spacing. That would get you down to 54 lines which would make the
entire block of executable code visible on the screen at once on my
monitor (a much more useful measure than an arbitrary line count).
>get_single_word) out into a new function which will require passing 6
variables as pointer (or pointer to pointer) arguments: new_mem,
word_begin, word_length, word_length_interval, ppc and ele_num. I think
that will be messy solution.
A function should perform a single task. It should be as large as it
needs to be to perform that task, but no larger. If the task is
unacceptably large (tm) or excessively complicated (tm), then it
should be broken into subtasks and coded accordingly.

While neither condition applies in this case, for practice you could
attempt to compartmentalize some aspect of g_s_w. As an example, you
could move the 16 lines of code that deal with reallocating the space
*ppc points to into a separate function. It would require only three
arguments (the current value of *ppc, the address of word length, and
the address of new_mem).
>

Regarding (2) I have to use feof() and ferror() which are little
confusing.
They are mutually exclusive in this case so you only need to use one
or the other. If the one you use returns 1, then that condition is
true. (E.g., if you use feof and it returns 1, then you reached end
of file and don't have an error). If the one you use returns 0, then
the other condition is true.

--
Remove del for email
Oct 4 '08 #19
On Oct 3, 3:27 am, arnuld <sunr...@invalid.addresswrote:
On Fri, 03 Oct 2008 23:22:03 +1300, Ian Collins wrote:
Which do you prefer, stumbling around in the dark, or turning on the light?

Using debugger means shutting down your brain. Thats what I think because
If I can't understand what I wrote in just 24 lines, I better throw the
code and start again.
I really don't see how a debugger can shut down your brain. I always
use a debugger at work.

Oct 4 '08 #20
CBFalconer said:

<snip>
the objective of keeping the source of a routine small enough to
fit on a single CRT screen.

I can usually easily read code I wrote thirty years ago, because I
have adhered to this principle [1]. Forty year old code is another
matter, because I hadn't yet learned the key facts. Forty-five is
even worse. The age matters, but not the language.
Presumably, then, fggets is forty years old (and pre-dates the C language).
Here is one CRTful of fggets:
int fggets(char* *ln, FILE *f)
{
int cursize, ch, ix;
char *buffer, *temp;

*ln = NULL; /* default */
if (NULL == (buffer = malloc(INITSIZE))) return NOMEM;
cursize = INITSIZE;

ix = 0;
while ((EOF != (ch = getc(f))) && ('\n' != ch)) {
if (ix >= (cursize - 1)) { /* extend buffer */
cursize += DELTASIZE;
if (NULL == (temp = realloc(buffer, (size_t)cursize))) {
/* ran out of memory, return partial line */
buffer[ix] = '\0';
*ln = buffer;
return NOMEM;
}
buffer = temp;
}
buffer[ix++] = ch;
}
Kinda sawed-off, isn't it?
[1] Or should that be principal?
"Principle" is correct. Reserve "principal" for use as an adjective
describing the foremost entity or entities in a group ("the principal
standard library functions for data capture in C are getc and fgets,
although several other functions are also used occasionally"); or as a
noun identifying (a) the amount of money used in an interest calculation,
(b) the person for whom an agent acts, (c) the person who is required to
ensure that an obligation is met, (d) in an orchestra, the chief player in
each section, (e) the leading performer in a theatrical performance,
(f) a person who commits or takes part in a crime, (g) the head teacher of
a school.

--
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
Oct 4 '08 #21
Chad wrote:
arnuld <sunr...@invalid.addresswrote:
>Ian Collins wrote:
>>Which do you prefer, stumbling around in the dark, or turning
on the light?

Using debugger means shutting down your brain. Thats what I
think because If I can't understand what I wrote in just 24
lines, I better throw the code and start again.

I really don't see how a debugger can shut down your brain. I
always use a debugger at work.
Well? :-)

--
[mail]: Chuck F (cbfalconer at maineline dot net)
[page]: <http://cbfalconer.home.att.net>
Try the download section.
Oct 4 '08 #22
Richard Heathfield wrote:
CBFalconer said:

<snip>
>the objective of keeping the source of a routine small enough to
fit on a single CRT screen.

I can usually easily read code I wrote thirty years ago, because I
have adhered to this principle [1]. Forty year old code is another
matter, because I hadn't yet learned the key facts. Forty-five is
even worse. The age matters, but not the language.

Presumably, then, fggets is forty years old (and pre-dates the C
language). Here is one CRTful of fggets:

int fggets(char* *ln, FILE *f)
{
int cursize, ch, ix;
char *buffer, *temp;

*ln = NULL; /* default */
if (NULL == (buffer = malloc(INITSIZE))) return NOMEM;
cursize = INITSIZE;

ix = 0;
while ((EOF != (ch = getc(f))) && ('\n' != ch)) {
if (ix >= (cursize - 1)) { /* extend buffer */
cursize += DELTASIZE;
if (NULL == (temp = realloc(buffer, (size_t)cursize))) {
/* ran out of memory, return partial line */
buffer[ix] = '\0';
*ln = buffer;
return NOMEM;
}
buffer = temp;
}
buffer[ix++] = ch;
}

Kinda sawed-off, isn't it?
I don't think you do anyone any favors by republishing my code with
lines snipped off. Maybe I am slow, but it took me a comparison
with the real source to realize what you were doing.

For the benefit of other readers, here are the terminal missing
lines:

}
if ((EOF == ch) && (0 == ix)) {
free(buffer);
return EOF;
}

buffer[ix] = '\0';
if (NULL == (temp = realloc(buffer, (size_t)ix + 1))) {
*ln = buffer; /* without reducing it */
}
else *ln = temp;
return OK;
} /* fggets */
/* End of ggets.c */

--
[mail]: Chuck F (cbfalconer at maineline dot net)
[page]: <http://cbfalconer.home.att.net>
Try the download section.
Oct 4 '08 #23
CBFalconer said:
Chad wrote:
>arnuld <sunr...@invalid.addresswrote:
>>Ian Collins wrote:

Which do you prefer, stumbling around in the dark, or turning
on the light?

Using debugger means shutting down your brain. Thats what I
think because If I can't understand what I wrote in just 24
lines, I better throw the code and start again.

I really don't see how a debugger can shut down your brain. I
always use a debugger at work.

Well? :-)
Now THAT was NOT NICE!

--
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
Oct 4 '08 #24
CBFalconer said:
Richard Heathfield wrote:
>CBFalconer said:

<snip>
>>the objective of keeping the source of a routine small enough to
fit on a single CRT screen.

I can usually easily read code I wrote thirty years ago, because I
have adhered to this principle [1]. Forty year old code is another
matter, because I hadn't yet learned the key facts. Forty-five is
even worse. The age matters, but not the language.

Presumably, then, fggets is forty years old (and pre-dates the C
language). Here is one CRTful of fggets:
[incomplete rendition of fggets snipped]
>>
Kinda sawed-off, isn't it?

I don't think you do anyone any favors by republishing my code with
lines snipped off.
I was simply illustrating that your claim - "keeping the source of a
routine small enough to fit on a single CRT screen" - is not matched by
your code.

--
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
Oct 4 '08 #25
Richard Heathfield wrote:
CBFalconer said:
>Richard Heathfield wrote:
>>CBFalconer said:

<snip>

the objective of keeping the source of a routine small enough to
fit on a single CRT screen.

I can usually easily read code I wrote thirty years ago, because I
have adhered to this principle [1]. Forty year old code is another
matter, because I hadn't yet learned the key facts. Forty-five is
even worse. The age matters, but not the language.
Presumably, then, fggets is forty years old (and pre-dates the C
language). Here is one CRTful of fggets:
[incomplete rendition of fggets snipped]
>>Kinda sawed-off, isn't it?
I don't think you do anyone any favors by republishing my code with
lines snipped off.

I was simply illustrating that your claim - "keeping the source of a
routine small enough to fit on a single CRT screen" - is not matched by
your code.
He might gave a large CRT...

--
Ian Collins.
Oct 4 '08 #26
Ian Collins said:
Richard Heathfield wrote:
>CBFalconer said:
<snip>
>>I don't think you do anyone any favors by republishing my code with
lines snipped off.

I was simply illustrating that your claim - "keeping the source of a
routine small enough to fit on a single CRT screen" - is not matched by
your code.
He might gave a large CRT...
Sure, but then someone *else* might have an even larger one, making the
whole argument rather moot.

The Right Size for a function is impossible to quantify, but it *is*
possible to qualify. For machine-generated and *machine-maintained* code,
it doesn't matter from a readability perspective, except when debugging
the generator/maintainer (where, presumably, it will normally be possible
to cut down the size to manageable proportions during the investigation).

For human-generated or human-maintained code, the function should not be so
large that its sheer size makes making changes (or finding bugs)
difficult.

This leads to the rule of thumb that, when writing or maintaining a
function, if you are closing in on a size of function that has
historically proved to cause debugging or maintenance difficulties,
refactor it.

There Is No Line. There's Black, there's White, and there's a whole bunch
of Grey. Try to keep as near the white end of grey as you can without
getting silly about it.

Note that CBFalconer's fggets function was not in fact excessively long.
That was not the point I was making about it. Rather, I was making the
point that an arbitrary rule such as "no more than one screenful" doesn't
really work.

--
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
Oct 4 '08 #27
Richard Heathfield wrote:
CBFalconer said:
>Chad wrote:
>>arnuld <sunr...@invalid.addresswrote:
Ian Collins wrote:

Which do you prefer, stumbling around in the dark, or turning
on the light?

Using debugger means shutting down your brain. Thats what I
think because If I can't understand what I wrote in just 24
lines, I better throw the code and start again.

I really don't see how a debugger can shut down your brain. I
always use a debugger at work.

Well? :-)

Now THAT was NOT NICE!
Anyone that leaves such a gaping opportunity requires it. :-)

--
[mail]: Chuck F (cbfalconer at maineline dot net)
[page]: <http://cbfalconer.home.att.net>
Try the download section.
Oct 4 '08 #28
Richard Heathfield wrote:
>
.... snip ...
>
Note that CBFalconer's fggets function was not in fact excessively
long. That was not the point I was making about it. Rather, I was
making the point that an arbitrary rule such as "no more than one
screenful" doesn't really work.
And the 24 line screen was incidental. I was actually pushing the
rule of seven, which I think you can see if you go back and read.

--
[mail]: Chuck F (cbfalconer at maineline dot net)
[page]: <http://cbfalconer.home.att.net>
Try the download section.
Oct 4 '08 #29
On Fri, 03 Oct 2008 13:28:32 +0100, Chris Dollin wrote:
>Bartc wrote:
Sounds like nonsense to me.
Yes, 40 lines is too long.

okay, forget about general function writing procedure. Don't you think the
while loop (with memory re-allocation) in my function is placed in an odd
place. To me, it feels like, this whole while loop should not be in this
function, or I am just getting confused (emotionally ?):
int get_single_word( char** ppc )
{
unsigned ele_num;
int ch;
size_t word_length, word_length_interval;
char* word_begin;
char* new_mem;

ele_num = 0;

word_length = WORD_SIZE;
word_length_interval = 2;

*ppc = malloc(word_length * sizeof(**ppc));
word_begin = *ppc;
if( NULL == ppc )
{
return GSW_ENOMEM;

}
while( (EOF != (ch = getchar())) && isspace(ch) )
{
continue; /* trailing whitespace */
}
if( EOF != ch )
{
*word_begin++ = ch;
ele_num = 1;
}
while( (EOF != (ch = getchar())) && (! isspace(ch)) )
{
if( (word_length - 1) == ele_num++ )
{
new_mem = realloc( *ppc, (word_length_interval * word_length * sizeof **ppc) );
*ppc = new_mem;

if( new_mem )
{
word_begin = new_mem + (word_begin - *ppc);
word_length *= word_length_interval;
*ppc = new_mem;
}
else
{
*word_begin = '\0';
return GSW_ENORESIZE;
}
}

*word_begin++ = ch;
}
*word_begin = '\0';

return GSW_OK;
}


--
www.lispmachine.wordpress.com
my email is @ the above blog.
Gooogle Groups is Blocked. Reason: Excessive Spamming

Oct 6 '08 #30
Antoninus Twink <no****@nospam.invalidwrote:
On 3 Oct 2008 at 21:51, CBFalconer wrote:
This combines quite nicely with the objective of keeping the source of
a routine small enough to fit on a single CRT screen.

Another glimpse into CBF's stone-age existence. How many clc'ers really
still use a CRT screen, I wonder?
I. They're a lot less blocky than most TFTs - and yes, I _can_ see the
difference, even if most people can't.

Richard
Oct 6 '08 #31
On Fri, 03 Oct 2008 17:31:23 -0700, Barry Schwarz wrote:
>arnuld wrote:
You use isspace to detect whitespace. isspace will return true for
several other characters besides these three.
I mean whatever whitespace there is, newlines, tabs etc etc. I will change
the comments to reflect this.
> if( NULL == ppc )
Surely this has been mentioned before. ppc contains the address of
pword in main. It can never be NULL. You probably meant *ppc.
Oh.. my .. I reall don't understand why the program was working with this
bug.
And I know your excessive vertical white space has been discussed.
Vertical white space is a matter of style but, to be blunt, yours sucks.
:-\

between function definitions: 2 vertical tabs

between variable assignments and variable 1 vertical tab
initializations:

point where variable assignments and/or 2 vertical tabs
initializations end and other expressions
start:

just before final return statement: 2 vertical tabs

Thats my style. is there something wrong with it ?

While neither condition applies in this case, for practice you could
attempt to compartmentalize some aspect of g_s_w. As an example, you
could move the 16 lines of code that deal with reallocating the space
*ppc points to into a separate function. It would require only three
arguments (the current value of *ppc, the address of word length, and
the address of new_mem).

I tried it but i get dangling pointer errors. See below for code.
They are mutually exclusive in this case so you only need to use one or
the other. If the one you use returns 1, then that condition is true.
(E.g., if you use feof and it returns 1, then you reached end of file
and don't have an error). If the one you use returns 0, then the other
condition is true.

/* a function written in ANSI C, that takes a word from stdin and manages the memory dynamically
*
* Since there is no generally agreed definition of what a 'word' is. I have taken a very simple
* approach:
*
* A word is a contiguous collection of non-whitespace characters. A whitespace is defined
* by isspace().
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
enum { WORD_SIZE = 2 };
enum { GSW_OK, GSW_ENOMEM, GSW_ENORESIZE } ;
int get_single_word( char** );
int alloc_new_mem( char** , char**, char**, size_t* );
int main( void )
{
char* pword;
while( (GSW_OK == get_single_word(&pword)) && ( *pword != 0) )
{
printf("You entered: [%s]\n", pword);
free( pword );
}
return 0;
}


int get_single_word( char** ppc )
{
unsigned ele_num = 0;
int ch = EOF;
size_t word_length = WORD_SIZE;
char* word_begin = NULL;
char* new_mem = NULL;
size_t* pwl = &word_length;

*ppc = malloc(word_length * sizeof(**ppc));
word_begin = *ppc;
if( NULL == *ppc )
{
return GSW_ENOMEM;

}
while( (EOF != (ch = getchar())) && isspace(ch) )
{
continue; /* Leading whitespace */
}
if( EOF != ch )
{
*word_begin++ = ch;
ele_num = 1;
}
while( (EOF != (ch = getchar())) && (! isspace(ch)) )
{
if( (word_length - 1) == ele_num++ )
{
if( GSW_OK != alloc_new_mem( ppc, &word_begin, &new_mem, pwl ) )
{
return GSW_ENORESIZE;
}
}

*word_begin++ = ch;
}

*word_begin = '\0';

return GSW_OK;
}

int alloc_new_mem( char** ppc, char** word_begin, char** new_mem, size_t* pwl )
{
size_t word_length_interval = 2;

*new_mem = realloc( *ppc, (word_length_interval * WORD_SIZE * sizeof **new_mem) );

if( *new_mem )
{
*word_begin = *new_mem + (*word_begin - *ppc);
*pwl *= word_length_interval;
*ppc = *new_mem;
}
else
{
**word_begin = '\0';
return GSW_ENORESIZE;
}

return GSW_OK;
}


========================= OUTPUT =====================
[arnuld@dune ztest]$ gcc -ansi -pedantic -Wall -Wextra get-single-word.c
[arnuld@dune ztest]$ ./a.out
Love
You entered: [Love]
Looooooooooooooooooooooooooooooooooooooooooooooooo oove
*** glibc detected *** realloc(): invalid next size: 0x09068008 ***
Aborted
[arnuld@dune ztest]
--
www.lispmachine.wordpress.com
my email is @ the above blog.
Gooogle Groups is Blocked. Reason: Excessive Spamming

Oct 6 '08 #32
On 6 Oct, 08:46, r...@hoekstra-uitgeverij.nl (Richard Bos) wrote:
Antoninus Twink <nos...@nospam.invalidwrote:
On *3 Oct 2008 at 21:51, CBFalconer wrote:
This combines quite nicely with the objective of keeping the source of
a routine small enough to fit on a single CRT screen.
Another glimpse into CBF's stone-age existence. How many clc'ers really
still use a CRT screen, I wonder?

I. They're a lot less blocky than most TFTs - and yes, I _can_ see the
difference, even if most people can't.
until recently I had dual monitors one flat screen one CRT.
Some of my screen backgrounds were noticibly different on the two
screen and the "blockiness" of the flat screen was apparent.

I know people who still using CRTs (it costs money to
replace them).

--
Nick Keighley
Oct 6 '08 #33
arnuld wrote:
>On Fri, 03 Oct 2008 17:31:23 -0700, Barry Schwarz wrote:
....
>And I know your excessive vertical white space has been discussed.
Vertical white space is a matter of style but, to be blunt, yours sucks.

:-\

between function definitions: 2 vertical tabs

between variable assignments and variable 1 vertical tab
initializations:

point where variable assignments and/or 2 vertical tabs
initializations end and other expressions
start:

just before final return statement: 2 vertical tabs
I suspect that you mean "blank line" rather than "vertical tab". I've
never deliberately used a vertical tab, and I have no idea whether I've
ever seen them, and I've heard that there are many displays and printers
that don't implement them. However, if I understand the relevant
wikipedia article correctly, just as a horizontal tab causes a jump to
the next horizontal tab stop (traditionally, but not necessarily 8
spaces apart), a vertical tab causes a jump to the next vertical tab
stop (traditionally but not necessarily 6 lines apart).
Thats my style. is there something wrong with it ?
Yes, by spreading things out so much, it makes it harder to see
different parts of your program at the same time, whether looking at a
screen display or a printed page. If you really were using the number of
vertical tabs that you specify, the problem would be much worse.
Oct 6 '08 #34
On Mon, 06 Oct 2008 10:51:36 +0000, James Kuyper wrote:

I suspect that you mean "blank line" rather than "vertical tab".

yes.

Yes, by spreading things out so much, it makes it harder to see
different parts of your program at the same time, whether looking at a
screen display or a printed page. If you really were using the number of
vertical tabs that you specify, the problem would be much worse.

I thought vertical tab and blank lines were synonyms. I use blank-lines.

--
www.lispmachine.wordpress.com
my email is @ the above blog.
Oct 6 '08 #35
On Fri, 03 Oct 2008 22:09:38 +0000, Antoninus Twink wrote:
Another glimpse into CBF's stone-age existence. How many clc'ers really
still use a CRT screen, I wonder?
<OT>
me, all the time. I have yet to see a friend of mine who uses TFT. TFT is
very expansive.
</OT>


--
www.lispmachine.wordpress.com
my email is @ the above blog.
Oct 6 '08 #36
arnuld <su*****@invalid.addresswrote:
On Fri, 03 Oct 2008 22:09:38 +0000, Antoninus Twink wrote:
Another glimpse into CBF's stone-age existence. How many clc'ers really
still use a CRT screen, I wonder?

me, all the time. I have yet to see a friend of mine who uses TFT. TFT is
very expansive.
I've never seen one growing larger, but they can be quite expensive.

Richard
Oct 6 '08 #37
On Fri, 03 Oct 2008 10:37:29 -0700, Lew Pitcher wrote:
However, I'll buy it as "development standard" in your shop (assuming
that this is code written for a company, and the code-writing group has
standards wrt function body length).
Nope. This code was written by myself, for myself, only to learn about the
dynamic memory allocation and pointer business.

1) Reduce statements to their most compact form
For example, the 5 line
if ( NULL == ppc )
{
return GSW_ENOMEM;
would become the one line
if (NULL == ppc ) return GSW_ENOMEM;
eliminating four lines,

I will like to see what other clc posters has to say about this say. If
they agree, I will drop this kind into my style-bucket. Personally, I
liked it :)


and the 4 line
while( (EOF != (ch = getchar())) && isspace(ch) )
{
continue; /* Leading whitespace */
}
would lose three lines to become
while( (EOF != (ch = getchar())) && isspace(ch) ) ;

Same as earlier.
2) Combine commonalities into single elements. The two while() loops
have some common test elements; you could combine the two loops
into
one, and distinguish the differences within the loop body

3) Create new functions from old logic. Your get_single_word() function
works in four phases:
1 - sanity check,
2 - skip leading whitespace,
3 - empty word handler,
4 - word string handler
Break one or more of these out into it's own function, and modify
get_single_word() to utilize the new function instead of its own
inline code. A good candidate might be the word string handler logic.

Hm.. thta the logic I was looking for.

...SNIP...
From what I can see, your main() only looks for a
GSW_OK; /all/ other returns cause a silent program termination.

is that worse ?
Lew
(posted from google groups due to failure with my
regular nntp service)

Thats why I did not see this post earlier. I got it when I unblocked the
google groups.
Thanks
--
www.lispmachine.wordpress.com
my email is @ the above blog.
Oct 6 '08 #38
please leave attributions in

On 6 Oct, 12:38, arnuld <sunr...@invalid.addresswrote:
1) Reduce statements to their most compact form
For example, the 5 line
if ( NULL == ppc )
{
return GSW_ENOMEM;
}
>
would become the one line
if (NULL == ppc ) return GSW_ENOMEM;
eliminating four lines,

I will like to see what other clc posters has to say about this say. If
they agree, I will drop this kind into my style-bucket. Personally, I
liked it :)
if you like it and it's reasonably clear and you don't have any
coding standards you have to comply with then stick with it!

I'd code it like this:

if (NULL == ppc)
return GSW_ENOMEM;

At least one clc regular never ommits the brackets and
would do something similar to you. The reasoning is that
adding another line to the while body is error prone
and you could forget to add the brackets.

At least one fairly regular poster would dislike the one
line version as he would view it as debugger hostile.

and the 4 line
while( (EOF != (ch = getchar())) && isspace(ch) )
{
continue; /* Leading whitespace */
}
would lose three lines to become
while( (EOF != (ch = getchar())) && isspace(ch) ) ;
I'd definitly have the ";" on a different line as
I find the single line version *very* easy to misread
<snip>

--
Nick Keighley
Oct 6 '08 #39
arnuld wrote:
....
>1) Reduce statements to their most compact form
For example, the 5 line
if ( NULL == ppc )
{
return GSW_ENOMEM;
would become the one line
if (NULL == ppc ) return GSW_ENOMEM;
eliminating four lines,


I will like to see what other clc posters has to say about this say. If
they agree, I will drop this kind into my style-bucket. Personally, I
liked it :)
The compact form presents problems due to the fact that the if condition
and the return statement are on the same line. The most serious one is
that in many (most?) debuggers, it's only possible to set a single break
point on a line. If you want to set a break point on the return
statement, you're forced to put a break point of then entire if
statement. The result is that the break point will trigger every single
time the if() is executed, regardless of whether or not the return
statement is executed.

The second problem is that compilers will identify the location of a bug
by the line number. It sometimes happens that the same diagnostic
message could be referring to either the 'if' condition, or the return
statement; putting them on separate lines will make it easier to figure
out where the actual error is.

I therefore always put each statement on a separate line. But this is a
matter of programming style, there are arguments for other approaches.
Oct 6 '08 #40
arnuld <su*****@invalid.addresswrites:
>On Fri, 03 Oct 2008 13:28:32 +0100, Chris Dollin wrote:
>>Bartc wrote:
Sounds like nonsense to me.
>Yes, 40 lines is too long.


okay, forget about general function writing procedure. Don't you think the
while loop (with memory re-allocation) in my function is placed in an odd
place. To me, it feels like, this whole while loop should not be in this
function, or I am just getting confused (emotionally ?):
You can write it that way, but not because "the while loop should not
be in this function" but because you can find a part (the includes the
while loop) that makes sense as a separate function.

For another example, when you've finished, you will find that in two
places you need to change the size of an allocated piece of memory. I
often write the code to do this (and to track the new size) as a
function because I know I may need it in more than one place. That is
not the only reason to write a function, but it is a good one.

On another topic you state your style is to:

| between function definitions: 2 vertical tabs
|
| between variable assignments and variable 1 vertical tab
| initializations:

I think you mean between declarations and first assignment.

| point where variable assignments and/or 2 vertical tabs
| initializations end and other expressions
| start:
|
| just before final return statement: 2 vertical tabs

I would not do this, but as I have said before, style is not worth
arguing about. However, you don't follow your own rules. In the
code below, I have left all blank lines quoted -- I usually omit them
when they come next to my added remarks.
int get_single_word( char** ppc )
{
unsigned ele_num;
int ch;
size_t word_length, word_length_interval;
char* word_begin;
char* new_mem;

ele_num = 0;

word_length = WORD_SIZE;
word_length_interval = 2;

*ppc = malloc(word_length * sizeof(**ppc));
word_begin = *ppc;
One one of the blank lines above is accounted for by your rules.
>

if( NULL == ppc )
{
return GSW_ENOMEM;

}
and the one before the }?
>

while( (EOF != (ch = getchar())) && isspace(ch) )
{
continue; /* trailing whitespace */
}
if( EOF != ch )
{
*word_begin++ = ch;
ele_num = 1;
}

Here you have three pairs of blank lines. What rules accounts for
these?
while( (EOF != (ch = getchar())) && (! isspace(ch)) )
{
if( (word_length - 1) == ele_num++ )
{
new_mem = realloc( *ppc, (word_length_interval * word_length * sizeof **ppc) );
*ppc = new_mem;
Here there is only one. I can't see why.
if( new_mem )
{
word_begin = new_mem + (word_begin - *ppc);
word_length *= word_length_interval;
*ppc = new_mem;
}
else
{
*word_begin = '\0';
return GSW_ENORESIZE;
}
}
Which rule governs this space?
*word_begin++ = ch;
}

and again which rules make you put two here...
*word_begin = '\0';
and only one here when your rule is for two before the final return?
return GSW_OK;
}
--
Ben.
Oct 6 '08 #41
On Fri, 03 Oct 2008 21:18:17 +1300, Ian Collins wrote:
Have you checked with a debugger to see why?

I thought using a Debugger (for such small programs) kills one's
understanding of language, thats why I never used any debugger.

--
www.lispmachine.wordpress.com
my email is @ the above blog.
Gooogle Groups is Blocked. Reason: Excessive Spamming

Oct 6 '08 #42
arnuld wrote:
Lew Pitcher wrote:
.... snip ...
>
>1) Reduce statements to their most compact form
For example, the 5 line
if ( NULL == ppc )
{
return GSW_ENOMEM;
would become the one line
if (NULL == ppc ) return GSW_ENOMEM;
eliminating four lines,

I will like to see what other clc posters has to say about this
say. If they agree, I will drop this kind into my style-bucket.
Personally, I liked it :)
That one depends on your debugging practices. If you want to be
able to trap after the decision, but before executing the return,
you want a separate line, such as:

if (!ppc)
return GSW_ENOMEM;

and note that you don't need the "NULL =" portion at all.

I very rarely use a debugger, so I would write it as:

if (!ppc) return GSW_ENOMEM;

--
[mail]: Chuck F (cbfalconer at maineline dot net)
[page]: <http://cbfalconer.home.att.net>
Try the download section.
Oct 6 '08 #43
Nick Keighley wrote:
arnuld <sunr...@invalid.addresswrote:
.... snip ...
>
please leave attributions in
>and the 4 line

while( (EOF != (ch = getchar())) && isspace(ch) )
{
continue; /* Leading whitespace */
}

would lose three lines to become
while( (EOF != (ch = getchar())) && isspace(ch) ) ;

I'd definitly have the ";" on a different line as
I find the single line version *very* easy to misread
Which is why the 'continue' is useful here, as in:

while ((EOF != (ch = getchar()))} && isspace(ch)) continue;

Note the extra (), which to me solidifies what is tested.

--
[mail]: Chuck F (cbfalconer at maineline dot net)
[page]: <http://cbfalconer.home.att.net>
Try the download section.
Oct 6 '08 #44
arnuld <su*****@invalid.addresswrites:
>On Fri, 03 Oct 2008 10:37:29 -0700, Lew Pitcher wrote:
1) Reduce statements to their most compact form
For example, the 5 line
if ( NULL == ppc )
{
return GSW_ENOMEM;
would become the one line
if (NULL == ppc ) return GSW_ENOMEM;
eliminating four lines,


I will like to see what other clc posters has to say about this say. If
they agree, I will drop this kind into my style-bucket. Personally, I
liked it :)
I always put a line break between an "if" statement and any
statement conditional upon it. I find it easier to read.
--
Ben Pfaff
http://benpfaff.org
Oct 6 '08 #45
On Mon, 06 Oct 2008 10:20:32 +0500, arnuld <su*****@invalid.address>
wrote:
>okay, forget about general function writing procedure. Don't you think the
while loop (with memory re-allocation) in my function is placed in an odd
place. To me, it feels like, this whole while loop should not be in this
function, or I am just getting confused (emotionally ?):
I don't know about emotionally, but you are getting confused about
which is the current version of your routine.
>

int get_single_word( char** ppc )
{
unsigned ele_num;
int ch;
size_t word_length, word_length_interval;
char* word_begin;
char* new_mem;

ele_num = 0;

word_length = WORD_SIZE;
word_length_interval = 2;

*ppc = malloc(word_length * sizeof(**ppc));
word_begin = *ppc;
if( NULL == ppc )
This is still the wrong test.
{
return GSW_ENOMEM;
If you reach this statement, the statement above that calls malloc
invoked undefined behavior.
>
}
while( (EOF != (ch = getchar())) && isspace(ch) )
{
continue; /* trailing whitespace */
You corrected the comment on a previous version. Why is it back to
being incorrect now?
}
if( EOF != ch )
{
*word_begin++ = ch;
ele_num = 1;
}
while( (EOF != (ch = getchar())) && (! isspace(ch)) )
{
if( (word_length - 1) == ele_num++ )
{
new_mem = realloc( *ppc, (word_length_interval * word_length * sizeof **ppc) );
*ppc = new_mem;
This still creates a memory leak when realloc fails.
>
if( new_mem )
{
word_begin = new_mem + (word_begin - *ppc);
word_length *= word_length_interval;
*ppc = new_mem;
}
else
{
*word_begin = '\0';
return GSW_ENORESIZE;
}
}

*word_begin++ = ch;
}
*word_begin = '\0';

return GSW_OK;
}
--
Remove del for email
Oct 7 '08 #46
On Mon, 06 Oct 2008 12:46:42 +0500, arnuld <su*****@invalid.address>
wrote:
>On Fri, 03 Oct 2008 17:31:23 -0700, Barry Schwarz wrote:
>>arnuld wrote:

>You use isspace to detect whitespace. isspace will return true for
several other characters besides these three.

I mean whatever whitespace there is, newlines, tabs etc etc. I will change
the comments to reflect this.
>> if( NULL == ppc )
>Surely this has been mentioned before. ppc contains the address of
pword in main. It can never be NULL. You probably meant *ppc.

Oh.. my .. I reall don't understand why the program was working with this
bug.
It worked because malloc never failed.
snip white space discussion
>While neither condition applies in this case, for practice you could
attempt to compartmentalize some aspect of g_s_w. As an example, you
could move the 16 lines of code that deal with reallocating the space
*ppc points to into a separate function. It would require only three
arguments (the current value of *ppc, the address of word length, and
the address of new_mem).


I tried it but i get dangling pointer errors. See below for code.
Except you never showed us the errors.
>
/* a function written in ANSI C, that takes a word from stdin and manages the memory dynamically
*
* Since there is no generally agreed definition of what a 'word' is. I have taken a very simple
* approach:
*
* A word is a contiguous collection of non-whitespace characters. A whitespace is defined
* by isspace().
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
enum { WORD_SIZE = 2 };
enum { GSW_OK, GSW_ENOMEM, GSW_ENORESIZE } ;
int get_single_word( char** );
int alloc_new_mem( char** , char**, char**, size_t* );
int main( void )
{
char* pword;
while( (GSW_OK == get_single_word(&pword)) && ( *pword != 0) )
{
printf("You entered: [%s]\n", pword);
free( pword );
}
return 0;
}


int get_single_word( char** ppc )
{
unsigned ele_num = 0;
int ch = EOF;
size_t word_length = WORD_SIZE;
char* word_begin = NULL;
char* new_mem = NULL;
size_t* pwl = &word_length;

*ppc = malloc(word_length * sizeof(**ppc));
word_begin = *ppc;
if( NULL == *ppc )
{
return GSW_ENOMEM;

}
while( (EOF != (ch = getchar())) && isspace(ch) )
{
continue; /* Leading whitespace */
}
if( EOF != ch )
{
*word_begin++ = ch;
ele_num = 1;
}
while( (EOF != (ch = getchar())) && (! isspace(ch)) )
{
if( (word_length - 1) == ele_num++ )
{
if( GSW_OK != alloc_new_mem( ppc, &word_begin, &new_mem, pwl ) )
Strange that you used the & operator for word_begin and new_mem but
felt the need for a new variable for &word_length.
> {
return GSW_ENORESIZE;
}
}

*word_begin++ = ch;
}

*word_begin = '\0';

return GSW_OK;
}

int alloc_new_mem( char** ppc, char** word_begin, char** new_mem, size_t* pwl )
{
size_t word_length_interval = 2;

*new_mem = realloc( *ppc, (word_length_interval * WORD_SIZE * sizeof **new_mem) );
Look at the realloc statement in your previous code. The two
arguments should evaluate identically. Hint: In this code all three
terms of the second argument are constant. That is not what your
original code did.
>
if( *new_mem )
{
*word_begin = *new_mem + (*word_begin - *ppc);
*pwl *= word_length_interval;
This is now a lie and you will write beyond the end of allocated
memory invoking undefined behavior
*ppc = *new_mem;
}
else
{
**word_begin = '\0';
return GSW_ENORESIZE;
}

return GSW_OK;
}


========================= OUTPUT =====================
[arnuld@dune ztest]$ gcc -ansi -pedantic -Wall -Wextra get-single-word.c
[arnuld@dune ztest]$ ./a.out
Love
You entered: [Love]
Loooooooooooooooooooooooooooooooooooooooooooooooo ooove
*** glibc detected *** realloc(): invalid next size: 0x09068008 ***
This error makes no sense and is probably the result of writing beyond
your allocation. While the value you computed in the call to realloc
is not the one you wanted, it is a valid value (4).

I don't see any dangling pointers.

--
Remove del for email
Oct 7 '08 #47
On October 6, 2008 07:38, in comp.lang.c, arnuld (su*****@invalid.address)
wrote:
>On Fri, 03 Oct 2008 10:37:29 -0700, Lew Pitcher wrote:
[snip]
>From what I can see, your main() only looks for a
GSW_OK; /all/ other returns cause a silent program termination.


is that worse ?
Worse than what?

As I see it, you only care if the function returns GSW_OK or not. Thus, all
your existing error values are suspect (you want either GSW_OK or !GSW_OK),
and adding another error value just compounds the situation.

Personally, I'd code in error values based on whether or not something
unique has to happen for them. In your case, there are two unique follow-on
actions; one that happens when everything works, and one that happens when
something fails. This implies that two return values would suffice for your
logic.

On the other hand, if you intended your calling function to take some
remedial action, or report on the cause of a failure situation, having
multiple error return values would be handy.
--
Lew Pitcher

Master Codewright & JOAT-in-training | Registered Linux User #112576
http://pitcher.digitalfreehold.ca/ | GPG public key available by request
---------- Slackware - Because I know what I'm doing. ------
Oct 7 '08 #48
On 6 Oct, 22:02, Ben Pfaff <b...@cs.stanford.eduwrote:
arnuld <sunr...@invalid.addresswrites:
On Fri, 03 Oct 2008 10:37:29 -0700, Lew Pitcher wrote:
1) Reduce statements to their most compact form
* *For example, the 5 line
* * * if ( NULL == ppc )
* * * * *{
* * * * * *return GSW_ENOMEM;
* *would become the one line
* * * if (NULL == ppc ) return GSW_ENOMEM;
* *eliminating four lines,
I will like to see what other clc posters has to say about this say. If
they agree, I will drop this kind into my style-bucket. Personally, I
liked it :)

I always put a line break between an "if" statement and any
statement conditional upon it. *I find it easier to read.
Also, having the statement on a separate line makes code
coverage tests more useful. For example, gcov has line based
granularity and can tell you how often each line has been
executed in your test suite. If the statement and
the condition appear on the same line, then it
generates less accurate reports.
Oct 8 '08 #49
On 6 Oct, 08:46, arnuld <sunr...@invalid.addresswrote:
On Fri, 03 Oct 2008 17:31:23 -0700, Barry Schwarz wrote:
And I know your excessive vertical white space has been discussed.
Vertical white space is a matter of style but, to be blunt, yours sucks..

*:-\

*between function definitions: * * * * * * * 2 vertical tabs

*between variable assignments and variable * 1 vertical tab
*initializations:

*point where variable assignments and/or * * 2 vertical tabs
*initializations end and other expressions
*start:

*just before final return statement: * * * * 2 vertical tabs

Thats my style. is there something wrong with it ?
The first 2 are perfectly reasonable, except that the
2nd one makes no sense -- do you mean that you put
a blank line between declarations and statements? I see
no point in putting more than one blank line before return, since
presumably it will be immediately followed by a line with
just a closing brace and 2 blank lines. Also in the third
point, I assume you mean that you break your functions into
3 basic components: declarations, "initializations" (simple
statements of the form var = value), and other statements.
In that case, a single blank line between "initializations"
and following statements is sufficient. (I'm putting
"initializations" in quotes here to distinguish your
apparent usage of the word to mean a simple statement from
the more natural interpretation of a declaration with an
initializer.) However, those are not the things that cause
your style to be unbearable. It is your use of braces that
is deplorable.

Oct 8 '08 #50

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

1
by: Luis | last post by:
I have a few input buttons at the end of an asp page. When I change the mime-type of the asp page to create a Word Document which the user can save, the input buttons are not displayed. Is there a...
13
by: Eric Lilja | last post by:
Hello, consider the following complete program: #include <assert.h> #include <ctype.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <time.h> static int...
8
by: lisaj | last post by:
I'm having huge difficulties producing a script for this: Write a javascript programme that will prompt for, and accept from the user, an input string which contains at least 8 characters. It...
20
by: dmurray14 | last post by:
Hey guys, I'm a C++ newbie here - I've messed with VB, but I mostly stick to web languages, so I find C++ to be very confusing at times. Basically, I am trying to import a text file, but I want...
1
by: Chris Carlen | last post by:
Hi: I'm writing a Python program, a hex line editor, which takes in a line of input from the user such as: -e 01 02 "abc def" 03 04 Trouble is, I don't want to split the quoted part where...
11
by: arnuld | last post by:
C takes input character by character. I did not find any Standard Library function that can take a word as input. So I want to write one of my own to be used with "Self Referential Structures" of...
24
by: arnuld | last post by:
I have a function named getword that read every single input from std. input. WHAT I WANTED: I want it read the word if it has less than or equal to 30 characters. Anything else beyond that...
209
by: arnuld | last post by:
I searched the c.l.c archives provided by Google as Google Groups with "word input" as the key words and did not come up with anything good. C++ has std::string for taking a word as input from...
1
by: arnuld | last post by:
On Mon, 29 Sep 2008 15:16:56 +0100, Ben Bacarisse wrote: An abstract overview of my own program by Ben had helped me focus on the design issue first. I came to know that whole problem went...
21
by: arnuld | last post by:
I have created a program to print the input words on stdout. Input is taken dynamically from stdin. In each word, each input character is allocated dynamically. I have ran this program with a file...
0
by: DolphinDB | last post by:
Tired of spending countless mintues downsampling your data? Look no further! In this article, you’ll learn how to efficiently downsample 6.48 billion high-frequency records to 61 million...
1
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: Vimpel783 | last post by:
Hello! Guys, I found this code on the Internet, but I need to modify it a little. It works well, the problem is this: Data is sent from only one cell, in this case B5, but it is necessary that data...
1
by: PapaRatzi | last post by:
Hello, I am teaching myself MS Access forms design and Visual Basic. I've created a table to capture a list of Top 30 singles and forms to capture new entries. The final step is a form (unbound)...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
1
by: Shællîpôpï 09 | last post by:
If u are using a keypad phone, how do u turn on JavaScript, to access features like WhatsApp, Facebook, Instagram....
0
by: af34tf | last post by:
Hi Guys, I have a domain whose name is BytesLimited.com, and I want to sell it. Does anyone know about platforms that allow me to list my domain in auction for free. Thank you
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.