By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
458,167 Members | 1,591 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 458,167 IT Pros & Developers. It's quick & easy.

Reading a string of unknown size

P: n/a
I have to read characters from stdin and save them in a string. The
problem is that I don't know how much characters will be read.

Francesco
--
-------------------------------------

http://www.riscossione.info/
Nov 25 '06 #1
Share this Question
Share on Google+
111 Replies


P: n/a
Tonio Cartonio said:
I have to read characters from stdin and save them in a string. The
problem is that I don't know how much characters will be read.
http://www.cpax.org.uk/prg/writings/fgetdata.php
http://cbfalconer.home.att.net/download/ggets.zip
http://www.iedu.com/mrd/c/getsm.c
http://storm.freeshell.org/anysize.c

Take your pick.

(Coming soon - Eric Sosman's equivalent, if he can remember to attach it to
the email this time...)

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at the above domain, - www.
Nov 25 '06 #2

P: n/a
Tonio Cartonio wrote:
I have to read characters from stdin and save them in a string. The
problem is that I don't know how much characters will be read.
You'll have to read the input, either character-at-a-time, (using
getc() or fgetc()), or line at a time, (using fgets()), and store them
into a block of memory which can be dynamically resized as you read in
more input.

It's fairly easy to do this yourself, but if you want to use an already
available one, try CBFalconer's ggets() function. Search the group's
archive. The URL is mentioned quite regularly.

Nov 25 '06 #3

P: n/a
I have to read characters from stdin and save them in a string. The
problem is that I don't know how much characters will be read.
int main()
{
char *str = NULL, ch ;
int i = 0 ;
str = (char*) malloc (2*sizeof(char)) ;
*str = '\0' ;

while( (ch=getchar()) != '\n' )
{
*(str+i) = ch ;
i++ ;
str = (char*) realloc(str, (2*sizeof(char)) + i ) ;
}
*(str+i) = '\0' ;

printf("\n\n %s ", str) ;

getch() ;
return 0;
}
:)
--
Regards
Santosh S Nayak
E-Mail - sa***********@gmail.com
WebPage -- http://santoshsnayak.googlepages.com

Nov 27 '06 #4

P: n/a
Santosh said:
>I have to read characters from stdin and save them in a string. The
problem is that I don't know how much characters will be read.

int main()
{
char *str = NULL, ch ;
int i = 0 ;
str = (char*) malloc (2*sizeof(char)) ;
Here is your first bug.
*str = '\0' ;
Here's the second.
>
while( (ch=getchar()) != '\n' )
Here's the third.
{
*(str+i) = ch ;
i++ ;
str = (char*) realloc(str, (2*sizeof(char)) + i ) ;
Here's the fourth and fifth, at least.
}
*(str+i) = '\0' ;

printf("\n\n %s ", str) ;
Here's your sixth.
>
getch() ;
And your seventh.
return 0;
}
:)
In fourteen lines of code (excluding spaces and braces), you managed at
least seven bugs. What are you smiling about?

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at the above domain, - www.
Nov 27 '06 #5

P: n/a
:)In fourteen lines of code (excluding spaces and braces), you managed at
least seven bugs. What are you smiling about?
The program works correctly.

No offence pal, but make sure you are at least 10% right before you
reply to any post.

Nov 27 '06 #6

P: n/a
Santosh said:
:)In fourteen lines of code (excluding spaces and braces), you managed
:at
least seven bugs. What are you smiling about?

The program works correctly.
Really? Let's explore that, shall we?

foo.c:2: warning: function declaration isn't a prototype
foo.c: In function `main':
foo.c:3: `NULL' undeclared (first use in this function)
foo.c:3: (Each undeclared identifier is reported only once
foo.c:3: for each function it appears in.)
foo.c:5: warning: implicit declaration of function `malloc'
foo.c:5: warning: cast does not match function type
foo.c:8: warning: implicit declaration of function `getchar'
foo.c:12: warning: implicit declaration of function `realloc'
foo.c:12: warning: cast does not match function type
foo.c:16: warning: implicit declaration of function `printf'
foo.c:18: warning: implicit declaration of function `getch'
make: *** [foo.o] Error 1

Oh, look - it doesn't even compile.
No offence pal, but make sure you are at least 10% right before you
reply to any post.
I was 100% right that your program was a good 50% wrong (in terms of bugs
per line). And it doesn't compile on my system. If it compiles on yours
without generating at least one diagnostic message, then your compiler is
broken.

Furthermore, the OP did not indicate his platform (nor was there any need
for him to do that), let alone his implementation, so you can't just claim
"it works on *my* system", since there is no indication whatsoever that the
OP's system is the same as your system.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at the above domain, - www.
Nov 27 '06 #7

P: n/a
Santosh wrote:
I have to read characters from stdin and save them in a string. The
problem is that I don't know how much characters will be read.
First include necessary headers: stdio.h, stdlib.h
int main()
Better yet, replace above with int main(void)
{
char *str = NULL, ch ;
int i = 0 ;
str = (char*) malloc (2*sizeof(char)) ;
Don't cast return value of malloc() in C. It can hide the non-inclusion
of it's prototype, (by way of failure to include stdlib.h), and, on
some implementations, can result in nasty crashes during runtime.

Since sizeof(char) is by definition 1, you can omit that and instead do
'2 * sizeof *str'. This has the advantage of becoming automatically
updated when you later on happen to change the type of *str.
*str = '\0' ;
And now you're possibly writing to a random area of memory, since you
failed to check the return value of malloc() above for failure.
while( (ch=getchar()) != '\n' )
Check for EOF not newline. Moreover getchar() returns an int value
which you're storing in a char variable, probably getting a spurious
garbage return value when end-of-file is encountered.
{
*(str+i) = ch ;
You've overwritten your earlier nul character.
i++ ;
str = (char*) realloc(str, (2*sizeof(char)) + i ) ;
Again, _don't_ cast the return value of XXalloc() functions in C, and
check the call for failure before proceeding further. Also change
sizeof(char) to sizeof *str.

Anyway, your allocation strategy is very inefficient. Your calling
realloc() once every iteration of the loop. This could result in
fragmentation of the C library's memory pool. Why not allocate in terms
of fixed sized or dynamically growing blocks, say 128 bytes or so to
start with?
}
*(str+i) = '\0' ;

printf("\n\n %s ", str) ;
Unless you terminate the output with a newline character, it's not
guaranteed to show up on screen, or wherever stdout happens to be
directed to.
getch() ;
Non-standard, unportable and unnecessary function. Just get rid of it.

Nov 27 '06 #8

P: n/a
per line). And it doesn't compile on my system. If it compiles on yours
without generating at least one diagnostic message, then your compiler is
broken.

Furthermore, the OP did not indicate his platform (nor was there any need
for him to do that), let alone his implementation, so you can't just claim
"it works on *my* system", since there is no indication whatsoever that the
OP's system is the same as your system.
Do not get too excited and offensive, you forgot to include the
following files:
#include <stdio.h>
#include <conio.h>

If you are using a Unix system:
#include <stdio.h>
#include <sys/types.hOR #include <system.h>

Nov 27 '06 #9

P: n/a
Santosh said:
>per line). And it doesn't compile on my system. If it compiles on yours
without generating at least one diagnostic message, then your compiler is
broken.

Furthermore, the OP did not indicate his platform (nor was there any need
for him to do that), let alone his implementation, so you can't just
claim "it works on *my* system", since there is no indication whatsoever
that the OP's system is the same as your system.

Do not get too excited and offensive,
I am neither excited nor offensive.
you forgot to include the
following files:
#include <stdio.h>
#include <conio.h>
No, I didn't forget: you did.

And C offers no header named <conio.h>
If you are using a Unix system:
#include <stdio.h>
#include <sys/types.hOR #include <system.h>
Wrong. That wouldn't help your program compile.

Furthermore, even with the inclusion of those headers, your program is still
broken in several important ways.

I suggest you stop defending and start thinking.

The Other Santosh has given a good analysis of some of the problems with
your program. If you don't understand that analysis, start asking
intelligent questions instead of acting all defensively.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at the above domain, - www.
Nov 27 '06 #10

P: n/a
Santosh wrote:
:)In fourteen lines of code (excluding spaces and braces), you managed at
least seven bugs. What are you smiling about?

The program works correctly.

No offence pal, but make sure you are at least 10% right before you
reply to any post.
Huh!?

It failes to even compile on my Linux system.

After culling the proprietary getch() call it compiles with several
warnings and runs sucessfully by sheer luck, making several unwarrented
assumptions, which though may hold now, are prone to disastrous failure
anytime, especially if the target machine is anything other than a
standard 32 bit PC.

Looks like you should apply your last statement above to yourself,
before rushing to dismiss others, who may possibly be more knowledgeble
on C than you.

Nov 27 '06 #11

P: n/a
Anyway, your allocation strategy is very inefficient. Your calling
realloc() once every iteration of the loop. This could result in
fragmentation of the C library's memory pool. Why not allocate in terms
of fixed sized or dynamically growing blocks, say 128 bytes or so to
start with?
Very True, I agree with you.
I just wanted to give "Tonio Cartonio" the idea of how to do it.

Nov 27 '06 #12

P: n/a
Santosh wrote: (and failed to maintain attributions)
>
>I have to read characters from stdin and save them in a string. The
The problem is that I don't know how much characters will be read.
Piggy backing. OP's post not available.

Just download and use ggets. Available at:

<http://cbfalconer.home.att.net/download/>

--
Chuck F (cbfalconer at maineline dot net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net>

Nov 27 '06 #13

P: n/a
CBFalconer said:
Santosh wrote: (and failed to maintain attributions)
>>
>>I have to read characters from stdin and save them in a string. The
The problem is that I don't know how much characters will be read.

Piggy backing. OP's post not available.

Just download and use ggets. Available at:

<http://cbfalconer.home.att.net/download/>
I already plugged it, in this very thread. (Along with a bunch of
alternatives.)

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at the above domain, - www.
Nov 27 '06 #14

P: n/a
Santosh said:
>Anyway, your allocation strategy is very inefficient. Your calling
realloc() once every iteration of the loop. This could result in
fragmentation of the C library's memory pool. Why not allocate in terms
of fixed sized or dynamically growing blocks, say 128 bytes or so to
start with?

Very True, I agree with you.
I just wanted to give "Tonio Cartonio" the idea of how to do it.
What you actually gave him was a very good demonstration of how not to do
it.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at the above domain, - www.
Nov 27 '06 #15

P: n/a
Is Santosh a common name ? Or was Santosh
trying to impersonate santosh ? Personally
I didn't realize that Santosh was different than
santosh until santosh's first post and in fact I
was surprised at the way he was conducting himeslf.
(Before I realized they were different people that is.)

Nov 27 '06 #16

P: n/a
Spiros Bousbouras said:
Is Santosh a common name ?
I couldn't say, but I once worked with someone of that name, a few years
ago. I doubt whether it's particularly rare.

<snip>

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at the above domain, - www.
Nov 27 '06 #17

P: n/a
Richard Heathfield <rj*@see.sig.invalidwrites:
Spiros Bousbouras said:
>Is Santosh a common name ?

I couldn't say, but I once worked with someone of that name, a few years
ago. I doubt whether it's particularly rare.
It seems to be fairly common, judging by the results of a Google
search.

I suggest that one or both of the [Ss]antosh's currently posting here
consider using their full name to avoid confusion. (Neither of them,
of course, is obligated to follow my advice.)

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 28 '06 #18

P: n/a
I suggest that one or both of the [Ss]antosh's currently posting here
consider using their full name to avoid confusion. (Neither of them,
of course, is obligated to follow my advice.)
Sounds Logical !
--
Santosh Nayak
E-Mail - sa***********@gmail.com
WebPage -- http://santoshsnayak.googlepages.com

Nov 28 '06 #19

P: n/a

santosh wrote:
Santosh wrote:
I have to read characters from stdin and save them in a string. The
problem is that I don't know how much characters will be read.

First include necessary headers: stdio.h, stdlib.h
int main()

Better yet, replace above with int main(void)
{
char *str = NULL, ch ;
int i = 0 ;
str = (char*) malloc (2*sizeof(char)) ;

Don't cast return value of malloc() in C. It can hide the non-inclusion
of it's prototype, (by way of failure to include stdlib.h), and, on
some implementations, can result in nasty crashes during runtime.

Since sizeof(char) is by definition 1, you can omit that and instead do
'2 * sizeof *str'. This has the advantage of becoming automatically
updated when you later on happen to change the type of *str.
*str = '\0' ;

And now you're possibly writing to a random area of memory, since you
failed to check the return value of malloc() above for failure.
while( (ch=getchar()) != '\n' )

Check for EOF not newline. Moreover getchar() returns an int value
which you're storing in a char variable, probably getting a spurious
garbage return value when end-of-file is encountered.
{
*(str+i) = ch ;

You've overwritten your earlier nul character.
i++ ;
str = (char*) realloc(str, (2*sizeof(char)) + i ) ;

Again, _don't_ cast the return value of XXalloc() functions in C, and
check the call for failure before proceeding further. Also change
sizeof(char) to sizeof *str.

Anyway, your allocation strategy is very inefficient. Your calling
realloc() once every iteration of the loop. This could result in
fragmentation of the C library's memory pool. Why not allocate in terms
of fixed sized or dynamically growing blocks, say 128 bytes or so to
start with?
}
*(str+i) = '\0' ;

printf("\n\n %s ", str) ;

Unless you terminate the output with a newline character, it's not
guaranteed to show up on screen, or wherever stdout happens to be
directed to.
getch() ;

Non-standard, unportable and unnecessary function. Just get rid of it.

Can u please further explain the following statement....

"Don't cast return value of malloc() in C. It can hide the
non-inclusion
of it's prototype, (by way of failure to include stdlib.h), and, on
some implementations, can result in nasty crashes during runtime."

I am unable to understand the intricacies of the above statement.

Nov 28 '06 #20

P: n/a
Sundar wrote:
I am unable to understand the intricacies of the above statement.
Then understand a couple of simpler statements:

1. Do not cast the return value of malloc().

2. If you use malloc() and/or free(), be sure to #include stdlib.h
No intricacies needed :-)

Nov 28 '06 #21

P: n/a

james of tucson wrote:
Sundar wrote:
I am unable to understand the intricacies of the above statement.

Then understand a couple of simpler statements:

1. Do not cast the return value of malloc().

2. If you use malloc() and/or free(), be sure to #include stdlib.h
No intricacies needed :-)
I mean that the definition of malloc says that it returns a void
pointer to the allocated space. Why should u not typecast ur return
void pointer into ur required char or int pointer? And i think that you
dont understand the term "intricacies" else i would not have had to
post my query again.

Nov 28 '06 #22

P: n/a
Sundar said:

<snip>
[...]the definition of malloc says that it returns a void
pointer to the allocated space. Why should u not typecast ur return
void pointer into ur required char or int pointer?
(a) Why would you need to cast? All code should either Do Something Good or
Stop Something Bad Happening. An automatic conversion is supplied, and
that's guaranteed by the Standard, so a cast adds neither value nor
protection.
(b) Without the cast, if you omit <stdlib.hthe compiler is required to
issue a diagnostic message for the mismatch between int and pointer, but
the cast removes this requirement (without fixing the bug that the
diagnostic message is reporting to you), thus giving you a silent bug
instead of a noisy bug.

For a fuller answer, see http://www.cpax.org.uk/prg/writings/casting.php

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at the above domain, - www.
Nov 28 '06 #23

P: n/a
"Santosh Nayak" <sa***********@gmail.comwrites:
>I suggest that one or both of the [Ss]antosh's currently posting here
consider using their full name to avoid confusion. (Neither of them,
of course, is obligated to follow my advice.)

Sounds Logical !
Thanks. If I have this straight, you've been signing yourself as
"Santosh", and you started posting here recently; the other Santosh
has been signing himself as "santosh" and has been posting here for
some time. Is that right?

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 28 '06 #24

P: n/a
Spiros Bousbouras wrote:
Is Santosh a common name ?
Depends. It's more common in N.India than the south. But it isn't a
particularly common name.
Or was Santosh
trying to impersonate santosh ? Personally
I didn't realize that Santosh was different than
santosh until santosh's first post and in fact I
was surprised at the way he was conducting himeslf.
(Before I realized they were different people that is.)
For a split second before I noticed the capitalisation, I thought I was
looking at one of my previous posts. :)

Nov 28 '06 #25

P: n/a
If I have this straight, you've been signing yourself as
"Santosh", and you started posting here recently; the other Santosh
has been signing himself as "santosh" and has been posting here for
some time. Is that right?
Yes, that is right. Thanks for the suggestion.

--
Santosh Nayak
E-Mail - santoshsna...@gmail.com
WebPage -- http://santoshsnayak.googlepages.com

Nov 28 '06 #26

P: n/a
Is Santosh a common name ?
Depends. It's more common in N.India than the south. But it isn't a
particularly common name.
Santosh is also a common name in South Indian (where i belong).

--
Santosh Nayak
E-Mail - santoshsna...@gmail.com
WebPage -- http://santoshsnayak.googlepages.com

Nov 28 '06 #27

P: n/a
Santosh Nayak wrote:
Is Santosh a common name ?
Depends. It's more common in N.India than the south. But it isn't a
particularly common name.

Santosh is also a common name in South Indian (where i belong).
If you say so, though that's contrary to my experience. Anyway let's
stop this discussion, it's getting way off-topic.

Nov 28 '06 #28

P: n/a
santosh wrote:
Santosh wrote:
I have to read characters from stdin and save them in a string. The
problem is that I don't know how much characters will be read.
First include necessary headers: stdio.h, stdlib.h
int main()

Better yet, replace above with int main(void)
{
char *str = NULL, ch ;
int i = 0 ;
str = (char*) malloc (2*sizeof(char)) ;

Don't cast return value of malloc() in C.
This is not a bug. Note that without some sort of cast, there is no
type checking, which is the biggest risk when dealing with void *
pointers.
[...] It can hide the non-inclusion of it's prototype,
On *SOME* older generation compilers. No modern compiler fails to give
a warning about this regardless of the cast.
[...] (by way of failure to include stdlib.h), and, on
some implementations, can result in nasty crashes during runtime.

Since sizeof(char) is by definition 1, you can omit that and instead do
'2 * sizeof *str'. This has the advantage of becoming automatically
updated when you later on happen to change the type of *str.
If you want automatic type safety you should do this:

#define safeMallocStr(p,n,type) do { (p) = (type *) malloc
((n)*sizeof (type)); } while (0);

and you get type checking, and correct semantics. So if you change the
type of the variable you are using, your compiler will issue warnings
if you mismatch here. Any variation you do in which you omit the cast
outside of malloc will fail to catch this "change the definition of the
pointer" scenario.
i++ ;
str = (char*) realloc(str, (2*sizeof(char)) + i ) ;

[...]
Anyway, your allocation strategy is very inefficient. Your calling
realloc() once every iteration of the loop. This could result in
fragmentation of the C library's memory pool. Why not allocate in terms
of fixed sized
Because your memory pool will *still* fragment. It is also O(n^2)
rather than O(n) because of the implicit copying performed in
realloc().
[...] or dynamically growing blocks, say 128 bytes or so to
start with?
You have to do thing in exponential steps (doublings is the most
obvious was to do this) otherwise, weak malloc strategies will
inevitably be explosed. Its also going to be very slow for large
inputs (it really *IS* O(n^2)). So are you going to trade a buffer
overflow in just to be handed back a denial of service?

--
Paul Hsieh
http://www.pobox.com/~qed/
http://bstring.sf.net/

Nov 28 '06 #29

P: n/a
Sundar wrote:
Can u please further explain the following statement....

"Don't cast return value of malloc() in C. It can hide the
non-inclusion
of it's prototype, (by way of failure to include stdlib.h), and, on
some implementations, can result in nasty crashes during runtime."
On really old compilers, if you forget to explicitely declare the
prototype of a function before you use it, the compiler can assume that
it has a prototype like:

extern int malloc ( /* this is not void; its empty. */ );

But what it is supposed to be is:

void * malloc (size_t);

The compiler may emit different callsite code based on these. This is
usually an issue if void * and int are of different sizes, or target
different machine registers or whatever. The reasoning behind leaving
off the cast, is that even old compilers will crap out if you try to
assign an int to a pointer. I.e., they are using a completely
different error to assist you on what is really another kind of error
altogether.

This "automatic prototype" thing has been deprecated in the latest ANSI
C standards and there is basically no moden compiler in existence which
will not issue at least a warning as soon as it detects this scenario.
I personally always compile with "warning equals errors", and warnings
set to max or near max (of course the vendors own header files rarely
compile at the highest warning level -- *sigh*). So its not a real
issue for me, and it shouldn't be an issue for anyone who pays
attention to compiler warnings.

The cast allows for much more serious type checking. If you are using
the pattern:

<var= (<type*) malloc (<count* sizeof (<type>));

and find a way of enforcing that the exact type is repeated precisely
(i.e., use a macro) then this usually works out better. If you change
<typeor the type of <varthe compiler will issue a warning unless
they are synchronized -- if you leave off this cast, you get no
assistance from the compiler, and you just have to get it correct.

So the whole idea of leaving off the cast is to help you because you
might make the mistake of omitting a header (a non-issue on modern
compilers which will give you this warning without this mechanism) but
it sacrifices more detailed type checking like making sure pointers
have the right base type which, for some reason, is not considered (by
some) as relevant a kind of mistake.

The whole "omit the cast" thing is a meme that exists amongst certain
people who have a very skewed idea of what it means to be C programmer.
If they are honest, they think that *development* of your code (not a
port-facto port) may, at any time, be forced onto some old C compiler
where their imagined scenario is an actual issue. More likely they
want to create an intention gratuitous incompatibility with C++ (where
the cast is mandatory.)

--
Paul Hsieh
http://www.pobox.com/~qed/
http://bstring.sf.net/

Nov 28 '06 #30

P: n/a
we******@gmail.com said:
santosh wrote:
>Santosh wrote:
I have to read characters from stdin and save them in a string. The
problem is that I don't know how much characters will be read.
First include necessary headers: stdio.h, stdlib.h
int main()

Better yet, replace above with int main(void)
{
char *str = NULL, ch ;
int i = 0 ;
str = (char*) malloc (2*sizeof(char)) ;

Don't cast return value of malloc() in C.

This is not a bug.
It merely hides one.
Note that without some sort of cast, there is no
type checking, which is the biggest risk when dealing with void *
pointers.
No, there is an even bigger risk - cargo cult programming, which is what
most people are doing when they cast malloc.
>[...] It can hide the non-inclusion of it's prototype,

On *SOME* older generation compilers. No modern compiler fails to give
a warning about this regardless of the cast.
So if anyone comes up with a counter-example, you can simply claim that it's
not a "modern" compiler. ("True Scotsman" argument.) Furthermore, do not
forget that some organisations are remarkably conservative, and will not
change software that they know to work - especially if that software is
mission-critical, as compilers easily can be.
>[...] (by way of failure to include stdlib.h), and, on
some implementations, can result in nasty crashes during runtime.

Since sizeof(char) is by definition 1, you can omit that and instead do
'2 * sizeof *str'. This has the advantage of becoming automatically
updated when you later on happen to change the type of *str.

If you want automatic type safety you should do this:

#define safeMallocStr(p,n,type) do { (p) = (type *) malloc
((n)*sizeof (type)); } while (0);
That doesn't look very type-safe to me.

void *p;
safeMallocStr(p, n, void); /* requires a diagnostic */

void *q;
safeMallocStr(q, n, char);
int *r = q; /* so much for type safety */
and you get type checking, and correct semantics. So if you change the
type of the variable you are using, your compiler will issue warnings
if you mismatch here.
Why not just remove the mismatch risk completely?
Any variation you do in which you omit the cast
outside of malloc will fail to catch this "change the definition of the
pointer" scenario.
Wrong.

T *p;

p = malloc(n * sizeof *p);

Now change p's type to U *. The malloc is still correct, and does not need
an extra, potentially error-prone, edit to a spurious macro call.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at the above domain, - www.
Nov 28 '06 #31

P: n/a
Keith Thompson wrote:
"Santosh Nayak" <sa***********@gmail.comwrites:
>>I suggest that one or both of the [Ss]antosh's currently posting
here consider using their full name to avoid confusion. (Neither
of them, of course, is obligated to follow my advice.)

Sounds Logical !

Thanks. If I have this straight, you've been signing yourself as
"Santosh", and you started posting here recently; the other Santosh
has been signing himself as "santosh" and has been posting here for
some time. Is that right?
I think it's the other way around. The 'good' santosh has been
using lower case s.

--
Chuck F (cbfalconer at maineline dot net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net>
Nov 28 '06 #32

P: n/a
Sundar wrote:
>
.... snip ...
>
Can u please further explain the following statement....

"Don't cast return value of malloc() in C. It can hide the
non-inclusion of it's prototype, (by way of failure to include
stdlib.h), and, on some implementations, can result in nasty
crashes during runtime."

I am unable to understand the intricacies of the above statement.
It's in the FAQ. Don't use silly abbreviations such as 'u'.

--
Chuck F (cbfalconer at maineline dot net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net>
Nov 28 '06 #33

P: n/a
we******@gmail.com wrote:
>
.... snip ...
>
The cast allows for much more serious type checking. If you are
using the pattern:

<var= (<type*) malloc (<count* sizeof (<type>));

and find a way of enforcing that the exact type is repeated
precisely (i.e., use a macro) then this usually works out better.
If you change <typeor the type of <varthe compiler will issue
a warning unless they are synchronized -- if you leave off this
cast, you get no assistance from the compiler, and you just have
to get it correct.
If you use the recommended:

<var= malloc(<count* sizeof *<var>);

you need no casts, and the exact type is enforced without any
concealment behind obfuscating macros or whatever.

--
Chuck F (cbfalconer at maineline dot net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net>
Nov 28 '06 #34

P: n/a
we******@gmail.com wrote:
santosh wrote:
Santosh wrote:
I have to read characters from stdin and save them in a string. The
problem is that I don't know how much characters will be read.
<snip>
i++ ;
str = (char*) realloc(str, (2*sizeof(char)) + i ) ;
[...]
Anyway, your allocation strategy is very inefficient. Your calling
realloc() once every iteration of the loop. This could result in
fragmentation of the C library's memory pool. Why not allocate in terms
of fixed sized

Because your memory pool will *still* fragment. It is also O(n^2)
rather than O(n) because of the implicit copying performed in
realloc().
The implicit copying will be performed in both cases, if realloc() runs
out of contiguous space. In addition calling realloc() for every byte
read adds significant avoidable overhead. Note the test below:

/* t1.c - realloc() once every byte */
#include <stdio.h>
#include <stdlib.h>

int main(void) {
unsigned char *buf = NULL, *stash = NULL;
size_t read = 0, bsize = 0;
int ch;

while((ch = fgetc(stdin)) != EOF) {
if(read == bsize) {
if((buf = realloc(buf, ++bsize)) == NULL) {
if(stash) free(stash);
return EXIT_FAILURE;
}
else stash = buf;
}
buf[read++] = ch;
}
free(stash);
return EXIT_SUCCESS;
}
/* end t1.c */

/* t2.c - buffer doubles upon each reallocation */
#include <stdio.h>
#include <stdlib.h>

int main(void) {
unsigned char *buf = NULL, *stash = NULL;
size_t read = 1, bsize = 1;
int ch;

while((ch = fgetc(stdin)) != EOF) {
if(read == bsize) {
if((buf = realloc(buf, bsize <<= 1)) == NULL) {
free(stash);
return EXIT_FAILURE;
}
else stash = buf;
}
buf[read - 1] = ch;
read++;
}
free(stash);
return EXIT_SUCCESS;
}
/* end t2.c */

$ gcc -Wall -Wextra -ansi -pedantic -o t1 t1.c
$ gcc -Wall -Wextra -ansi -pedantic -o t2 t2.c
$ du -b t1
7315 t1
$ du -b t2
7299 t2
$ du -sh /cdrom/boot/isolinux/linux
1.7M /cdrom/boot/isolinux/linux
$ time ./t1 < /cdrom/boot/isolinux/linux
real 0m1.483s
user 0m0.600s
sys 0m0.880s
$time ./t2 < /cdrom/boot/isolinux/linux
real 0m0.131s
user 0m0.104s
sys 0m0.028s
$

Well, apparently, the exponential allocation scheme is significantly
faster than the linear one.
[...] or dynamically growing blocks, say 128 bytes or so to
start with?

You have to do thing in exponential steps (doublings is the most
obvious was to do this) otherwise, weak malloc strategies will
inevitably be explosed. Its also going to be very slow for large
inputs (it really *IS* O(n^2)).
I'm sorry but I don't quite understand how it's going to any _slower_
than calling realloc() every one byte. I guess for large files, (or any
file for that matter), the disk overhead is going to swamp that of
realloc(), whether or not it's called every byte, since they won't be
buffered by the operating system.
So are you going to trade a buffer
overflow in just to be handed back a denial of service?
You can possibly recover from a denial of service situation but a
buffer overflow could mean a hard crash.

Nov 28 '06 #35

P: n/a
santosh wrote:
we******@gmail.com wrote:
santosh wrote:
Santosh wrote:
I have to read characters from stdin and save them in a string. The
problem is that I don't know how much characters will be read.
i++ ;
str = (char*) realloc(str, (2*sizeof(char)) + i ) ;
>
[...]
Anyway, your allocation strategy is very inefficient. Your calling
realloc() once every iteration of the loop. This could result in
fragmentation of the C library's memory pool. Why not allocate in terms
of fixed sized
Because your memory pool will *still* fragment. It is also O(n^2)
rather than O(n) because of the implicit copying performed in
realloc().

The implicit copying will be performed in both cases, if realloc() runs
out of contiguous space. In addition calling realloc() for every byte
read adds significant avoidable overhead. Note the test below:

/* t1.c - realloc() once every byte */
#include <stdio.h>
#include <stdlib.h>

int main(void) {
unsigned char *buf = NULL, *stash = NULL;
size_t read = 0, bsize = 0;
int ch;

while((ch = fgetc(stdin)) != EOF) {
if(read == bsize) {
if((buf = realloc(buf, ++bsize)) == NULL) {
if(stash) free(stash);
return EXIT_FAILURE;
}
else stash = buf;
}
buf[read++] = ch;
}
free(stash);
return EXIT_SUCCESS;
}
/* end t1.c */

/* t2.c - buffer doubles upon each reallocation */
#include <stdio.h>
#include <stdlib.h>

int main(void) {
unsigned char *buf = NULL, *stash = NULL;
size_t read = 1, bsize = 1;
int ch;

while((ch = fgetc(stdin)) != EOF) {
if(read == bsize) {
if((buf = realloc(buf, bsize <<= 1)) == NULL) {
free(stash);
return EXIT_FAILURE;
}
else stash = buf;
}
buf[read - 1] = ch;
read++;
}
free(stash);
return EXIT_SUCCESS;
}
/* end t2.c */

$ gcc -Wall -Wextra -ansi -pedantic -o t1 t1.c
$ gcc -Wall -Wextra -ansi -pedantic -o t2 t2.c
$ du -b t1
7315 t1
$ du -b t2
7299 t2
$ du -sh /cdrom/boot/isolinux/linux
1.7M /cdrom/boot/isolinux/linux
$ time ./t1 < /cdrom/boot/isolinux/linux
real 0m1.483s
user 0m0.600s
sys 0m0.880s
$time ./t2 < /cdrom/boot/isolinux/linux
real 0m0.131s
user 0m0.104s
sys 0m0.028s
$

Well, apparently, the exponential allocation scheme is significantly
faster than the linear one.
There is a reason for this. Let's do the math. The exponential
realloc strategy means you will call realloc() log_2(n) times, each
with a cost of 1, 2, 4, ..., O(N) in the event of a required memcpy().
Sum that up and you will see that its O(N). The constant factor is
basically 2 writes per byte.

If you do it linearly, k bytes at a time, then you will do O(N/k)
reallocs, with an average potential memcpy penalty of N/2. So that's a
cost of O(N*N/(2*k)) which is O(N^2).

Changing from "every byte" to some linear block of length k, is
basically trying to decrease the constant factor outside of the O(N^2).
Of course that will work for small N, but that's pointless and
unnecessary, and ineffective for large N.

This analysis is critically important, since it affects what you say
next:
[...] or dynamically growing blocks, say 128 bytes or so to
start with?
You have to do thing in exponential steps (doublings is the most
obvious was to do this) otherwise, weak malloc strategies will
inevitably be explosed. Its also going to be very slow for large
inputs (it really *IS* O(n^2)).

I'm sorry but I don't quite understand how it's going to any _slower_
than calling realloc() every one byte.
Who said this?
[...] I guess for large files, (or any
file for that matter), the disk overhead is going to swamp that of
realloc(), whether or not it's called every byte, since they won't be
buffered by the operating system.
If you are swapping to disk, then the inherent memcpy() performance hit
is still there and is significantly worsened. In fact I would suggest
that any scenario that leads to disk swapping in the linear growth
method would necessarily turn into a kind of DOS (whether intentional
or not.) While a robust enough system using the exponential strategy
is likely to continue to function even if it does swap.
So are you going to trade a buffer
overflow in just to be handed back a denial of service?

You can possibly recover from a denial of service situation but a
buffer overflow could mean a hard crash.
So you are saying its ok to suffer DOSes when there is no good reason
to do so?

--
Paul Hsieh
http://www.pobox.com/~qed/
http://bstring.sf.net/

Nov 28 '06 #36

P: n/a
CBFalconer wrote:
we******@gmail.com wrote:
... snip ...

The cast allows for much more serious type checking. If you are
using the pattern:

<var= (<type*) malloc (<count* sizeof (<type>));

and find a way of enforcing that the exact type is repeated
precisely (i.e., use a macro) then this usually works out better.
If you change <typeor the type of <varthe compiler will issue
a warning unless they are synchronized -- if you leave off this
cast, you get no assistance from the compiler, and you just have
to get it correct.

If you use the recommended:

<var= malloc(<count* sizeof *<var>);

you need no casts, and the exact type is enforced without any
concealment behind obfuscating macros or whatever.
Well, this still has the potential for cut and paste errors unless you
macrofy the whole line. If you don't macrofy, then you risk error no
matter what.

So let us take a more serious approach compare macros which prevent any
mismatch errors:

#define scaredOfCPlusPlus(var,count) var = malloc(count*sizeof *var)
#define newThing(type,count) (type *) malloc (count * sizeof (type))

So you can say var = newThing(char *, 512), and if the type is wrong,
the compiler tells you. Furthermore you can pass newThing(,) as a
parameter to a function. The scaredOfCPlusPlus(,) macro works fine,
but doesn't look familliar, and can't be passed as a parameter to a
function.

And, of course, the real difference is that the first compiles straight
in C++, and the second is just an error. I have found that in general
the C++ optimizers and warnings are better for the C++ mode of my
compilers than the C mode.

--
Paul Hsieh
http://www.pobox.com/~qed/
http://bstring.sf.net/

Nov 28 '06 #37

P: n/a
In article <11**********************@80g2000cwy.googlegroups. com>,
<we******@gmail.comwrote:
>And, of course, the real difference is that the first compiles straight
in C++, and the second is just an error. I have found that in general
the C++ optimizers and warnings are better for the C++ mode of my
compilers than the C mode.
Fortran compilers are usually even better than that. Obviously
you should write your C code so that it compiles with Fortran compilers.
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (4039.22'N, 11150.29'W) +1 801 277 2603
email: forget about it http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.
Nov 28 '06 #38

P: n/a


we******@gmail.com wrote On 11/28/06 14:54,:
CBFalconer wrote:
>>we******@gmail.com wrote:

... snip ...
>>>The cast allows for much more serious type checking. If you are
using the pattern:

<var= (<type*) malloc (<count* sizeof (<type>));

and find a way of enforcing that the exact type is repeated
precisely (i.e., use a macro) then this usually works out better.
If you change <typeor the type of <varthe compiler will issue
a warning unless they are synchronized -- if you leave off this
cast, you get no assistance from the compiler, and you just have
to get it correct.

If you use the recommended:

<var= malloc(<count* sizeof *<var>);

you need no casts, and the exact type is enforced without any
concealment behind obfuscating macros or whatever.


Well, this still has the potential for cut and paste errors unless you
macrofy the whole line. If you don't macrofy, then you risk error no
matter what.
(Macros cure errors? News to me ...)

The principal advantage of the recommended form is that a
visual inspection of the line *in isolation* tells you whether
it's correct or incorrect. If the l.h.s. agrees with the sizeof
operand, the allocation is correct (unless <varis a float or
an int or some other non-pointer thing, in which case the
compiler will squawk anyhow).

You do not need to go hunting for the declaration of <var>,
nor do you need to rummage around for the definition of some
macro and try to figure out its expansion. You can verify the
correctness of the code with a "local" inspection, without
digging through a pile of headers, hoping you've found the
right version and haven't been fooled by a morass of conditional
compilation.
So let us take a more serious approach compare macros which prevent any
mismatch errors:

#define scaredOfCPlusPlus(var,count) var = malloc(count*sizeof *var)
#define newThing(type,count) (type *) malloc (count * sizeof (type))

So you can say var = newThing(char *, 512), and if the type is wrong,
the compiler tells you. Furthermore you can pass newThing(,) as a
parameter to a function. The scaredOfCPlusPlus(,) macro works fine,
but doesn't look familliar, and can't be passed as a parameter to a
function.
Why not? I don't see any advantage in writing such a macro,
but if you chose to do so the expression it generated would be
perfectly good as an argument to function.
And, of course, the real difference is that the first compiles straight
in C++, and the second is just an error. I have found that in general
the C++ optimizers and warnings are better for the C++ mode of my
compilers than the C mode.
(Have you interchanged "first" and "second" here?)

It doesn't seem to me that one's C style should be twisted
in deference to the practices of C++, or of Java, or of COBOL.
Nor vice versa, of course. Speak English or speak Spanish,
but don't lapse into Spanglish.

--
Er*********@sun.com

Nov 28 '06 #39

P: n/a
"Santosh Nayak" <sa***********@gmail.comwrites:
>If I have this straight, you've been signing yourself as
"Santosh", and you started posting here recently; the other Santosh
has been signing himself as "santosh" and has been posting here for
some time. Is that right?

Yes, that is right. Thanks for the suggestion.
You're welcome.

And please don't snip attribution lines. I wrote the text above
starting with "If I have this straight". There should have been a
line at the start of the quoted text identifying the author, something
like "Keith Thompson <ks***@mib.orgwrites:". The Google interface
automatically provides such a line; please don't delete it.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 28 '06 #40

P: n/a
CBFalconer <cb********@yahoo.comwrites:
Keith Thompson wrote:
>"Santosh Nayak" <sa***********@gmail.comwrites:
>>>I suggest that one or both of the [Ss]antosh's currently posting
here consider using their full name to avoid confusion. (Neither
of them, of course, is obligated to follow my advice.)

Sounds Logical !

Thanks. If I have this straight, you've been signing yourself as
"Santosh", and you started posting here recently; the other Santosh
has been signing himself as "santosh" and has been posting here for
some time. Is that right?

I think it's the other way around. The 'good' santosh has been
using lower case s.
That's what I said. Assuming that "the 'good' santosh" refers to
the one who's been posting here for a long time (I'm not going to
make any value judgements), he's the one who has been posting with a
lower case s; Santosh Nayak is the relative newcomer, and he's been
posting with an upper case S. (And Santosh Nayak confirmed this,
in a followup that you probably didn't see before posting yours.)

So, "santosh" (no last name, lower case s) has been posting here for a
long time, and "Santosh Nayak" is a relative newcomer, who briefly
posted as "Santosh".

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 28 '06 #41

P: n/a
In article <ek********@news3.newsguy.com>,
Chris Torek <no****@torek.netwrote:
>>And, of course, the real difference is that the first compiles straight
in C++, and the second is just an error. I have found that in general
the C++ optimizers and warnings are better for the C++ mode of my
compilers than the C mode.
>Fortran compilers are usually even better than that. Obviously
you should write your C code so that it compiles with Fortran compilers.
Or use IBM's PL/1 checkout compiler. It will give you lots of
warnings, but will probably translate your code into PL/1 as a bonus.

-- Richard
--
"Consideration shall be given to the need for as many as 32 characters
in some alphabets" - X3.4, 1963.
Nov 28 '06 #42

P: n/a
On 27 Nov 2006 20:46:32 -0800, "Sundar" <su*********@gmail.comwrote:
>
santosh wrote:
Can u please further explain the following statement....

"Don't cast return value of malloc() in C. It can hide the
non-inclusion
of it's prototype, (by way of failure to include stdlib.h), and, on
some implementations, can result in nasty crashes during runtime."

I am unable to understand the intricacies of the above statement.
Under the C89 standard, an undeclared function is presumed to return
an int. It is entirely possible for an int to be returned by a
function using a different method than that used to return a pointer.

If there is no prototype in scope for malloc, but there is a cast,
then the usual warning about converting from an int to a pointer is
suppressed because the cast says to the compiler "I know what I'm
doing". The code that is generated will convert the supposed int to a
pointer. Since malloc really returned a pointer, the generated code
is processing a non-existent int.

Furthermore, malloc requires a size_t argument. There is an awful lot
of code where the argument expression has type int. If a prototype is
in scope, the argument will be converted automatically. If not, the
compiler will happily generate an int and pass it to malloc. If
size_t is not an (unsigned) int but a larger type, who knows what data
malloc will consider as the argument.

Both cases are examples of undefined behavior which, according to
Murphy's law, will appear to work until it is most damaging not to
(e.g., demonstration in front of very important customer).

On the other had, if you omit the cast, the diagnostic regarding the
conversion of an implied int to a pointer should provide enough
incentive to include stdlib.h which will automatically eliminate the
possibility of either problem occurring.

Since there is a well-defined implied conversion between void* and any
other object pointer type in either direction, the cast gains you
nothing but prevents the compiler from helping you in the case you
forgot the include the header. What some might call a lose/no-win
situation.

The oft recommended position in clc is cast only when you really know
why your are casting.
Remove del for email
Nov 29 '06 #43

P: n/a
Eric Sosman wrote:
we******@gmail.com wrote On 11/28/06 14:54,:
CBFalconer wrote:
>we******@gmail.com wrote:

... snip ...

The cast allows for much more serious type checking. If you are
using the pattern:

<var= (<type*) malloc (<count* sizeof (<type>));

and find a way of enforcing that the exact type is repeated
precisely (i.e., use a macro) then this usually works out better.
If you change <typeor the type of <varthe compiler will issue
a warning unless they are synchronized -- if you leave off this
cast, you get no assistance from the compiler, and you just have
to get it correct.

If you use the recommended:

<var= malloc(<count* sizeof *<var>);

you need no casts, and the exact type is enforced without any
concealment behind obfuscating macros or whatever.

Well, this still has the potential for cut and paste errors unless you
macrofy the whole line. If you don't macrofy, then you risk error no
matter what.

(Macros cure errors? News to me ...)
I'm sure a lot of obvious things are news to you. What's not news to
me is that you would take a narrow statement I've made and
intentionally pretend I said something more general.
The principal advantage of the recommended form is that a
visual inspection of the line *in isolation* tells you whether
it's correct or incorrect.
Which means what, in terms of coding safety? You are trading compiler
enforced type checking for manual based safety checking. You don't see
the inherent flaw in this? In your world people get blamed for
mistakes that in my world cannot even be made.
[...] If the l.h.s. agrees with the sizeof
operand, the allocation is correct (unless <varis a float or
an int or some other non-pointer thing, in which case the
compiler will squawk anyhow).

You do not need to go hunting for the declaration of <var>,
My compiler tells me the two types that are in conflict at the
diagnostic line (as does yours, probably) so I don't need to "hunt" for
anything with my solution either.
nor do you need to rummage around for the definition of some
macro and try to figure out its expansion. You can verify the
correctness of the code with a "local" inspection, without
digging through a pile of headers, hoping you've found the
right version and haven't been fooled by a morass of conditional
compilation.
The risk of error is simply not balanced by this. You can name your
macro genericArrayAlloc(,) and I don't think people will worry too much
about how the macro expands.

If your code is hundreds of thousands of lines, or if its been
substantially written by someone else, then manual inspection of all
your code is not a feasible option. Wherever possible, the tools and
compilers themselves should be enlisted to find as many "obvious once
you look at it" kinds of bugs automatically.
So let us take a more serious approach compare macros which prevent any
mismatch errors:

#define scaredOfCPlusPlus(var,count) var = malloc(count*sizeof *var)
#define newThing(type,count) (type *) malloc (count * sizeof (type))

So you can say var = newThing(char *, 512), and if the type is wrong,
the compiler tells you. Furthermore you can pass newThing(,) as a
parameter to a function. The scaredOfCPlusPlus(,) macro works fine,
but doesn't look familliar, and can't be passed as a parameter to a
function.

Why not? I don't see any advantage in writing such a macro,
but if you chose to do so the expression it generated would be
perfectly good as an argument to function.
It requires an additional variable declaration that may be superfluous.
Hiding the "=" operator or anything as complex in macros is the kind
of thing that eventually leads to problems.
And, of course, the real difference is that the first compiles straight
in C++, and the second is just an error. I have found that in general
the C++ optimizers and warnings are better for the C++ mode of my
compilers than the C mode.

(Have you interchanged "first" and "second" here?)
(Yes)
It doesn't seem to me that one's C style should be twisted
in deference to the practices of C++, or of Java, or of COBOL.
It isn't a matter of style. Its a matter of gaining access to better
tools. My C compilers simply don't emit a comparable number of
diagnostics, nor the quality of code that my C++ compilers do (even
when they are made by the very same vendor, packaged in the very same
tool.)

Making your C code compilable in C++ is a net gain in productivity, and
leads to a drammatic improvement in correctness, and a measurable
improvement in object code performance. Java and COBOL are
non-sequitor in this discussion.

--
Paul Hsieh
http://www.pobox.com/~qed/
http://bstring.sf.net/

Nov 29 '06 #44

P: n/a
Chris Torek wrote:
we******@gmail.com wrote:
And, of course, the real difference is that the first compiles straight
in C++, and the second is just an error. I have found that in general
the C++ optimizers and warnings are better for the C++ mode of my
compilers than the C mode.

Fortran compilers are usually even better than that.
Uhhh ... no they are not. Fortran compilers only compare favorably to
some C compilers in very narrow situations where the C compiler is
unable to prove that some pointers are non-aliasing ("restrict" was
added to C99 to eliminate this scenario completely). The real
challenge is to implement x << y in Fortran so that its no worse than 4
times slower than the comparable C output.

The point is, of course, that you almost certainly already know this
....
[...] Obviously
you should write your C code so that it compiles with Fortran compilers.
.... which makes this at best a poor attempt at sarcasm, but more likely
an intentional deception.

--
Paul Hsieh
http://www.pobox.com/~qed/
http://bstring.sf.net/

Nov 29 '06 #45

P: n/a
we******@gmail.com writes:
Chris Torek wrote:
[...]
>[...] Obviously
you should write your C code so that it compiles with Fortran compilers.

... which makes this at best a poor attempt at sarcasm, but more likely
an intentional deception.
Chris's comment was obviously sarcastic (I won't comment on whether it
was a "poor attempt"). If you seriously believe that Chris Torek is
intentionally trying to deceive people into believing that programmers
should write C code so it compiles with Fortran compilers, you have a
*severe* misunderstanding.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Nov 29 '06 #46

P: n/a
Richard Heathfield wrote:
we******@gmail.com said:
santosh wrote:
Santosh wrote:
I have to read characters from stdin and save them in a string. The
problem is that I don't know how much characters will be read.
First include necessary headers: stdio.h, stdlib.h

int main()

Better yet, replace above with int main(void)

{
char *str = NULL, ch ;
int i = 0 ;
str = (char*) malloc (2*sizeof(char)) ;

Don't cast return value of malloc() in C.
This is not a bug.

It merely hides one.
Note that without some sort of cast, there is no
type checking, which is the biggest risk when dealing with void *
pointers.

No, there is an even bigger risk - cargo cult programming, which is what
most people are doing when they cast malloc.
Uhh ... ok, but which has worse outcome? Superfluous structure that
your compiler is going to strip out of the object code anyways has no
negative impact on correctness or performance. Messing up a void *
pointer will cause truly arbitrary action. The two are not comparable
by outcome.
[...] It can hide the non-inclusion of it's prototype,
On *SOME* older generation compilers. No modern compiler fails to give
a warning about this regardless of the cast.

So if anyone comes up with a counter-example, you can simply claim that it's
not a "modern" compiler. ("True Scotsman" argument.)
For development? Are you going to use a digital watch to run your
compiler? You can demand minimum standards for your development
platform -- and numerous free compilers exist that behave as I suggest.
[...] Furthermore, do not
forget that some organisations are remarkably conservative, and will not
change software that they know to work - especially if that software is
mission-critical, as compilers easily can be.
Right -- but those same organizations are unlikely to be developing
lots of new code anyways. I don't look to such organizations to
leadership on how I should program. I only suffer their nonsense if
they are handing me a paycheck.
[...] (by way of failure to include stdlib.h), and, on
some implementations, can result in nasty crashes during runtime.

Since sizeof(char) is by definition 1, you can omit that and instead do
'2 * sizeof *str'. This has the advantage of becoming automatically
updated when you later on happen to change the type of *str.
If you want automatic type safety you should do this:

#define safeMallocStr(p,n,type) do { (p) = (type *) malloc
((n)*sizeof (type)); } while (0);

That doesn't look very type-safe to me.

void *p;
safeMallocStr(p, n, void); /* requires a diagnostic */
My compiler barfs on sizeof(void). So the error is caught.
void *q;
safeMallocStr(q, n, char);
int *r = q; /* so much for type safety */
That's ridiculous. Use of void * is never type safe. Using the
non-casting style of malloc usage doesn't change the above scenario in
any relevant way. Ironically, the correct solution is to use a C++
compiler which would spit errors at you for the last line.
and you get type checking, and correct semantics. So if you change the
type of the variable you are using, your compiler will issue warnings
if you mismatch here.

Why not just remove the mismatch risk completely?
What risk are you talking about? Outside of gratuitous use of void *
pointers (which is tantamount to using gets() in "controlled
environments") there is no risk.
Any variation you do in which you omit the cast
outside of malloc will fail to catch this "change the definition of the
pointer" scenario.

Wrong.

T *p;

p = malloc(n * sizeof *p);

Now change p's type to U *. The malloc is still correct, and does not need
an extra, potentially error-prone, edit to a spurious macro call.
The macro is potentially error-prone, but mismatching the variable and
the thing you are taking sizeof is not error-prone? Fiirst of all, you
have not explained how the macro is error prone, while the above is so
obviously susceptable to cut-and-paste errors.

--
Paul Hsieh
http://www.pobox.com/~qed/
http://bstring.sf.net/

Nov 29 '06 #47

P: n/a
we******@gmail.com wrote:
Eric Sosman wrote:
>>we******@gmail.com wrote On 11/28/06 14:54,:
>>>[...]
Well, this still has the potential for cut and paste errors unless you
macrofy the whole line. If you don't macrofy, then you risk error no
matter what.

(Macros cure errors? News to me ...)

I'm sure a lot of obvious things are news to you.
I'm sure you're right, which means I must have missed
something obvious.
> The principal advantage of the recommended form is that a
visual inspection of the line *in isolation* tells you whether
it's correct or incorrect.

Which means what, in terms of coding safety? You are trading compiler
enforced type checking for manual based safety checking. You don't see
the inherent flaw in this? In your world people get blamed for
mistakes that in my world cannot even be made.
No, I'm considering the poor sod who's trying to track down
a bug in a big hairy intertwined mess of code. If he's reading
along and he sees the Recommended Form, he can tell at once that
it's correct and not the cause of his problem (barring a mis-
computation of the number of items to be allocated, which he
needs to check in either formulation). He is not distracted by
the need to go haring off to other parts of the code base to find
out what the Dickens this macro is, or whether its customary
definition has been overridden by some "clever" use of #ifdef in
a well-concealed header file. (If you haven't encountered such
things, you haven't been around long enough.) He can read, verify,
and move along, all without scrolling the screen. That means his
attention is not diverted away from whatever the bug is; blind
alleys are eliminated without strolling down them.
The risk of error is simply not balanced by this. You can name your
macro genericArrayAlloc(,) and I don't think people will worry too much
about how the macro expands.
If they don't, they should. Quickly, now: From the evidence
at hand, which argument is the type and which is the count? Or
is one of the arguments supposed to be the l.h.s. variable name
and not a type name at all? You can stare all day at the point
of invocation and not know what the macro expands to -- and you
can hunt all day through mazes of header files to find half a
dozen different conflicting definitions of the macro, and waste
time trying to figure out which is in force at the point of interest.
If your code is hundreds of thousands of lines, or if its been
substantially written by someone else, then manual inspection of all
your code is not a feasible option. Wherever possible, the tools and
compilers themselves should be enlisted to find as many "obvious once
you look at it" kinds of bugs automatically.
The largest program I have worked on myself was only about three
million lines, roughly 2.5 million of C and 0.5 million of Lisp.
It was written and rewritten and re-rewritten over a period of about
fifteen years by a programming team that started as half-a-dozen
crazy zealots and grew (irregularly) to perhaps ninety or a hundred
people. I was one of them for eleven years, and have (I think) the
bare beginnings of an idea of what it must be like to work on a
big software project. (No, three million lines isn't "big" by any
standard. All I'm saying is that it's "big enough" to exceed a
human's ability for direct comprehension and to require the use of
conventions and suchlike formalisms as aids to understanding.)

And in light of what I've experienced, I stand by my opinion.
>>>So you can say var = newThing(char *, 512), and if the type is wrong,
the compiler tells you. Furthermore you can pass newThing(,) as a
parameter to a function. The scaredOfCPlusPlus(,) macro works fine,
but doesn't look familliar, and can't be passed as a parameter to a
function.

Why not? I don't see any advantage in writing such a macro,
but if you chose to do so the expression it generated would be
perfectly good as an argument to function.

It requires an additional variable declaration that may be superfluous.
Hiding the "=" operator or anything as complex in macros is the kind
of thing that eventually leads to problems.
Straw man: It was your decision, not mine, to hide an assignment
inside the macro. You are criticizing your own macro, not the form
it distorts.
Making your C code compilable in C++ is a net gain in productivity,
and leads to a drammatic improvement in correctness, and a measurable
improvement in object code performance. Java and COBOL are
non-sequitor in this discussion.
"Sequitur." It's Latin, like C an old-fashioned language. If
you prefer Italian and C++ by all means speak them, but don't try
to give advice to the classicists.

--
Eric Sosman
es*****@acm-dot-org.invalid
Nov 29 '06 #48

P: n/a
Keith Thompson wrote:
we******@gmail.com writes:
Chris Torek wrote:
[...]
[...] Obviously
you should write your C code so that it compiles with Fortran compilers.
... which makes this at best a poor attempt at sarcasm, but more likely
an intentional deception.

Chris's comment was obviously sarcastic (I won't comment on whether it
was a "poor attempt"). If you seriously believe that Chris Torek is
intentionally trying to deceive people into believing that programmers
should write C code so it compiles with Fortran compilers, you have a
*severe* misunderstanding.
Typical shallow point of view on your part.

He's deceiving people by 1) intentionally reading that my argument is
that you should make your C code work in languages that might output
faster code (clearly I am picking C++ for the obvious reasons) and 2)
he's propogating the idea that Fortran is faster than C as a blanket
statement (this isn't true).

For sarcasm to be effective, you normally fairly represent what the
opposing idea (not done here) is and then show it at its extreme. He
starts by encoding two deceptions (which is a very typical propogandist
trick; if you unravel one deception, you may still fail to unwrap the
other) then applies his sarcasm in this case as a means of
misdirection. Then the sheep just ignore the deceptions and assess it
for its sarcastic value.

People who watch Fox News critically will recognize this as a very
standard trick they engage in all the time (host: "Do the democracts
support terrorism by suggesting we withdraw our troops?" fake-liberal:
"No! We are not cut and runners").

The only question here: Is Chris a liar or is he stupid? I don't think
he's stupid.

--
Paul Hsieh
http://www.pobox.com/~qed/
http://bstring.sf.net/

Nov 29 '06 #49

P: n/a
we******@gmail.com said:

<snip>
he's propogating the idea that Fortran is faster than C as a blanket
statement (this isn't true).
He said no such thing.
The only question here: Is Chris a liar or is he stupid? I don't think
he's stupid.
Nor is he a liar. And to ask the only *other* question remaining, I don't
think you're a liar either. So that's settled, then.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at the above domain, - www.
Nov 29 '06 #50

111 Replies

This discussion thread is closed

Replies have been disabled for this discussion.