469,268 Members | 942 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,268 developers. It's quick & easy.

Any way to take a word as input from stdin ?

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 stdin. C takes input
in 2 ways:

1) as a character, etchar()
2) as a whole line, fgets()
as C programmer, are we supposed to create a get_word function everytime
when we need a words as input from stdin ( e.g. terminal)
--
www.lispmachine.wordpress.com
my email is @ the above blog.
Google Groups is Blocked. Reason: Excessive Spamming

Sep 10 '08
209 7556
Nick Keighley <ni******************@hotmail.comwrote:
On 17 Sep, 07:59, arnuld <sunr...@invalid.addresswrote:
..aye.... , so lets learn the practical aspects like error-recovery too. I
don't like academic solutions BTW

when, exactly, did "academic" become a pejorative term?
When testing became a more reliable approach to checking for bugs than
program proofs.
"Yes it works in practice - but does it work in theory?"

"There is nothing as practical as a good theory."
"Beware of the above code; I haven't tested it, but only proved it
correct."

Mind you, there _is_ a bit of difference between "academic" and "looking
this up in a beginners' textbook should show the way forward".

Richard
Sep 19 '08 #151
arnuld said:
>On Fri, 19 Sep 2008 08:55:41 +0000, Richard Heathfield wrote:
>>arnuld said:
I understood completely the *pw_begin++ part, the confusion remains in
in the Right Hand Side, the pword has triple levels of indirection ***.
>No, it doesn't. Read the code again: pword is of type char *.

Eh.. I think I am overwhelmed by the power pointers and arrays provide,
as with great power comes great responsibility, like Spiderman said.
Anyway, I have created little edited version of get_single_word and I
wrote it fully without taking a single look at the clc posted solutions.
I am posting it here as now it contains my own style of programming. See
if you notice something god or bad.
I had a quick look through, and noticed one thing: in the event of a
realloc failure, you return an error code which indicates that the parsing
was incomplete because the memory block could not be re-sized. That's
fine, but it would be pleasant if the caller were able to attempt to
recover, and you can help with this goal by null-terminating the string
before returning (which means that you need to choose to resize just
*before* you run out of memory, as you'll need one place for the
terminator).

Apart from that, my quick glance didn't reveal anything particularly
untoward.

--
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
Sep 19 '08 #152
arnuld <su*****@invalid.addresswrites:
<snip>
This is final version and after that we will
start discussing get_words() and next:
<snip>
int get_single_word( char** ppc )
{
unsigned idx;
int ch;
size_t arr_size;
char* pw_begin;
char* new_mem;

arr_size = WORD_SIZE;
*ppc = malloc(arr_size * sizeof(**ppc));
pw_begin = *ppc;
if( NULL == ppc )
{
return GSW_ENOMEM;

}
while( (EOF != (ch = getchar())) && isspace(ch) )
{
continue; /* trailing whitespace */
}
if( EOF != ch )
{
*pw_begin++ = ch;
}
for( idx = 0; (EOF != (ch = getchar())) && (! isspace(ch)); ++idx )
{
if( WORD_SIZE == idx )
{
new_mem = realloc( *ppc, (2 * WORD_SIZE * sizeof **ppc) );
This looks very odd. You realloc once when idx == WORD_SIZE but if
2 * WORD_SIZE is not enough, then what?
*ppc = new_mem;

if( NULL == new_mem )
{
return GSW_ENORESIZE;
}
You have both a memory leak and logic error here. As I pointed out
before, when you allocate new memory you must make pw_begin point to
the right place. You've change the code, but not made it correct
yet. If the realloc is OK, you need pw_begin to point (about) idx
places into new_mem.

The leak is caused only when realloc fails. You set *ppc to NULL (the
return from realloc) but that loses the pointer to the word so it can
now ever be freed.
}

*pw_begin++ = ch;
You need also to check all your index counts. This will write the at
index 3 into a string of length 3 (i.e. out of bounds) and the text
for reallocation is wrong as well. You need to realloc space when idx
== WORD_SIZE - 2 (I think) since idx in incremented late and you must
have space for the null. Anyway, check them (and use valgrind).
}
*pw_begin = '\0';

return GSW_OK;
}
--
Ben.
Sep 19 '08 #153
Ben Bacarisse said:
arnuld <su*****@invalid.addresswrites:
<snip>
>>
for( idx = 0; (EOF != (ch = getchar())) && (! isspace(ch)); ++idx )
{
if( WORD_SIZE == idx )
{
new_mem = realloc( *ppc, (2 * WORD_SIZE * sizeof **ppc) );

This looks very odd. You realloc once when idx == WORD_SIZE but if
2 * WORD_SIZE is not enough, then what?
Oh, good spot. I *showed* him how to do this. It didn't occur to me to
check that he had bothered to listen. Sheesh, furrfu, etc.
>*ppc = new_mem;

if( NULL == new_mem )
{
return GSW_ENORESIZE;
}

You have both a memory leak and logic error here. As I pointed out
before, when you allocate new memory you must make pw_begin point to
the right place. You've change the code, but not made it correct
yet. If the realloc is OK, you need pw_begin to point (about) idx
places into new_mem.
Another good spot.

Again, I showed him how to do this properly. Perhaps he has reading
difficulties?

--
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
Sep 19 '08 #154
On Fri, 19 Sep 2008 12:05:24 +0100, Ben Bacarisse wrote:
>arnuld <su*****@invalid.addresswrites:
for( idx = 0; (EOF != (ch = getchar())) && (! isspace(ch)); ++idx )
{
if( WORD_SIZE == idx )
{
new_mem = realloc( *ppc, (2 * WORD_SIZE * sizeof **ppc) );
This looks very odd. You realloc once when idx == WORD_SIZE but if
2 * WORD_SIZE is not enough, then what?

How about adding idx = 0; after new_mem line ?
> *ppc = new_mem;

if( NULL == new_mem )
{
return GSW_ENORESIZE;
}
You have both a memory leak and logic error here. As I pointed out
before, when you allocate new memory you must make pw_begin point to
the right place. You've change the code, but not made it correct
yet. If the realloc is OK, you need pw_begin to point (about) idx
places into new_mem.

you pointed it out in get_words code but this function you quoted is
get_single_word. ppc is the pointer to pointer to char that you get from
function argument, which will be passed to free() in main(). pw_begin is
used to put input characters into the array. so both ppc and pw_begin need
to point to new_mem. right ?
The leak is caused only when realloc fails. You set *ppc to NULL (the
return from realloc) but that loses the pointer to the word so it can
now ever be freed.
okay, I have added an else statement aligning with if clause.
> *pw_begin++ = ch;

You need also to check all your index counts. This will write the at
index 3 into a string of length 3 (i.e. out of bounds) and the text for
reallocation is wrong as well. You need to realloc space when idx ==
WORD_SIZE - 2 (I think) since idx in incremented late and you must have
space for the null. Anyway, check them (and use valgrind).
I really did not understand what you mean. I mean, i am unable to
comprehend what you said. This is my new code with buggy output:
/* A program that takes a single word from input
* it uses a while loop and dynamic memory allocation to take
* continuous input form user
*
* VERSION: 1.1
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
enum { WORD_SIZE = 3 };
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);
}
return 0;
}


int get_single_word( char** ppc )
{
unsigned idx;
int ch;
size_t arr_size;
char* pw_begin;
char* new_mem;

arr_size = WORD_SIZE;
*ppc = malloc(arr_size * sizeof(**ppc));
pw_begin = *ppc;
if( NULL == ppc )
{
return GSW_ENOMEM;

}
while( (EOF != (ch = getchar())) && isspace(ch) )
{
continue; /* trailing whitespace */
}
if( EOF != ch )
{
*pw_begin++ = ch;
}
for( idx = 0; (EOF != (ch = getchar())) && (! isspace(ch)); ++idx )
{
if( (WORD_SIZE - 1) == idx ) /* -1 for '\0' character*/
{
new_mem = realloc( *ppc, (2 * WORD_SIZE * sizeof **ppc) );

if( NULL == new_mem )
{
*pw_begin = '\0';
return GSW_ENORESIZE;
}
else
{
pw_begin = *ppc = new_mem;
idx = 0;
}
}

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

return GSW_OK;
}


========================= OUTPUT =======================================

[arnuld@dune ztest]$ gcc -ansi -pedantic -Wall -Wextra get-single-word.c
[arnuld@dune ztest]$ ./a.out
Richard Heathfield
You entered: [rd]
You entered: [d]
Party
You entered: [ty]
[arnuld@dune ztest]$


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

Sep 22 '08 #155
On Fri, 19 Sep 2008 12:05:24 +0100, Ben Bacarisse wrote:

You have both a memory leak and logic error here. As I pointed out
before, when you allocate new memory you must make pw_begin point to
the right place. You've change the code, but not made it correct
yet. If the realloc is OK, you need pw_begin to point (about) idx
places into new_mem.
Well, pointing pw_begin to realloc()ed memory makes whole program beahving
in a weired way, like printing only last 2 characters of an input word.
See my other reply with code and output.


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

Sep 22 '08 #156
On Mon, 15 Sep 2008 16:42:47 +1200, Ian Collins <ia******@hotmail.com>
wrote:
arnuld wrote:

I think std::string in C++ defines what exactly *definition* of word is.
you see even if you put a line as input, std::string will automatically
dissect it into separate words.
No, it will not.

<OTThe input stream tokenises the input. The C++ standard defines how
formatted input is tokenised. </OT>
<OTHe's closer than you are. The istream doesn't tokenize; the
extractor (aka >>) for std::string does. The standard does define
this, although as dependent on locale functionality which is
implementation-dependent -- but a locale that significantly changes
whitespace would be perverse.

- formerly david.thompson1 || achar(64) || worldnet.att.net
Sep 22 '08 #157
On Thu, 11 Sep 2008 16:23:03 +0100, Chris Dollin <ch**********@hp.com>
wrote:
arnuld wrote:
I have not checked it but will be doing it later. The only one question
that keeps on popping up into my mind is "Why C was not designed to have
this feature ? ".
It's not clear (to me) if 'this feature' is input of unbounded-length
lines or of parsing words (defined as non-white); but either way ...
Because C was designed for /implementing/ this feature; as a bare-bones
systems programming language.
Actually it was designed primarily to implement an OS, which by its
nature has a pretty significant overlap with language support and
similar low-level utilities, although in practice it has been used for
a much wider range of tools and applications.
That reminds of an article "Back to Basics" by Joel
Spolsky where he said that we have null terminated strings in C whihc
are much slower than PASCAL strings

I'd be interested in real evidence for this claim. Real, as in, it
happened in these programs and couldn't be eliminated by straightforward
fixes, rather than contrived examples or beginners gotchas.
Terminated strings in general are faster for some things and in some
cases and slower for others than counted. Especially in strict
sequential execution (little or no overlap, little or no caching, no
speculation) which was the common case then. If you use terminated, a
terminator of null is usually fastest, because many machines can
'compare' to zero more efficiently than any other value.

But since C was not originally envisioned/expected to be used for very
extensive text or string processing, I think the decision was more
(mostly) what was easy and fast to _implement_.
not by choice but by force, as C was
developed on PDP-7, which had ASCIZ table, which required strings to be Z
terminated ( Z means ZERO).

That seems ... unlikely ... to me. Just because one's assembler has
an ASCIZ directive doesn't mean one has to use it; even if one does,
one can perfectly well also associate a length with a string as well
as a null terminator.
Agree (both). Morever C wasn't developed on the -7; B was, but the
evolution into C (which occurred in several stages) began on the -11.
I'm pretty sure no DEC before VAX had standard hardware support for
either kind of string, although some -11 models did have an optional
'commercial instruction set' tailored for COBOL (or DIBOL?).

- formerly david.thompson1 || achar(64) || worldnet.att.net
Sep 22 '08 #158
On Fri, 19 Sep 2008 11:17:37 +0000, Richard Heathfield wrote:
Oh, good spot. I *showed* him how to do this. It didn't occur to me to
check that he had bothered to listen. Sheesh, furrfu, etc.

I *did* bother to listen. The only problem is using array subscripting
kills my ability to understand pointers. I think a C newbie needs to use
lots of pointers if he wants to understand them. Thats why I am not using
array subscripting.

Another good spot.

Again, I showed him how to do this properly. Perhaps he has reading
difficulties?

I have array and pointer understanding difficulties. No normal
difficulties in reading English.


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

Sep 22 '08 #159
On Fri, 19 Sep 2008 10:19:48 +0000, Richard Heathfield wrote:

I had a quick look through, and noticed one thing: in the event of a
realloc failure, you return an error code which indicates that the parsing
was incomplete because the memory block could not be re-sized. That's
fine, but it would be pleasant if the caller were able to attempt to
recover, and you can help with this goal by null-terminating the string
before returning (which means that you need to choose to resize just
*before* you run out of memory, as you'll need one place for the
terminator).
That's fixed now.


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

Sep 22 '08 #160
arnuld <su*****@invalid.addresswrites:
>On Fri, 19 Sep 2008 12:05:24 +0100, Ben Bacarisse wrote:
>>arnuld <su*****@invalid.addresswrites:
for( idx = 0; (EOF != (ch = getchar())) && (! isspace(ch)); ++idx )
{
if( WORD_SIZE == idx )
{
new_mem = realloc( *ppc, (2 * WORD_SIZE * sizeof **ppc) );
>This looks very odd. You realloc once when idx == WORD_SIZE but if
2 * WORD_SIZE is not enough, then what?

How about adding idx = 0; after new_mem line ?
That will not make the memory allocation any bigger. It is more
usual just keep track of the current size and double it every time
you run out of space.
>You have both a memory leak and logic error here. As I pointed out
before, when you allocate new memory you must make pw_begin point to
the right place. You've change the code, but not made it correct
yet. If the realloc is OK, you need pw_begin to point (about) idx
places into new_mem.

you pointed it out in get_words code but this function you quoted is
get_single_word.
Yes, I forgot that. The idea is exactly the same though.
ppc is the pointer to pointer to char that you get from
function argument, which will be passed to free() in main().
Yes, I get that but not why you are telling me this! You seem to
understand and fix the leak below.
pw_begin is
used to put input characters into the array. so both ppc and pw_begin need
to point to new_mem. right ?
No. *ppc (that was a typo right?) must always point to the memory
that needs to be freed (in main or wherever). new_mem point to a
bigger buffer already partially filled with characters or to null if
realloc fails. pw_begin (not a good name) point to where the next
character is to be stored.

*ppc should get set to new_mem only when realloc does not return NULL
or you leak memory. That is now done.

pw_begin must be set to where the next character is to go, not to
new_mem. new_mem (if not NULL) already has some characters in it.
pw_begin must point as far into new_men as it does into the old buffer
so I would write something like this:

new_mem = realloc(...);
if (new_mem) {
pw_begin = new_mem + (pw_being - *ppc);
*ppc = new_mem;
}
>The leak is caused only when realloc fails. You set *ppc to NULL (the
return from realloc) but that loses the pointer to the word so it can
now ever be freed.

okay, I have added an else statement aligning with if clause.
Great.
>> *pw_begin++ = ch;

You need also to check all your index counts. This will write the at
index 3 into a string of length 3 (i.e. out of bounds) and the text for
reallocation is wrong as well. You need to realloc space when idx ==
WORD_SIZE - 2 (I think) since idx in incremented late and you must have
space for the null. Anyway, check them (and use valgrind).

I really did not understand what you mean. I mean, i am unable to
comprehend what you said. This is my new code with buggy output:
Your checks for when you had run out of space were wrong. That is all
I meant. You could write outside of the memory you had allocated (and
you still can).

Off-topic bit:
valgrind is a superb tool for checking these things. I can't praise
it highly enough. You will find and fix more simple bugs, faster, by
using valgrind than using any other method except clear thinking and
we all find clear thinking about pointers and offsets and indexes hard
at times.
/* A program that takes a single word from input
* it uses a while loop and dynamic memory allocation to take
* continuous input form user
*
* VERSION: 1.1
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
enum { WORD_SIZE = 3 };
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);
}
return 0;
}


int get_single_word( char** ppc )
{
unsigned idx;
int ch;
size_t arr_size;
char* pw_begin;
char* new_mem;

arr_size = WORD_SIZE;
*ppc = malloc(arr_size * sizeof(**ppc));
pw_begin = *ppc;
if( NULL == ppc )
{
return GSW_ENOMEM;

}
while( (EOF != (ch = getchar())) && isspace(ch) )
{
continue; /* trailing whitespace */
}
if( EOF != ch )
{
*pw_begin++ = ch;
}
for( idx = 0; (EOF != (ch = getchar())) && (! isspace(ch)); ++idx )
{
if( (WORD_SIZE - 1) == idx ) /* -1 for '\0' character*/
This is still off by one. One solution, since you already have one
character in the buffer, is to start with idx = 1 not 0.
{
new_mem = realloc( *ppc, (2 * WORD_SIZE * sizeof **ppc) );
This still needs fixing. You already have arr_size. You must have
been planning to use to grow the array!
>
if( NULL == new_mem )
{
*pw_begin = '\0';
return GSW_ENORESIZE;
}
else
{
pw_begin = *ppc = new_mem;
idx = 0;
See above for how to set pw_begin. Setting idx = 0 is not enough to
allocate more space the next time we run out and if you track the size
with arr_size you don't need to reset idx at all!
}
}

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

return GSW_OK;
}
You are very close to getting this done. Just a couple of bugs remain.

--
Ben.
Sep 22 '08 #161
David Thompson <da************@verizon.netwrote:
>
But since C was not originally envisioned/expected to be used for very
extensive text or string processing, I think the decision was more
(mostly) what was easy and fast to _implement_.
Not according to DMR <http://cm.bell-labs.com/cm/cs/who/dmr/chist.html>:

In BCPL, the first packed byte contains the number of characters
in the string; in B, there is no count and strings are
terminated by a special character, which B spelled `*e'. This
change was made partially to avoid the limitation on the length
of a string caused by holding the count in an 8- or 9-bit slot,
and partly because maintaining the count seemed, in our
experience, less convenient than using a terminator.
--
Larry Jones

Hmm... That might not be politic. -- Calvin
Sep 22 '08 #162
On Mon, 22 Sep 2008 13:23:16 +0100, Ben Bacarisse wrote:

No. *ppc (that was a typo right?) must always point to the memory
that needs to be freed (in main or wherever). new_mem point to a
bigger buffer already partially filled with characters or to null if
realloc fails. pw_begin (not a good name) point to where the next
character is to be stored.

Now I understood why those pointers actually exist.

pw_begin must be set to where the next character is to go, not to
new_mem. new_mem (if not NULL) already has some characters in it.
pw_begin must point as far into new_men as it does into the old buffer
so I would write something like this:

new_mem = realloc(...);
if (new_mem) {
pw_begin = new_mem + (pw_being - *ppc);
*ppc = new_mem;
}

Thanks a lot for this code. It made me understand many things :)
Your checks for when you had run out of space were wrong. That is all
I meant. You could write outside of the memory you had allocated (and
you still can).
Throw away the old code. See below for my new code, with change in the
names of variables to make things clearer. See if you see any bugs.

Off-topic bit:
valgrind is a superb tool for checking these things. I can't praise it
highly enough. You will find and fix more simple bugs, faster, by using
valgrind than using any other method except clear thinking and we all
find clear thinking about pointers and offsets and indexes hard at
times.
I will put it my arsenal ;)

#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);
}
return 0;
}


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.
Google Groups is Blocked. Reason: Excessive Spamming

Sep 23 '08 #163
On Tue, 23 Sep 2008 10:18:43 +0500, arnuld <su*****@invalid.address>
wrote:
>#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);
}
Since get_single_word allocated memory for you, you should free it
here.
>

return 0;
}


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;
You certainly like to waste horizontal space. One blank line between
sections of code is almost always sufficient.
*ppc = malloc(word_length * sizeof(**ppc));
word_begin = *ppc;
if( NULL == ppc )
{
return GSW_ENOMEM;
And should never be used here.
}
while( (EOF != (ch = getchar())) && isspace(ch) )
{
continue; /* trailing whitespace */
Leading whitespace, not trailing.
}
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;
The purpose of new_mem is to allow you to deal with the old allocated
block of memory when realloc fails. By immediately assigning new_mem
to *ppc, you have deleted that capability. Since you repeat this
assignment 5 lines down, I think this is residual code you forgot to
delete.
>
if( new_mem )
{
word_begin = new_mem + (word_begin - *ppc);
And with the previous assignment to *ppc the parenthetical expression
will invoke undefined behavior whenever realloc returns a different
address (actually moves the data to a new block of memory).
> 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
Sep 23 '08 #164
On Mon, 22 Sep 2008 22:50:03 -0700, Barry Schwarz wrote:
>arnuld wrote:
while( (GSW_OK == get_single_word(&pword)) && ( *pword != 0) )
{
printf("You entered: [%s]\n", pword);
}

Since get_single_word allocated memory for you, you should free it
here.

eech... my mistake. Why I always forget the free()
You certainly like to waste horizontal space. One blank line between
sections of code is almost always sufficient.
ok

> if( NULL == ppc )
{
return GSW_ENOMEM;

And should never be used here.
why can't I return at this time ?

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

Leading whitespace, not trailing.
ouch!
>> new_mem = realloc( *ppc, (word_length_interval * word_length * sizeof
**ppc) ); *ppc = new_mem;
The purpose of new_mem is to allow you to deal with the old allocated
block of memory when realloc fails. By immediately assigning new_mem to
*ppc, you have deleted that capability. Since you repeat this
assignment 5 lines down, I think this is residual code you forgot to
delete.
hey.. thats a typo, though big one ;)


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

Sep 23 '08 #165
On Tue, 23 Sep 2008 15:32:12 +0500, arnuld <su*****@invalid.address>
wrote:
>On Mon, 22 Sep 2008 22:50:03 -0700, Barry Schwarz wrote:
>>arnuld wrote:
while( (GSW_OK == get_single_word(&pword)) && ( *pword != 0) )
{
printf("You entered: [%s]\n", pword);
}

Since get_single_word allocated memory for you, you should free it
here.


eech... my mistake. Why I always forget the free()
>You certainly like to waste horizontal space. One blank line between
sections of code is almost always sufficient.

ok

>> if( NULL == ppc )
{
return GSW_ENOMEM;

And should never be used here.

why can't I return at this time ?
The return is fine. I was referring to the blank line between the
return and the }.

--
Remove del for email
Sep 24 '08 #166
On Tue, 23 Sep 2008 18:50:06 -0700 Barry Schwarz <sc******@dqel.comwrote:
The return is fine. I was referring to the blank line between the
return and the }.

So our program is done ? should we go t the next level ?

--
www.lispmachine.wordpress.com
my email is @ the above blog.
Google Groups is Blocked. Reason: Excessive Spamming
Sep 24 '08 #167
On Fri, 19 Sep 2008 10:19:48 +0000, Richard Heathfield wrote:
I had a quick look through, and noticed one thing: in the event of a
realloc failure, you return an error code which indicates that the parsing
was incomplete because the memory block could not be re-sized. That's
fine, but it would be pleasant if the caller were able to attempt to
recover, and you can help with this goal by null-terminating the string
before returning (which means that you need to choose to resize just
*before* you run out of memory, as you'll need one place for the
terminator).

Apart from that, my quick glance didn't reveal anything particularly
untoward.

okay here is my pseudo-C-code for the complete program:

int main( void )
{
char* pword;
size_t words_count;
int sort_ret;
words_count = get_input( &pword );

if( words_count )
{
sort_ret = sort_input( &pword );

if( (! sort_ret ))
{
printf_input( &pword );
}
}
free(&pword);
return 0;
}

void print_words( char **ppc )
{
printf("---------------------------------------\n\n");

while( **ppc )
{
printf("%c\n", **ppc++);
}
}

int sort_input( char **ppc )
{
/* sort words using std. lib. qsort()
if( sort_succeeds )
{
return 0;
}
else
{
return 1;
}
*/
}

void get_input( char** ppc )
{
int ret_value;

ret_value = GSW_OK;
while( (ret_value == get_single_word(&ppc)) && ( *ppc != 0) )
{
;
}

printf("get_word done");

}

I have 2 points to notice here:

1) Isn't main() little messy ?
2) design of the program requires get_single_input to take a ***
indirection.


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

Sep 24 '08 #168
arnuld wrote:

(fx:snip)
okay here is my pseudo-C-code for the complete program:
int main( void )
{
char* pword;
size_t words_count;
int sort_ret;
words_count = get_input( &pword );

if( words_count )
{
sort_ret = sort_input( &pword );

if( (! sort_ret ))
{
printf_input( &pword );
}
}
free(&pword);
return 0;
}
(fx:snip)
I have 2 points to notice here:

1) Isn't main() little messy ?
Stripping blank lines and variables which IMAO don't
have enough ROI gets us:

int main( void )
{
char* pword;
size_t words_count = get_input( &pword );
if(words_count)
{
if(!sort_input( &pword ))
{
printf_input( &pword );
}
}
free( &pword );
return 0;
}

And then discarding clutterbraces [1] and de-notting and
collapsing the two `if`s into one `if` and an `&&` we get:

int main( void )
{
char* pword;
size_t words_count = get_input( &pword );
if(words_count && sort_input( &pword ) == 0) printf_input( &pword );
free( &pword );
return 0;
}

/Now/ it's not (so) messy.

(I haven't paid any attention to all to the code outside `main`.)

[1] Those who don't think they're clutter don't, of course.

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

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

Sep 24 '08 #169
On Wed, 24 Sep 2008 15:09:45 +0500, arnuld <su*****@invalid.address>
wrote:
>On Fri, 19 Sep 2008 10:19:48 +0000, Richard Heathfield wrote:
>I had a quick look through, and noticed one thing: in the event of a
realloc failure, you return an error code which indicates that the parsing
was incomplete because the memory block could not be re-sized. That's
fine, but it would be pleasant if the caller were able to attempt to
recover, and you can help with this goal by null-terminating the string
before returning (which means that you need to choose to resize just
*before* you run out of memory, as you'll need one place for the
terminator).

Apart from that, my quick glance didn't reveal anything particularly
untoward.


okay here is my pseudo-C-code for the complete program:

int main( void )
{
char* pword;
size_t words_count;
int sort_ret;
words_count = get_input( &pword );
Down below get_input returns void.
>
if( words_count )
{
sort_ret = sort_input( &pword );

if( (! sort_ret ))
{
printf_input( &pword );
}
}
free(&pword);
return 0;
}

void print_words( char **ppc )
{
printf("---------------------------------------\n\n");

while( **ppc )
{
printf("%c\n", **ppc++);
}
}

int sort_input( char **ppc )
{
/* sort words using std. lib. qsort()
if( sort_succeeds )
{
return 0;
}
else
{
return 1;
}
*/
}

void get_input( char** ppc )
{
int ret_value;

ret_value = GSW_OK;
while( (ret_value == get_single_word(&ppc)) && ( *ppc != 0) )
{
;
}

printf("get_word done");

}

I have 2 points to notice here:

1) Isn't main() little messy ?
2) design of the program requires get_single_input to take a ***
indirection.
Since you haven't shown the function we can't tell. However, I expect
the function would work with a char** and you could remove the & from
the call argument.
>
--
Remove del for email
Sep 25 '08 #170
On Wed, 24 Sep 2008 19:17:46 -0700, Barry Schwarz wrote:
Since you haven't shown the function we can't tell. However, I expect
the function would work with a char** and you could remove the & from
the call argument.
If i remove it, I get Segfault right there

--
www.lispmachine.wordpress.com
my email is @ the above blog.
Sep 25 '08 #171
arnuld <su*****@invalid.addresswrites:
>On Wed, 24 Sep 2008 19:17:46 -0700, Barry Schwarz wrote:
>Since you haven't shown the function we can't tell. However, I expect
the function would work with a char** and you could remove the & from
the call argument.

If i remove it, I get Segfault right there
Did you remove it and make the correct adjustments elsewhere? Without
code we can't know what is happening.

--
Ben.
Sep 25 '08 #172
On Thu, 25 Sep 2008 11:51:59 +0100, Ben Bacarisse wrote:

Did you remove it and make the correct adjustments elsewhere? Without
code we can't know what is happening.

okay, here is the code which runs fine. DO you see any hidden bugs ?

/* A program that will ask the user for input and then will sort the input alphabetically
and will print it on stdout

* As of now it does not sort any words but it will very soon. I am writing it in parts
* when parts work fine,then we put them in one place :)

* Since I did not want to put any limitation on input size in this program, I have used
* dynamic memory allocation to solve the problem. My intent in creating and then solving
* this problem was purely of C learning (as defined by ANSI standard) and nothign else. I
* wanted to learn C and hence this problem and quite heavy discussion of it on comp.lang.c.
* I owe many thanks to the brillant help I got in comp.lang.c
*
* VERSION 1.0
*
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
enum { WORD_SIZE = 3 };
enum { GSW_OK, GSW_ENOMEM, GSW_ENORESIZE } ;
void print_input( char** );
size_t get_input( char** );
int get_single_word( char** );

int main( void )
{
char* pword;
size_t words_count;
words_count = get_input( &pword );

printf("words_count = %u\n", words_count);

return 0;
}


void print_words( char **ppc )
{
printf("---------------------------------------\n\n");

while( **ppc )
{
printf("%c\n", **ppc++);
}
}


size_t get_input( char** pword )
{
size_t w_cnt;

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


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; /* 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;
}


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

Sep 25 '08 #173
On Sep 25, 5:37 am, arnuld <sunr...@invalid.addresswrote:
On Thu, 25 Sep 2008 11:51:59 +0100, Ben Bacarisse wrote:
Did you remove it and make the correct adjustments elsewhere? Without
code we can't know what is happening.

okay, here is the code which runs fine. DO you see any hidden bugs ?

/* A program that will ask the user for input and then will sort the input alphabetically
and will print it on stdout

* As of now it does not sort any words but it will very soon. I am writing it in parts
* when parts work fine,then we put them in one place :)

* Since I did not want to put any limitation on input size in this program, I have used
* dynamic memory allocation to solve the problem. My intent in creating and then solving
* this problem was purely of C learning (as defined by ANSI standard) and nothign else. I
* wanted to learn C and hence this problem and quite heavy discussion of it on comp.lang.c.
* I owe many thanks to the brillant help I got in comp.lang.c
*
* VERSION 1.0
*
*
*/

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

enum { WORD_SIZE = 3 };
enum { GSW_OK, GSW_ENOMEM, GSW_ENORESIZE } ;

void print_input( char** );
size_t get_input( char** );
int get_single_word( char** );

int main( void )
{
char* pword;
size_t words_count;

words_count = get_input( &pword );

printf("words_count = %u\n", words_count);

return 0;

}

void print_words( char **ppc )
{
printf("---------------------------------------\n\n");

while( **ppc )
{
printf("%c\n", **ppc++);
}

}

size_t get_input( char** pword )
{
size_t w_cnt;

w_cnt = 0;
while( (GSW_OK == get_single_word(pword)) && ( **pword != 0) )
{
printf("You entered: [%s]\n", *pword);
++w_cnt;
free( *pword );
}

return w_cnt;

}
Maybe I'm wrong, but since get_single_word() takes char**, shouldn't
you be passing &pword instead of pword?

Sep 25 '08 #174
Chad <cd*****@gmail.comwrites:
On Sep 25, 5:37 am, arnuld <sunr...@invalid.addresswrote:
On Thu, 25 Sep 2008 11:51:59 +0100, Ben Bacarisse wrote:
Did you remove it and make the correct adjustments elsewhere? Without
code we can't know what is happening.

okay, here is the code which runs fine. DO you see any hidden bugs ?

/* A program that will ask the user for input and then will sort the input alphabetically
and will print it on stdout

* As of now it does not sort any words but it will very soon. I am writing it in parts
* when parts work fine,then we put them in one place :)

* Since I did not want to put any limitation on input size in this program, I have used
* dynamic memory allocation to solve the problem. My intent in creating and then solving
* this problem was purely of C learning (as defined by ANSI standard) and nothign else. I
* wanted to learn C and hence this problem and quite heavy discussion of it on comp.lang.c.
* I owe many thanks to the brillant help I got in comp.lang.c
*
* VERSION 1.0
*
*
*/

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

enum { WORD_SIZE = 3 };
enum { GSW_OK, GSW_ENOMEM, GSW_ENORESIZE } ;

void print_input( char** );
size_t get_input( char** );
int get_single_word( char** );

int main( void )
{
char* pword;
size_t words_count;

words_count = get_input( &pword );

printf("words_count = %u\n", words_count);

return 0;

}

void print_words( char **ppc )
{
printf("---------------------------------------\n\n");

while( **ppc )
{
printf("%c\n", **ppc++);
}

}

size_t get_input( char** pword )
{
size_t w_cnt;

w_cnt = 0;
while( (GSW_OK == get_single_word(pword)) && ( **pword != 0) )
{
printf("You entered: [%s]\n", *pword);
++w_cnt;
free( *pword );
}

return w_cnt;

}

Maybe I'm wrong, but since get_single_word() takes char**, shouldn't
you be passing &pword instead of pword?
"size_t get_input( char** pword )"
Sep 25 '08 #175
On Sep 25, 6:27 am, Richard<rgr...@gmail.comwrote:
Chad <cdal...@gmail.comwrites:
On Sep 25, 5:37 am, arnuld <sunr...@invalid.addresswrote:
On Thu, 25 Sep 2008 11:51:59 +0100, Ben Bacarisse wrote:
Did you remove it and make the correct adjustments elsewhere? Without
code we can't know what is happening.
okay, here is the code which runs fine. DO you see any hidden bugs ?
/* A program that will ask the user for input and then will sort the input alphabetically
and will print it on stdout
* As of now it does not sort any words but it will very soon. I am writing it in parts
* when parts work fine,then we put them in one place :)
* Since I did not want to put any limitation on input size in this program, I have used
* dynamic memory allocation to solve the problem. My intent in creating and then solving
* this problem was purely of C learning (as defined by ANSI standard) and nothign else. I
* wanted to learn C and hence this problem and quite heavy discussion of it on comp.lang.c.
* I owe many thanks to the brillant help I got in comp.lang.c
*
* VERSION 1.0
*
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
enum { WORD_SIZE = 3 };
enum { GSW_OK, GSW_ENOMEM, GSW_ENORESIZE } ;
void print_input( char** );
size_t get_input( char** );
int get_single_word( char** );
int main( void )
{
char* pword;
size_t words_count;
words_count = get_input( &pword );
printf("words_count = %u\n", words_count);
return 0;
}
void print_words( char **ppc )
{
printf("---------------------------------------\n\n");
while( **ppc )
{
printf("%c\n", **ppc++);
}
}
size_t get_input( char** pword )
{
size_t w_cnt;
w_cnt = 0;
while( (GSW_OK == get_single_word(pword)) && ( **pword != 0) )
{
printf("You entered: [%s]\n", *pword);
++w_cnt;
free( *pword );
}
return w_cnt;
}
Maybe I'm wrong, but since get_single_word() takes char**, shouldn't
you be passing &pword instead of pword?

"size_t get_input( char** pword )"

Huh? On
size_t get_input( char** pword )

he passes &pword.

Yet, on
int get_single_word( char** ppc )

he passes pword.

Sep 25 '08 #176
Chad <cd*****@gmail.comwrites:
On Sep 25, 6:27 am, Richard<rgr...@gmail.comwrote:
>Chad <cdal...@gmail.comwrites:
On Sep 25, 5:37 am, arnuld <sunr...@invalid.addresswrote:
<snip>
>okay, here is the code which runs fine. DO you see any hidden bugs ?
<snip>
>int main( void )
{
char* pword;
size_t words_count;
> words_count = get_input( &pword );
<snip>
>}
<snip>
>size_t get_input( char** pword )
{
size_t w_cnt;
> w_cnt = 0;
while( (GSW_OK == get_single_word(pword)) && ( **pword != 0) )
<snip>
>}
Maybe I'm wrong, but since get_single_word() takes char**, shouldn't
you be passing &pword instead of pword?

"size_t get_input( char** pword )"

Huh? On

size_t get_input( char** pword )

he passes &pword.

Yet, on

int get_single_word( char** ppc )

he passes pword.
Richard's point is that *in* get_input, pword is a char ** so it of
the right type to pass to get_single_word.

There are problems with this code, but a type miss-match is not one of
them.

--
Ben.
Sep 25 '08 #177
arnuld <su*****@invalid.addresswrites:
>On Thu, 25 Sep 2008 11:51:59 +0100, Ben Bacarisse wrote:
>Did you remove it and make the correct adjustments elsewhere? Without
code we can't know what is happening.

okay, here is the code which runs fine. DO you see any hidden bugs ?
It looks much the same as before. The loop from main has moved into
get_input. The type of get_input is not right for the final version
but I think you know that from Richard Heathfield's orginal comments.

<snip>

--
Ben.
Sep 25 '08 #178
On Thu, 25 Sep 2008 17:37:45 +0500, arnuld <su*****@invalid.address>
wrote:
>okay, here is the code which runs fine. DO you see any hidden bugs ?
I find your definition of fine a little to broad.
>
/* A program that will ask the user for input and then will sort the input alphabetically
and will print it on stdout

* As of now it does not sort any words but it will very soon. I am writing it in parts
* when parts work fine,then we put them in one place :)

* Since I did not want to put any limitation on input size in this program, I have used
* dynamic memory allocation to solve the problem. My intent in creating and then solving
* this problem was purely of C learning (as defined by ANSI standard) and nothign else. I
* wanted to learn C and hence this problem and quite heavy discussion of it on comp.lang.c.
* I owe many thanks to the brillant help I got in comp.lang.c
*
* VERSION 1.0
*
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
enum { WORD_SIZE = 3 };
enum { GSW_OK, GSW_ENOMEM, GSW_ENORESIZE } ;
void print_input( char** );
size_t get_input( char** );
int get_single_word( char** );

int main( void )
{
char* pword;
size_t words_count;
words_count = get_input( &pword );

printf("words_count = %u\n", words_count);
words_count is unsigned but it need not be an int. If it is not, you
invoke undefined behavior here. This is one of the places in C89
where a cast is called for.
>
return 0;
}


void print_words( char **ppc )
I don't think you call this function.
>{
printf("---------------------------------------\n\n");

while( **ppc )
{
printf("%c\n", **ppc++);
So you really want one character per line?

Since * and ++ have the same precedence and associate right to left,
the second argument is parsed as (*(*(ppc++))). It is your local copy
of ppc that is incremented. Since it started out pointing to pword in
main, it will now point one byte beyond pword. Since this byte is not
the start of a char*, the next time you dereference ppc you invoke
undefined behavior.

And you don't want to use *(*ppc)++ because that will increment pword.
You really need a local pointer if you want this syntax. I think a
local subscript would be easier to understand.
int i;
for (i = 0; (*ppc)[i]; i++)
printf(...
}
}


size_t get_input( char** pword )
{
size_t w_cnt;

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


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 )
If this if could ever evaluate to true then the previous statement
would have invoked undefined behavior first. But since ppc is
guaranteed to point to pword in main, this whole section is just dead
code that cannot be executed. You apparently meant *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;
It is a small point but you do not distinguish between end of file and
an error on input.
>}
--
Remove del for email
Sep 26 '08 #179
On Thu, 25 Sep 2008 15:36:32 +0100, Ben Bacarisse wrote:
It looks much the same as before. The loop from main has moved into
get_input. The type of get_input is not right for the final version
but I think you know that from Richard Heathfield's orginal comments.
Oh.. I missed that. I have changed get_input from:

size_t get_input( char** )

to

int get_input( char**, size_t* )

but I get this problem then:
enum { GI_OK, GI_ERR };

int get_input( char** pword, size_t* w_cnt )
{
*w_cnt = 0;

while( (GSW_OK == get_single_word(pword)) && ( **pword != 0) )
{
printf("You entered: [%s]\n", *pword);
++*w_cnt;
free( *pword );
}

return GI_OK;
}

Any error in get_input() will come from what get_single_word() returns. If
I get an error, I don't understand how to catch it, it means I have to
change the while loop a a little:
int get_input( char** pword, size_t* w_cnt )
{
int err_catcher;
*w_cnt = 0;
while( (err_catcher = get_single_word(pword)) && ( **pword != 0) )
{
if( GSW_OK == err_catcher )
{
printf("You entered: [%s]\n", *pword);
++*w_cnt;
free( *pword );
}
else
{
return GI_ERR;
}
}

return GI_OK;
}


--
www.lispmachine.wordpress.com
my email is @ the above blog.
Gooogle Groups is Blocked. Reason: Excessive Spamming
Sep 26 '08 #180
On Thu, 25 Sep 2008 19:00:19 -0700, Barry Schwarz wrote:
>On Thu, 25 Sep 2008 17:37:45 +0500, arnuld <su*****@invalid.address>
words_count = get_input( &pword );

printf("words_count = %u\n", words_count);
words_count is unsigned but it need not be an int. If it is not, you
invoke undefined behavior here. This is one of the places in C89
where a cast is called for.
Now thats a big problem. words_count is size_t but you have no format
specifier for size_t. If i cast it to unsigned then K&R2 on page 204,
Appendix 7, 4.8) says the the particular type of size_t is unsigned
integer but that is implementation defined. Then why not make words_count
an unsigned int ?


>>void print_words( char **ppc )

I don't think you call this function.
yes, I did not because it will come much later (or may be I will remove
it, depends on when I will start implementing the final stage. final stage
will come after I will have sorted the input)
Since * and ++ have the same precedence and associate right to left, the
second argument is parsed as (*(*(ppc++))). It is your local copy of
ppc that is incremented. Since it started out pointing to pword in
main, it will now point one byte beyond pword. Since this byte is not
the start of a char*, the next time you dereference ppc you invoke
undefined behavior.

Thanks for the insight :)
> 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;
It is a small point but you do not distinguish between end of file and
an error on input.
EOF mean Ctrl-D in Linux. What else could be the errors ?


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

Sep 26 '08 #181
arnuld <su*****@invalid.addresswrites:
>On Thu, 25 Sep 2008 19:00:19 -0700, Barry Schwarz wrote:
>>On Thu, 25 Sep 2008 17:37:45 +0500, arnuld <su*****@invalid.address>
words_count = get_input( &pword );

printf("words_count = %u\n", words_count);
>words_count is unsigned but it need not be an int. If it is not, you
invoke undefined behavior here. This is one of the places in C89
where a cast is called for.

Now thats a big problem. words_count is size_t but you have no format
specifier for size_t.
C99 does: %zu and I thought you were permitting your self C99 extras.
In C90 the canonical solution is to cast to unsigned long -- size_t
can't be any "bigger" than unsigned long in C90 (it could be in C99).

<snip>
>It is a small point but you do not distinguish between end of file and
an error on input.

EOF mean Ctrl-D in Linux. What else could be the errors ?
An unreadable file? Someone pulls the plug? Loads of things can go
wrong reading a file. You don't *have* to report a read error (Barry
says it is a small point) but you might want to.

--
Ben.
Sep 26 '08 #182
arnuld <su*****@invalid.addresswrites:
>On Thu, 25 Sep 2008 15:36:32 +0100, Ben Bacarisse wrote:
>It looks much the same as before. The loop from main has moved into
get_input. The type of get_input is not right for the final version
but I think you know that from Richard Heathfield's orginal comments.

Oh.. I missed that. I have changed get_input from:

size_t get_input( char** )

to

int get_input( char**, size_t* )
I thought tha plan was that get_input would set its parameter to a
char ** containing the list of words? If so, it needs to be a char
*** but I see you are currently just printing words inside get_input.
If that is the new design, the call it print_words or some such.
but I get this problem then:
enum { GI_OK, GI_ERR };
<snip code>
I won't comment on the details until I know what the intent is.

--
Ben.
Sep 26 '08 #183
On Fri, 26 Sep 2008 12:10:13 +0100, Ben Bacarisse wrote:

>Now thats a big problem. words_count is size_t but you have no format
specifier for size_t.

C99 does: %zu and I thought you were permitting your self C99 extras.
In C90 the canonical solution is to cast to unsigned long -- size_t
can't be any "bigger" than unsigned long in C90 (it could be in C99).
I was going for C99 but then many people here can't compile C99 based
programs. Thats why I am working on C90 based solutions

An unreadable file? Someone pulls the plug? Loads of things can go
wrong reading a file. You don't *have* to report a read error (Barry
says it is a small point) but you might want to.

But how you will catch the error. You catch End of File by using EOF
macro. What can I use to catch different errors you mentioned ?

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

Sep 26 '08 #184
On Fri, 26 Sep 2008 12:12:47 +0100, Ben Bacarisse wrote:
I thought tha plan was that get_input would set its parameter to a
char ** containing the list of words? If so, it needs to be a char
*** but I see you are currently just printing words inside get_input.
If that is the new design, the call it print_words or some such.

No, I plan to sort them but don't know how. Right now I am just printing
them and free()ing the memory after every single word is printed

But if I need to sort them, then first I need to collect them all and only
then I could free(), that may create memory run-out problem. You have
better ideas for alphabetical sorting ?
I won't comment on the details until I know what the intent is.

The intent is to take input from stdin with the definition of words we
have agreed about some time ago. Then sorting those words alphbetically
and printing them on the stdout. Thats it. All must be done using Dynamic
Memory Allocation. I am using this exercise a way to teach myself C and
general programming concepts.


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

Sep 26 '08 #185
arnuld wrote:
>On Fri, 26 Sep 2008 12:10:13 +0100, Ben Bacarisse wrote:
....
>An unreadable file? Someone pulls the plug? Loads of things can go
wrong reading a file. You don't *have* to report a read error (Barry
says it is a small point) but you might want to.


But how you will catch the error. You catch End of File by using EOF
macro. What can I use to catch different errors you mentioned ?
The same way. getchar() uses EOF to signal any problems it could run
into. If you need to distinguish between an End of File and an I/O
error, you have to use feof() and ferror().
Sep 26 '08 #186
On Fri, 26 Sep 2008 12:03:21 +0000, James Kuyper wrote:
feof() and ferror().
I checked man pages, both take FILE* as input. we are dealing with stdin
here. Even if it is feasible, then I have to make very massive changes in
my program.

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

Sep 26 '08 #187
arnuld <su*****@invalid.addresswrites:
>On Fri, 26 Sep 2008 12:12:47 +0100, Ben Bacarisse wrote:
>I thought tha plan was that get_input would set its parameter to a
char ** containing the list of words? If so, it needs to be a char
*** but I see you are currently just printing words inside get_input.
If that is the new design, the call it print_words or some such.


No, I plan to sort them but don't know how. Right now I am just printing
them and free()ing the memory after every single word is printed

But if I need to sort them, then first I need to collect them all and only
then I could free(), that may create memory run-out problem. You have
better ideas for alphabetical sorting ?
>I won't comment on the details until I know what the intent is.


The intent is to take input from stdin with the definition of words we
have agreed about some time ago. Then sorting those words alphbetically
and printing them on the stdout. Thats it. All must be done using Dynamic
Memory Allocation. I am using this exercise a way to teach myself C and
general programming concepts.
Then, as a learning exercise, I'd implement get_input (I'd probably
call it get_words but that is not important) and sort the array and
print it "outside" (probably in main). That gives you more learning!

--
Ben.
Sep 26 '08 #188
On Fri, 26 Sep 2008 13:39:47 +0100, Ben Bacarisse wrote:

Then, as a learning exercise, I'd implement get_input (I'd probably
call it get_words but that is not important) and sort the array and
print it "outside" (probably in main). That gives you more learning!
well ,thats what I am doing. I don't see any difference in your idea. I
even have a function name i mind: printf_input(..) and also I will free()
in main() too, as input char* to get_input(...) is also created in main().

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

Sep 26 '08 #189
arnuld <su*****@invalid.addresswrites:
>On Fri, 26 Sep 2008 13:39:47 +0100, Ben Bacarisse wrote:

>Then, as a learning exercise, I'd implement get_input (I'd probably
call it get_words but that is not important) and sort the array and
print it "outside" (probably in main). That gives you more learning!

well ,thats what I am doing. I don't see any difference in your idea. I
even have a function name i mind: printf_input(..) and also I will free()
in main() too, as input char* to get_input(...) is also created in
main().
Great. Post an outline. What you posted before had the wrong types
for that sort of design.

--
Ben.
Sep 26 '08 #190
In article <pa****************************@invalid.address> ,
arnuld <su*****@invalid.addresswrote:
> feof() and ferror().

I checked man pages, both take FILE* as input. we are dealing with stdin
here. Even if it is feasible, then I have to make very massive changes in
my program.
Why? stdin is a FILE *.

-- Richard
--
Please remember to mention me / in tapes you leave behind.
Sep 26 '08 #191
arnuld wrote:
>On Fri, 26 Sep 2008 12:03:21 +0000, James Kuyper wrote:
> feof() and ferror().

I checked man pages, both take FILE* as input. we are dealing with stdin
here. ...
stdin is a FILE*. What's the problem?
Sep 26 '08 #192
On Sep 25, 7:00 pm, Barry Schwarz <schwa...@dqel.comwrote:
On Thu, 25 Sep 2008 17:37:45 +0500, arnuld <sunr...@invalid.address>
wrote:
okay, here is the code which runs fine. DO you see any hidden bugs ?

I find your definition of fine a little to broad.


/* A program that will ask the user for input and then will sort the input alphabetically
and will print it on stdout
* As of now it does not sort any words but it will very soon. I am writing it in parts
* when parts work fine,then we put them in one place :)
* Since I did not want to put any limitation on input size in this program, I have used
* dynamic memory allocation to solve the problem. My intent in creating and then solving
* this problem was purely of C learning (as defined by ANSI standard) and nothign else. I
* wanted to learn C and hence this problem and quite heavy discussion of it on comp.lang.c.
* I owe many thanks to the brillant help I got in comp.lang.c
*
* VERSION 1.0
*
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
enum { WORD_SIZE = 3 };
enum { GSW_OK, GSW_ENOMEM, GSW_ENORESIZE } ;
void print_input( char** );
size_t get_input( char** );
int get_single_word( char** );
int main( void )
{
char* pword;
size_t words_count;
words_count = get_input( &pword );
printf("words_count = %u\n", words_count);

words_count is unsigned but it need not be an int. If it is not, you
invoke undefined behavior here. This is one of the places in C89
where a cast is called for.
return 0;
}
void print_words( char **ppc )

I don't think you call this function.
{
printf("---------------------------------------\n\n");
while( **ppc )
{
printf("%c\n", **ppc++);

So you really want one character per line?

Since * and ++ have the same precedence and associate right to left,
the second argument is parsed as (*(*(ppc++))). It is your local copy
of ppc that is incremented. Since it started out pointing to pword in
main, it will now point one byte beyond pword. Since this byte is not
the start of a char*, the next time you dereference ppc you invoke
undefined behavior.

And you don't want to use *(*ppc)++ because that will increment pword.
You really need a local pointer if you want this syntax. I think a
local subscript would be easier to understand.
int i;
for (i = 0; (*ppc)[i]; i++)
printf(...
Why would it matter if pword gets incremented?
Sep 27 '08 #193
On Fri, 26 Sep 2008 10:03:00 +0500, arnuld <su*****@invalid.address>
wrote:
>On Thu, 25 Sep 2008 19:00:19 -0700, Barry Schwarz wrote:
>>On Thu, 25 Sep 2008 17:37:45 +0500, arnuld <su*****@invalid.address>
words_count = get_input( &pword );

printf("words_count = %u\n", words_count);
>words_count is unsigned but it need not be an int. If it is not, you
invoke undefined behavior here. This is one of the places in C89
where a cast is called for.

Now thats a big problem. words_count is size_t but you have no format
specifier for size_t. If i cast it to unsigned then K&R2 on page 204,
Appendix 7, 4.8) says the the particular type of size_t is unsigned
integer but that is implementation defined. Then why not make words_count
an unsigned int ?
You can if you want to.

>
>It is a small point but you do not distinguish between end of file and
an error on input.

EOF mean Ctrl-D in Linux. What else could be the errors ?
Doesn't Linux support the < redirection operator so that stdin could
be a file? Could not whatever device the stream connects to
(including the keyboard) suffer a hardware problem? Can the cable
that connects the device to the computer break or accidentally be
pulled out of its receptacle? Could the driver which accesses the
device be coded improperly or be corrupted in memory? For a disk
file, could the file system be corrupt and point to a non-existent
sector on disk? Could the disk be formatted incorrectly? Could
another process attempt to format the disk (or delete the file) while
you are reading from it?

--
Remove del for email
Sep 27 '08 #194
On Sep 26, 5:24 pm, Chad <cdal...@gmail.comwrote:
On Sep 25, 7:00 pm, Barry Schwarz <schwa...@dqel.comwrote:
On Thu, 25 Sep 2008 17:37:45 +0500, arnuld <sunr...@invalid.address>
wrote:
>okay, here is the code which runs fine. DO you see any hidden bugs ?
I find your definition of fine a little to broad.
>/* A program that will ask the user for input and then will sort the input alphabetically
and will print it on stdout
* As of now it does not sort any words but it will very soon. I am writing it in parts
* when parts work fine,then we put them in one place :)
* Since I did not want to put any limitation on input size in this program, I have used
* dynamic memory allocation to solve the problem. My intent in creating and then solving
* this problem was purely of C learning (as defined by ANSI standard) and nothign else. I
* wanted to learn C and hence this problem and quite heavy discussion of it on comp.lang.c.
* I owe many thanks to the brillant help I got in comp.lang.c
*
* VERSION 1.0
*
*
>*/
>#include <stdio.h>
>#include <stdlib.h>
>#include <ctype.h>
>enum { WORD_SIZE = 3 };
>enum { GSW_OK, GSW_ENOMEM, GSW_ENORESIZE } ;
>void print_input( char** );
>size_t get_input( char** );
>int get_single_word( char** );
>int main( void )
>{
char* pword;
size_t words_count;
words_count = get_input( &pword );
printf("words_count = %u\n", words_count);
words_count is unsigned but it need not be an int. If it is not, you
invoke undefined behavior here. This is one of the places in C89
where a cast is called for.
return 0;
>}
>void print_words( char **ppc )
I don't think you call this function.
>{
printf("---------------------------------------\n\n");
while( **ppc )
{
printf("%c\n", **ppc++);
So you really want one character per line?
Since * and ++ have the same precedence and associate right to left,
the second argument is parsed as (*(*(ppc++))). It is your local copy
of ppc that is incremented. Since it started out pointing to pword in
main, it will now point one byte beyond pword. Since this byte is not
the start of a char*, the next time you dereference ppc you invoke
undefined behavior.
And you don't want to use *(*ppc)++ because that will increment pword.
You really need a local pointer if you want this syntax. I think a
local subscript would be easier to understand.
int i;
for (i = 0; (*ppc)[i]; i++)
printf(...

Why would it matter if pword gets incremented?

Wait. I think I see why.

printf("%c\n", **ppc++);

is the same as
printf("%c\n", (*ppc++)[0]);

And the OP wants to increment each word, not increment each letter in
a word. I think. Okay, I'm done talking to myself. With that, I think
I'm going to drive to Denny's in Richmond and just talk to myself.
Sep 27 '08 #195
On Fri, 26 Sep 2008 13:52:09 +0100, Ben Bacarisse wrote:
>arnuld <su*****@invalid.addresswrites:
>>On Fri, 26 Sep 2008 13:39:47 +0100, Ben Bacarisse wrote:
>>Then, as a learning exercise, I'd implement get_input (I'd probably
call it get_words but that is not important) and sort the array and
print it "outside" (probably in main). That gives you more learning!
>well ,thats what I am doing. I don't see any difference in your idea. I
even have a function name i mind: printf_input(..) and also I will free()
in main() too, as input char* to get_input(...) is also created in
main().
Great. Post an outline. What you posted before had the wrong types
for that sort of design.

Here is the outline which gives run time error of the free() call in main():


/* A program that will ask the user for input and then will sort the input alphabetically
and will print it on stdout

* As of now it does not sort any words but it will very soon. I am writing it in parts
* when parts work fine,then we put them in one place :)

* Since I did not want to put any limitation on input size in this program, I have used
* dynamic memory allocation to solve the problem. My intent in creating and then solving
* this problem was purely of C learning (as defined by ANSI standard) and nothing else. I
* wanted to learn C and hence this problem and quite heavy discussion of it on comp.lang.c.
* I owe many thanks to the brilliant help I got in comp.lang.c
*
* VERSION 1.0
*
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
enum { WORD_SIZE = 3, WORD_ERR = -1 };
enum { GSW_OK, GSW_ENOMEM, GSW_ENORESIZE } ;
enum { GI_OK = 0 , GI_ERR = WORD_ERR };
int get_input( char**, size_t* );
int get_single_word( char** );

int main( void )
{
char* pword;
int input_err;
size_t words_count;

pword = NULL;
words_count = 0;
input_err = WORD_ERR; /* we will update the status in function call to get_input() */

input_err = get_input( &pword, &words_count );

if( WORD_ERR != input_err )
{
printf("words_count = %u\n", words_count);
}
/* sort_input(...)
printf_input(...) */

free( &pword );
return 0;
}

int get_input( char** pword, size_t* w_cnt )
{
int err_catcher;
*w_cnt = 0;
while( (err_catcher = get_single_word(pword)) && ( **pword != 0) )
{
if( GSW_OK == err_catcher )
{
printf("You entered: [%s]\n", *pword);
++*w_cnt;
}
else
{
return GI_ERR;
}
}

return GI_OK;
}


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 == word_begin )
{
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;
}
--
www.lispmachine.wordpress.com
my email is @ the above blog.
Gooogle Groups is Blocked. Reason: Excessive Spamming

Sep 29 '08 #196
arnuld <su*****@invalid.addresswrites:
>On Fri, 26 Sep 2008 13:52:09 +0100, Ben Bacarisse wrote:
<snip>
>Great. Post an outline. What you posted before had the wrong types
for that sort of design.

Here is the outline which gives run time error of the free() call in
main():
This is not an outline for the design you explained. This is very
similar to what you posted before -- the get_input function prints the
words. I thought you wanted get_input to store them all in a dynamic
array and "return" that (return in quotes because the plan was for a
status code to be the actual return values -- the array would be a
char *** parameter).

<snip>
char* pword;
....
free( &pword );
Whenever you see this you know it is wrong. &pword is the address of
a variable -- in this case a local object in main. You can't free
local variables. You can free what they point to (if they are
pointers) but that involves passing the value (i.e. the contents of
the variable) to free, not a pointer to the variable itself.

--
Ben.
Sep 29 '08 #197
On Mon, 29 Sep 2008 11:18:54 +0100, Ben Bacarisse wrote:

This is not an outline for the design you explained. This is very
similar to what you posted before -- the get_input function prints the
words.

Thats just there unintentionally, for a memory check. I will remove it.
I thought you wanted get_input to store them all in a dynamic
array and "return" that (return in quotes because the plan was for a
status code to be the actual return values --

*Exactly* that..

the array would be a char *** parameter).
yes, but then get_single_word() will take a char*** as argument. When I try to
do that I get invalid pointer error. I have to admit that this busines of
pointers is really hell confusing. get_words() is already getting the address of
the pointer then why have to pass the address of the address of the
pointer to get_single_word(). Even when I do that my program compiles
fine but ends in doing semantic error. Program exits as soon as you input
one word.

2nd, someone told me on clc that if a function crosses 40 lines then
alarms should be ringing. get_single_word() is a 60 line function. Does
it need to be abstracted into 2 other functions ?
Whenever you see this you know it is wrong. &pword is the address of
a variable -- in this case a local object in main. You can't free
local variables. You can free what they point to (if they are
pointers) but that involves passing the value (i.e. the contents of
the variable) to free, not a pointer to the variable itself.
Oh.. no, I did not notice this stupidity :( .

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
enum { WORD_SIZE = 3, WORD_ERR = -1 };
enum { GSW_OK, GSW_ENOMEM, GSW_ENORESIZE } ;
enum { GI_OK = 0 , GI_ERR = WORD_ERR };
int get_words( char**, size_t* );
int get_single_word( char*** );

int main( void )
{
char* pword;
int input_err;
size_t words_count;

pword = NULL;
words_count = 0;
input_err = WORD_ERR; /* we will update the status in function call to get_input() */

input_err = get_words( &pword, &words_count );

if( WORD_ERR != input_err )
{
printf("words_count = %u\n", words_count);
}
/* call to - sort_input(...)
call to - printf_input(...) */

free( pword );
return 0;
}

int get_words( char** pword, size_t* w_cnt )
{
int err_catcher;
*w_cnt = 0;
while( (err_catcher = get_single_word(&pword)) && ( **pword != 0) )
{
if( GSW_OK == err_catcher )
{
++*w_cnt;
}
else
{
return GI_ERR;
}
}

return GI_OK;
}


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 == word_begin )
{
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;
}
======================== OUTPUT ================================
[arnuld@dune ztest]$ gcc -ansi -pedantic -Wall -Wextra sort-input.c
[arnuld@dune ztest]$ ./a.out
Like
words_count = 0
[arnuld@dune ztest]$



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

Sep 29 '08 #198
On Fri, 26 Sep 2008 19:11:18 +0000, James Kuyper wrote:

stdin is a FILE*. What's the problem?
yes stdin is a FILE* but (ch = getchar()) is not. When user input EOF
(Ctrl-D), then ch has that value, how to check that ?

/* A program that will ask the user for input and then will sort the input alphabetically
and will print it on stdout

* As of now it does not sort any words but it will very soon. I am writing it in parts
* when parts work fine,then we put them in one place :)

* Since I did not want to put any limitation on input size in this program, I have used
* dynamic memory allocation to solve the problem. My intent in creating and then solving
* this problem was purely of C learning (as defined by ANSI standard) and nothing else. I
* wanted to learn C and hence this problem and quite heavy discussion of it on comp.lang.c.
* I owe many thanks to the brilliant help I got in comp.lang.c
*
* VERSION 1.0
*
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
enum { WORD_SIZE = 3, WORD_ERR = -1 };
enum { GSW_OK, GSW_ENOMEM, GSW_ENORESIZE, GSW_EINPUT } ;
enum { GI_OK = 0 , GI_ERR = WORD_ERR };
int get_words( char**, size_t* );
int get_single_word( char*** );

int main( void )
{
char* pword;
int input_err;
size_t words_count;

pword = NULL;
words_count = 0;
input_err = WORD_ERR; /* we will update the status in function call to get_input() */

input_err = get_words( &pword, &words_count );

if( WORD_ERR != input_err )
{
printf("words_count = %u\n", words_count);
}
/* call to - sort_input(...)
call to - printf_input(...) */

free( pword );
return 0;
}

int get_words( char** pword, size_t* w_cnt )
{
int err_catcher;
*w_cnt = 0;
while( (err_catcher = get_single_word(&pword)) && ( **pword != 0) )
{
if( GSW_OK == err_catcher )
{
++*w_cnt;
}
else
{
return GI_ERR;
}
}

return GI_OK;
}


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 == word_begin )
{
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;
}
if( feof(ch) )
{
*word_begin = '\0';
}
else if( ferror(ch) )
{
return GSW_EINPUT;
}
return GSW_OK;
}
=========================== OUTPUT =======================================
[arnuld@dune ztest]$ gcc -ansi -pedantic -Wall -Wextra sort-input.c
sort-input.c: In function `get_single_word':
sort-input.c:147: warning: passing arg 1 of `feof' makes pointer from integer without a cast
sort-input.c:151: warning: passing arg 1 of `ferror' makes pointer from integer without a cast
[arnuld@dune ztest]$

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

Sep 29 '08 #199
arnuld wrote:
>On Fri, 26 Sep 2008 19:11:18 +0000, James Kuyper wrote:

>stdin is a FILE*. What's the problem?

yes stdin is a FILE* but (ch = getchar()) is not. When user input EOF
(Ctrl-D), then ch has that value, how to check that ?
What does that have to do with it? what you pass to feof() and ferror()
is not the value returned by the I/O function. What you pass it is the
FILE* associated with the stream that you are using the I/O function on.
The getchar() function is exactly equivalent to getc(stdin); it's
provided as a separate function from getc() only for convenience. All
you need to do is check feof(stdin) and ferror(stdin).
Sep 29 '08 #200

This discussion thread is closed

Replies have been disabled for this discussion.

By using this site, you agree to our Privacy Policy and Terms of Use.