Any way to take a word as input from stdin ?

J

James Kuyper

arnuld wrote:
....
....
This whole program is based on that condition of *pc != NULL. Why don't
we put a line like, *pc == NULL and then return from the program with the
ENOMEM value right there ?

If you return from the program, the fact that errno contains ENOMEM has
no further significance.
 
J

James Kuyper

Richard Heathfield wrote:
....
The compiler will do something like this:

CMP ptr, 0
JE _B
(500 bytes of assembly instructions here)
_B:
MOV RR, ptr

On the second pass, JE _B will be translated into a jump to a specific
(relocatable) address, and the jump will consist simply of changing the
instruction pointer to have that new value. The program doesn't have to
"go till it finds the return" - it simply has to assign a new value to the
instruction pointer, and it doesn't give tuppence whether that value is
close to the value it had before or not.

It depends upon the assembly language; I've written assembly in
languages where a short jump used a faster instruction than a long jump.
However, it was only a little bit faster; not enough to justify worrying
about in C code.
 
J

James Kuyper

Richard said:
arnuld said: ....

I've never heard such baloney. C is a language. Turbo C is an ancient
implementation, no longer supported, which runs on only one tiny class of
platforms.


Try telling that to the OS390 guys.

I would imagine, since he prefaced his statement with "In Indian
computer education system ...", that this would imply that the specified
system doesn't have any OS390 guys. He wasn't making a more general
statement. The wording of his statement leaves open the possibility that
there are implementations of C which are better than the ones he listed,
they just don't happen to be available in that system. If this is the
case, he has my sympathy - I thought the Indians were more advanced than
that.

However, India is a huge place, and I doubt that arnuld has seen the
entire "Indian computer education system". I suspect that he's
describing the attitude of one particular piece (of unknown size) of
that system. However, his description of that piece of the system might
be perfectly accurate.
 
B

Ben Bacarisse

Okay here is my new code:

A few comments.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>


enum { WORD_SIZE = 28, ARRSIZE = 10 };

enum { GSW_OK, GSW_ENOMEM, GSW_ENORESIZE } ;

enum { GW_OK, GW_ENOMEM, GW_ENORESIZE };


int get_words( char***, size_t* );
int get_single_word( char** );


int main( void )
{
char** pword; /* pw means pointer to word */
size_t word_count;
int num;

pword = NULL;
word_count = 0;

num = get_words( &pword, &word_count );

printf("words = %d, num = %d\n", (int) word_count, num);



free(pword);

return 0;
}


int get_words( char*** pw, size_t* cnt )
{
size_t idx;
int mem_check;
char **pw_begin, **new_mem;
char* pword;
size_t arr_size;

arr_size = ARRSIZE;
mem_check = GW_ENOMEM;

*pw = calloc( arr_size, sizeof **pw );
pw_begin = *pw;

if( *pw )
{
mem_check = GW_OK;
pw_begin = *pw;


for( idx = 0; (! get_single_word( &pword )) && *pword; ++idx )

I find this counter-intuitive. I had to go check what get_single_word
returns for success (GSW_OK) and then go check that this was indeed
zero so ! of it was true. I'd write
for( idx = 0; get_single_word( &pword ) == GSW_OK; ++idx )

and try hard to make sure that there is no need for the extra check
on *pword. I have not checked if you need it.
{
if( idx == arr_size )
{
new_mem = realloc( **pw, (2 * arr_size * sizeof new_mem));

if( new_mem )
{
pw_begin = new_mem;

Surely not? The next words has to go after the existing ones in the new
memory not at the start.
}
else
{
mem_check = GW_ENORESIZE;
}
}

if( GSW_OK == mem_check )

This looks wrong. You set mem_check only once and that is to GW_OK.
Now GW_OK == GSW_OK (probably) but why test it anyway since we are in
an the if where it was set? I.e. you get to this test unless
mem_check is GW_OK.
{
pw_begin++ = &pword;
}
}

I find this a gruesome waste of space, but that is only style! You go
with what feels right.
pw_begin = NULL;

}

*cnt = idx;

return mem_check;
}




int get_single_word( char** pc )
{
int mem_check;
unsigned idx;
int ch;

size_t curr_size;
char *new_mem;
char *pc_begin;

mem_check = GSW_ENOMEM; /* will updat eit on first use */
curr_size = WORD_SIZE;

*pc = calloc(curr_size, sizeof(**pc));

if( (! *pc) )
{
mem_check = GSW_ENOMEM;
return mem_check;
}
else
{
mem_check = GSW_OK;
pc_begin = *pc;
}



while( (ch = getchar()) && (isspace( (unsigned char) ch)) )

Ah! The cast is wrong here. Not just unneeded, but wrong. I'll
gladly say why but I think you get way more out of it if you can work
out why for yourself. It won't actually fail o any system that I can
recall but it is, technically, not portable.
{
continue; /* skip leading white space */
}


if( EOF != ch )
{
*pc_begin++ = ch;
}

while( (GSW_OK == mem_check) &&
((ch = getchar()) != EOF) &&
(! isspace( (unsigned char) ch)) )

And here it is unneeded but can't, even theoretically, cause a
problem.
{
if( idx == curr_size )
{
new_mem = realloc( pc_begin, (2 * curr_size * sizeof(*new_mem)));

if( new_mem )
{
pc_begin = new_mem;

Again, is this right? New characters need to go after the ones that
are there already.
 
K

Keith Thompson

arnuld said:
you say that calloc() will automatically return a pointer to pointer ?
[...]

No, calloc() returns a void*. The assignment implicitly converts that
void* result to the type of the left side; in this case, whatever type
*pw has.
 
A

arnuld

I thought the Indians were more advanced than that.

You are wrong. Most Indian students say that you need Windows to run a
computer, without Windows you can not use a computer. I have yet to meet a
person who uses Linux as his daily use OS.


However, India is a huge place, and I doubt that arnuld has seen the
entire "Indian computer education system". I suspect that he's
describing the attitude of one particular piece (of unknown size) of
that system.

I am graduated from "Panjab University", one of the top 4 most respected
universities in India. You can think about what rest of will be like. 2nd,
other than these top 4, most do not eve have proper working hardware
available to them. Most shocking fact is that you won't find a computer
teachers, even if you find institute.

Only *a few* are good, hear of IIT, Indian Institute of Technology, a
supreme quality Engg. College with 5 or 8 branches all over India. It is
the only institute which gives quality education.

I met a programmer, 2 years ago, he asked me what I am doing at that time.
I said I was reading Haskell, he had first devision in his Computer
Science Engg. degree and was earning 20,000 rupees a month. He asked me
"What is Husk... a..all.... some sort of Fictional Novel ? ".... :-\
 
D

Default User

arnuld said:
I did not know that TURBO C is an ancient compiler. As of 2008, the
Indian Computer Education system still rely on TURBO C compiler.


That's because it's free.




Brian
 
D

Default User

Andrew said:
Well, TURBO C is not C, and VC++ is not C++. Microsoft should not have
named their products so similarly to those real languages.

Then you should the same complaint about gcc and almost every other C
implementation. Almost all offer some sort of extensions.

Turbo C contained a nearly conforming C89 compiler. I believe I've
heard that there were a few bugs, but I don't recall what they were.
The manual had a portability statement for every library function
included that specified whether it was ANSI C, UNIX, or
platform-specific.

Oh, and Turbo C was Borland, not Microsoft.




Brian
 
D

Default User

Richard said:
arnuld said:

Lots of people would write it like that. In my code, I consider an
"early return" like that to be a bug that I should fix, because in my
code I want every function and every loop to have one entry point and
one exit point. I find that this makes my programs much easier to
read and thus to maintain.

Our company coding standard now allows early return for initial
parameter checking. In the old days, the usual method was something
like:

int func(int a, int b)
{
returnval = 0;

if (a > 10)
{
returnval = -1;
}
else if (b > 20)
{
returnval = -2;
}

if (returnval == 0)
{
/* do the real work and set returnval appropriately */
}

return returnval;
}

Now you can do:

int func(int a, int b)
{
returnval = 0;

if (a > 10)
{
return -1;
}
if (b > 20)
{
return -2;
}

/* do the real work and set returnval appropriately */

return returnval;
}


I don't know if it's better, worse, or just differently-abled.



Brian
 
J

jellybean stonerfish

You are wrong. Most Indian students say that you need Windows to run a
computer, without Windows you can not use a computer. I have yet to meet
a person who uses Linux as his daily use OS.

Off topic, but what the hell. I, living in Southern California, have yet
to meet anybody who uses linux. Besides myself, and people I have given
computers to. I work in construction, and have been in many offices, and
have seen nothing but window and mac boxes. Eventually, if my children
let me have some free time, I will join a LUG.

sf
 
A

arnuld

Off topic, but what the hell. I, living in Southern California, have yet
to meet anybody who uses linux. Besides myself, and people I have given
computers to. I work in construction, and have been in many offices, and
have seen nothing but window and mac boxes. Eventually, if my children
let me have some free time, I will join a LUG.

Thats what *exactly* I am telling. Indian students and users are same as
American students or users. People wrongly believe that Indian guys are
much more computer literate. Like US or Germany, most don't even
understand the difference between OS and Windows.
 
J

jellybean stonerfish

Thats what *exactly* I am telling. Indian students and users are same as
American students or users. People wrongly believe that Indian guys are
much more computer literate. Like US or Germany, most don't even
understand the difference between OS and Windows.

In other words, stupidity has no boundaries.

sf
 
F

Flash Gordon

arnuld wrote, On 19/09/08 06:35:
Thats what *exactly* I am telling. Indian students and users are same as
American students or users.

It varies in India, America and the US. There are definitely people in
Silicon Valley who know about and use Linux. The majority of people
outside IT don't know and don't care.
People wrongly believe that Indian guys are
much more computer literate.

I have talked to other people involved in SW outsourcing to India and
I've yet to meet people who believe that. Don't get me wrong, I'm not
saying Indian people are less intelligent, just that the people I've met
involved in doing outsourcing SW to India do it because the staff are
cheap enough that you can hire enough to make up for the staff being
*less* able. This is one reason why certain key parts of the SW
development are kept in the UK/USA/wherever.
Like US or Germany, most don't even
understand the difference between OS and Windows.

For most people the computer should just be an appliance. They want to
do word processing, play games, browse the web etc. It is US who should
be making it possible to do that *without* knowing or caring about the
OS. Of course, the OS needs to be locked down for people like that so
that they can't break it (cue OS wars). People in IT and SW development
are and should be different.
 
A

arnuld

...SNIP...
What you meant to write is:

*pw_begin++ = pword;

This is legal because * has higher precedence than = so what happens is
that ++ yields the old value of pw_begin, * gives us the object to which
that old value points, and = now assigns to the object. Since pw_begin has
type char **, pw_begin++ has type char **, *pw_begin++ has type char * and
is a real object, so we can assign a char * value to it. pword is one such
value.


I understood completely the *pw_begin++ part, the confusion remains in
in the Right Hand Side, the pword has triple levels of indirection ***.
while pw_begin has two **. So dereferencing pw_begin gives me single level
of indirection. SO it looks like this:

* = ***


thats what confusing me an din that confusion I did &pword :(
 
R

Richard Bos

CBFalconer said:
Try this:

No thanks; I've already written my own, several times for several
different situations, and I don't think a single solution would do.
Besides, it's such a simple thing to write a basic version of, with such
opportunity for a variety of approaches, that I believe this is one of
those problems which it does a newbie good to attempt his own instead of
using someone else's almost-perfect-enough solution.

Richard
 
A

arnuld

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. This is final version and after that we will
start discussing get_words() and next:


/* A program that takes a single word from input
* it uses a while loop and dynamic memory allocation to take
* continuous input form user
*
*/


#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 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) );
*ppc = new_mem;

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

*pw_begin++ = ch;
}


*pw_begin = '\0';

return GSW_OK;
}
 
R

Richard Bos

Nick Keighley said:
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
 
B

Ben Bacarisse

arnuld said:
This is final version and after that we will
start discussing get_words() and next:
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).
 
A

arnuld

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 ?


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.


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]$
 
A

arnuld

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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,808
Messages
2,569,684
Members
45,439
Latest member
keviralu

Latest Threads

Top