Any way to take a word as input from stdin ?

A

arnuld

*pc = calloc(AVERAGE_SIZE - 1, sizeof **pc);

why sizeof **pc and not sizeof *pc ?


Okay - although it's better not to embed messages like this in library
functions if you can avoid it.


its *not* a library function. its my function. and which message you are
talking about, perror or return call ?


Don't forget to check that return value in the caller.

yes, will do that when get_words will be ready.


I thought you wanted to stop at whitespace?

Also, it's better to move pc_begin than *pc, if you must move either of
them. Given that you have idx keeping track of things, I see no reason to
modify *pc (and plenty of reasons not to), and no reason for pc_begin to
exist at all. You can simply do (*pc)[idx] = ch;

Because [] make it look like an array when you can never pass an array in
C, you always pass a pointer and that *pc++ reminds of that i am working
in a region of memory starting at *pc and ending at *pc == '\0'. 3rd, when
I start using [] i start forgetting how to use pointers.

pc_begin is there because i have rad enough that any callto malloc/calloc
*must* be accompanied by call to free(), other wise we will have a memory
leak. Since I am moving the original pointer (pc), I use pc_begin to save
the beginning position of original pointer, so that I can pass that to
free().

pc is char **, so ++pc is char ** (and utterly invalid),

invalid ? I am moving the pointer to next value, so that I can assign to
the **pc .

and *++pc is char*, so you're setting a wild pointer to 0. Not good. Could
be worse, but not good.

That should be **++pc , my typo in the original code.



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

why sizeof **pc, why not sizeof(char*) ?


new = realloc(*pc, 2 * cursize * sizeof *new);

Same question. Why sizeof *new rather than sizeof char* ?


if(GSW_OK == rc)
{
pc_begin[idx++] = ch;
}

is it the same as **pc++ = ch; ? I think it is. Last, you did not free
the memory. Here is my code without realloc. First I will make calloc work
then I think about realloc. It Segfaults BTW :




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


enum { AVERAGE_SIZE = 28 };

enum { GSW_OK, GSW_ENOMEM, GSW_ENORESIZE } ;


int get_single_word( char** );


int main( void )
{
char* pw; /* pw means pointer to word */

get_single_word( &pw );

printf("word you entered is: %s\n", pw);

return 0;
}



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

size_t curr_size;
char* pc_begin;


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

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

while( ( (ch = getchar()) != EOF) && isspace( (unsigned char)ch ))
{
continue; /* Leading whitespace, protection from some stupid user */
}

for( idx = 0; (ch = getchar()) && (! isspace((unsigned char) ch)); ++idx )
{
if( curr_size == idx )
{
/* realloc, we will think about it later.
use input of size less than ARRSIZE characters for now */
}

if( GSW_OK == ret_value )
{
**pc++ = ch;
}
}


**++pc = '\0';

return ret_value;
}
 
R

Ron Ford

Ron Ford said:



I don't understand what this has to do with the subject of discussion. In
fact, you frequently baffle me with incomprehensible replies that seem to
bear no relation to what is being discussed or indeed to anything
whatsoever. Is this deliberate? If so, please stop. Think about it - the
more you jar people off, the less help you'll get with your C questions.

Ashcroft must have meant less to you than the Americans he had to shut down
to prepare the way for extraconstitutionality. Among the first deviations
to established law were with DARPA, data mining, and spying on domestic
terrorists, aka democrats.

You can say it has nothing to do with C, the house language of the CIA, but
I'll beg to differ. Their methodology is as flawed as mismatched quotes.

You undercounted by one hundred percent on UB with return (*(int
*)p2)-(*(int *)p1); ask Huck. This is a newsgroup. The fundie
interpretation of the topic--there is no C but C--denies the funner part of
the medium, to say nothing of things that can't be said elsewhere, because
Mitt Romney types own every other medium.

Don't worry, I'll move along. I think 7-5 needs 2 solns, one that just
changes getop, and the better one that Ben could complete. Ciao,
C_Dreamer.

Here's 'show me" in two different languages, one that admits of whitespace,
and the other not, the context for which, of course, you snipped:

'Pokozhautye!'
"Zeig mal!"
 
A

arnuld

Think about it. First satisfy yourself that this is correct:

V = calloc(n, sizeof *V);

This is from MAN page itself:

The calloc() function shall allocate unused space for an array
of nelem elements each of whose size in bytes is elsize. The space
shall be initialized to all bits 0.

Array elements in your example are of type V, not *V. This is what
confusing me.




The perror call. The place to display this kind of error message is in
the application code, which in your case is basically main().

so we *always* use perror() in main() ?



Anyway, I finally got around to testing my code, and noticed some bugs.
Fixing those gives working code:


cool :)


.... SNIP.....
int main(void)
{
char *word = NULL;
while(get_single_word(&word) == 0 && word[0] != '\0') {
printf("[%s]\n", word);
free(word);
}

we calloc the memory in some other function while freeing it in some
other. Thats really strange. I am not saying its wrong. I am saying its
feels strange for the programmers who has used languages like Lisp,
Python, Ruby and C++ (only using Std. Lib. like string and vector)


I will code the program and will work on understanding it :)
 
N

Nick Keighley

Nick Keighley said:


What makes you think he's using it pejoratively? He's just saying he
doesn't like academic solutions. I don't like salmon, but that doesn't
mean I consider "salmon" to be a pejorative term.

but it is often used that way.

Are the algorithms in Knuth academic? Does arnuld dislike them?

This isn't about theory vs practice, but about good practice vs indifferent
practice.

and good practice often has a sound theoretical base.
 
A

arnuld

V isn't a type. It's a pointer. Let them be of type T, instead. Okay?

Yes, V points to n elements, each of which is sizeof *V bytes in size. What
is *V? It's the thing pointed to by V. What's sizeof *V, then? Right - the
size of one of these things. It's hard to make this any easier.

I should have been more clear. Take a look st this:

char* T;
T = calloc( 10, sizeof(char));

while your expression is:

char* T;
T = calloc( 10, sizeof(*T));


Thats what I am talking about, I am looking for a place to store N
characters, not 10 pointers to pointers (in our original program). So why
create space for char** when we want to store char(s) in them. This is my
original question about calloc/malloc/realloc

Are you claiming Lisp can only do lists one element long?


No, I am claiming that we never ever think of managing memory in Lisp :)
 
J

James Kuyper

Nick said:
but it is often used that way.

In context, arnuld was using the term "academic" in reference to
Richard's statement 'If this is a mere learning exercise and the
learning task is not error recovery, then yes, by all means bomb out.
That's the "student solution"...'. I think that the contextual meaning
was clearly pejorative ("mere learning exercise"), whether or not he
meant it to be more generally pejorative.
 
B

Ben Bacarisse

arnuld said:
I should have been more clear. Take a look st this:

char* T;
T = calloc( 10, sizeof(char));

while your expression is:

char* T;
T = calloc( 10, sizeof(*T));


Thats what I am talking about, I am looking for a place to store N
characters, not 10 pointers to pointers (in our original program).

And there is the problem (in your understanding). sizeof (*T) is 1.
*T is the first char pointer to by T. It is not in any way a
pointer. It is a way to denote a single char.

It would have been slightly clearer, I think, if you had not used the
name T since Richard was using T as the type of the things pointed to
by V. Is this any clearer:

char *ptr;
ptr = calloc(10, sizeof *ptr);

?
 
J

James Kuyper

arnuld wrote:
....
I should have been more clear. Take a look st this:

char* T;
T = calloc( 10, sizeof(char));

while your expression is:

char* T;
T = calloc( 10, sizeof(*T));


Thats what I am talking about, I am looking for a place to store N
characters, not 10 pointers to pointers (in our original program). So why
create space for char** when we want to store char(s) in them. This is my
original question about calloc/malloc/realloc

It really appears to be a problem with your understanding of how sizeof
operates.

The above statement reserves space for 10 characters; "*T" is an
expression with type 'char', and therefore "sizeof *T" has exactly the
same value as sizeof(char);

In your original code, you had

int get_single_word( char** pc )

and

*pc = calloc(AVERAGE_SIZE-1, sizeof(char));

which Richard recommended that you change to:

*pc = calloc(AVERAGE_SIZE - 1, sizeof **pc);

"**pc" is an expression of type 'char', and therefore "sizeof **pc"
means exactly the same as sizeof(char).

The advantage of using "sizeof **pc" is that deciding whether or not
sizeof(char) is correct requires looking back at the declaration of
'pc'. You can determine whether or not "sizeof **pc" is the right value,
just by looking at this one line; it remains the the correct value, no
matter what the declaration of pc is (unless pc has a type for which the
calloc() call is inappropriate, in which case it's a constraint violation).
 
R

Richard

Richard Heathfield said:
arnuld said:


Not quite. It's:

T = calloc(10, sizeof *T);

(Spot the difference.)

The first is more widely used in the real world in my experience. What
are the problems with

T = calloc( 10, sizeof(*T));

?
 
A

arnuld

In context, arnuld was using the term "academic" in reference to
Richard's statement 'If this is a mere learning exercise and the
learning task is not error recovery, then yes, by all means bomb out.
That's the "student solution"...'. I think that the contextual meaning
was clearly pejorative ("mere learning exercise"), whether or not he
meant it to be more generally pejorative.


I think you guys need to stop arguing and listen to me instead ;) .
Forget about pejorative or bombing out.


My meaning of academic means, "being not practical" . In Indian computer
education system, clrscr() is the function that belongs to a language
named TURBO C, which is better than C. There is *only* one good C and that
is TURBO C. Same for VC++ which, of course , is much better than C++.
Microsoft has created a better language than C.

Thats *exactly* what I have been taught in my 3 years of graduation and
thats *exactly* what academic means. I did not even told that TURBO C was
actually a proprietary compiler. I was told it was the C.


okay, enough of real rant.
 
A

arnuld

It really appears to be a problem with your understanding of how sizeof
operates.

The above statement reserves space for 10 characters; "*T" is an
expression with type 'char', and therefore "sizeof *T" has exactly the
same value as sizeof(char);
....SNIP....


Oh.. no... I think I overwhelmed by the pointers and arrays. Now I got it,
Ben's code also helped me a lot to clear up the confusion:


char *ptr;
ptr = calloc(10, sizeof *ptr);


*ptr is the char actually. same for **ppc in my program. I don't
understand why I was so much messed up in understating this little thing.
 
A

Andrew Poelstra

My meaning of academic means, "being not practical" . In Indian computer
education system, clrscr() is the function that belongs to a language
named TURBO C, which is better than C. There is *only* one good C and that
is TURBO C. Same for VC++ which, of course , is much better than C++.
Microsoft has created a better language than C.

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

(On the other hand, Microsoft does have some real languages now, like C#
and friends, which are perfectly fine languages in their own right, and
don't go around masquerading as other ones.)
Thats *exactly* what I have been taught in my 3 years of graduation and
thats *exactly* what academic means. I did not even told that TURBO C was
actually a proprietary compiler. I was told it was the C.

Well, that's silly.
okay, enough of real rant.

Yes - this entire article is off-topic.
 
A

arnuld

Anyway, I finally got around to testing my code, and noticed some bugs.
Fixing those gives working code:
...SNIP...


I wrote the program without looking at your code and it works fine :) .


..SNIP...
if(ch != EOF)
{
pc_begin[idx++] = ch;

So it is C programming style to do that ? I mean, whenever we get a ** or
a *** pointer in some function argument we should create a new * and
reference it to the original value. e.g. we had a dual indirection pointer
here char **pc, so we did:

pc_begin = *ppc;

or

char*** ppc;
pc_begin = **pppc;

which gives single pointer and has 2 benefits:

1) We can manipulate that single pointer easily without any ambiguous
and confusing pointer arithmetic.
2) It leaves the original pointer unchanged.


Is this the lesson here ?
 
A

arnuld

...SNIP...
Anyway, I finally got around to testing my code, and noticed some bugs.
Fixing those gives working code:

(Headers and #defines as before)

int get_single_word( char** pc )
{
int rc = GSW_ENOMEM; /* if we succeed, we'll update the status */
size_t idx = 0;
int ch;
char *pc_begin = NULL;
size_t cursize = AVERAGE_SIZE;
char *new = NULL;

*pc = calloc(cursize, sizeof **pc);
if(*pc != NULL)
{
rc = GSW_OK; /* so far so good */
pc_begin = *pc;
.....SNIP...

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 ?

....SNIP..

here is what the code of get_words() looks like, which is supposed to
create a dynamic array of pointers pointing to different words:


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

arr_size = ARRSIZE;
mem_check = GW_ENOMEM;

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

if( **pw )
{
mem_check = GW_OK;
pw_begin = **pw;
}
else
{
mem_check = GW_ENOMEM;
return mem_check;
}

if( idx == arr_size )
{
new_mem = realloc( **pw, (2 * arr_size * sizeof new_mem));

if( new_mem )
{
pw_begin = new_mem;

}
else
{
mem_check = GW_ENORESIZE;
return mem_check;
}


Its nearly a duplicate of get_single_word, as the design is same. onlya
few things are confusing me. calloc() will return a pointer to allocated
space which we will assign to a pointer. But in this function we are
working with pointer to arrays or pointer to pointers. So how come get the
pointer to pointer as first element of the allocated space. Or calloc()
does it for us and we can do something like:


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

arnuld

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.

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. and if you do
write a program in standard C (ANSI, I mean), creating a function of your
own to "clear the screen" instead of using clrscr() and #include
<conio.h>, you will not get any marks. I did not get any :(

IIRC, Question was: Write a C program that will .... and will clear the
screen in the end.


Try telling that to the OS390 guys. How many C implementations did your
teachers use before arriving at this opinion?

In our colleges TURBO C is the only thing we know, of course, as of 2008.


How many C++ implementations did your teachers use before arriving at this
opinion?

We use 2: TURBO C++ and VC++. In the beginning of 2008, a 75% marks
holder in MCA (Master of Computer Applications) told me that was taught
by his professor that VC++ is better than C++ . he called
me an idiot when I told him he is not using ISO C++ standard but fell
silent when I asked him explain the difference between a vector and an
array in C++. He apologized later after I told him the difference between
the C++ and the VC++. Guess what .. he was from my college and was my
senior and he is earning 2 times more than me :(



You were told wrong.

I was even told that Windows is a prerequisite for UNIX ..

okay wait... I was also told about the History of Programming Languages:


----- History Begins ------

First we had BASIC and all of the programs were written in BASIC. Then we
had C which replaced BASIC, and now Java has replaced C.

----- History Ends ------


It's hard to know what you're ranting against. If it's the apparent
incompetence of the teaching you are receiving, I sympathise.

I paid a heck lot of money in 3 years for that qualification (2000 -
2003) but found later that just 3 months at USENET refute everything I
learned. Those were one of the the most painful moments of my life when I
learned that there are compilers and there are languages, ( one of
the other painful truth was when I found that we can run our computer
without installing Windows, using Red Hat UNIX:

http://lispmachine.wordpress.com/2007/07/21/the-unix-effect-blindedfolds-removed/


okay, its going very OT, won't reply anymore :)
 
A

arnuld

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.

Will not that make the program less efficient as program has to go till it
finds the return ?


Surely you mean *pw = calloc( arr_size, sizeof **pw );


you say that calloc() will automatically return a pointer to pointer ?

Oh, by the way - I don't see the bit where you point the array's
elements to words. Why isn't get_words calling get_single_word?


because I did not wrote it yet ;) . I wanted to remove some confusions
first and then proceed ahead.
 
A

arnuld

Only if the compiler is really brain-damaged.

Let's say the code is:

if(ptr != NULL) /* A */
{
/* lots of code, translating to 500 bytes of assembly instructions */
}

return ptr; /* B */

The compiler will do something like this:

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


hey.. thats assembly :)
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.

Nobody taught me that way on comp.lang.c++. Seems like C is very closer to
assembly language.


No, calloc returns void * - and I don't see the relevance of your
question to the point I made.


I quoted the wrong code. See this code:

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


*pw means pointer to pointer. I want to dynamically allocate an array of
pointers. but calloc() gives void* in return not void**. So how can
I dynamically allocate an array of pointers. The array elements (pointers)
will point to words ,which again are pointers.


This is going to be base for get_words function, which will be passed the
address of a pointer to pointer, making the 3 levels of indirection coming
into the picture.
 
A

arnuld

...SNIP..
Surely you mean *pw = calloc( arr_size, sizeof **pw );

Oh, by the way - I don't see the bit where you point the array's elements
to words. Why isn't get_words calling get_single_word?


Okay here is my new code:



#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 )
{
if( idx == arr_size )
{
new_mem = realloc( **pw, (2 * arr_size * sizeof new_mem));

if( new_mem )
{
pw_begin = new_mem;
}
else
{
mem_check = GW_ENORESIZE;
}
}

if( GSW_OK == mem_check )
{
pw_begin++ = &pword;
}
}

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)) )
{
continue; /* skip leading white space */
}


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

while( (GSW_OK == mem_check) &&
((ch = getchar()) != EOF) &&
(! isspace( (unsigned char) ch)) )
{
if( idx == curr_size )
{
new_mem = realloc( pc_begin, (2 * curr_size * sizeof(*new_mem)));

if( new_mem )
{
pc_begin = new_mem;
curr_size *= 2;
}
else
{
mem_check = GSW_ENORESIZE; /* error, couldn't not enlarge */
*pc_begin = '\0';
return mem_check;
}
}

if( GSW_OK == mem_check )
{
*pc_begin++ = ch;
}

}


*pc_begin = '\0';


return mem_check;
}

======================= OUTPUT ========================
[arnuld@dune ztest]$ gcc -ansi -pedantic -Wall -Wextra sort-input.c
sort-input.c: In function `get_words':
sort-input.c:79: error: invalid lvalue in assignment
[arnuld@dune ztest]$



Line 79: pw_begin++ = &pword;

I don't understand why I am getting this error.
 

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

No members online now.

Forum statistics

Threads
473,780
Messages
2,569,608
Members
45,248
Latest member
MagdalenaB

Latest Threads

Top