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

a little mistake

P: n/a
ash
i am writing this program (for exercise1-9 in k&r-2nd edition) which
removes extra spaces in string
example- "test string" will be "test string"

#include<stdio.h>
#include<string.h>
#include<conio.h>
main()
{
char str[20],st[20];
int i=0,j=0;
printf("enter string");
gets(str);

while(str[i]!=NULL)
{
if(str[i]==' ')
{ st[j++]=st[i++];

while(str[i]==' ') i++;

}
else
st[j++]=str[i++];
}
st[j]=NULL;
strcpy(str,st);
puts(str);
}

(compiled in turbo c++ for windows version 3.1)
i know there should be other ways to write this program (thats a bad
program ),can someone help me in writing that program in compact way
and give me some logic and tips.
i want to use gcc but i don`t have linux operating system and one
software which allows gcc compiling in windows (cygwin) is not working.
anyone can advice me such a program that allows compiling with gcc in
windows( this is off topic but advices are always welcome).

thankx

Jun 16 '06 #1
Share this Question
Share on Google+
54 Replies


P: n/a

"ash" <as************@rediffmail.com> wrote in message
news:11**********************@i40g2000cwc.googlegr oups.com...
i am writing this program (for exercise1-9 in k&r-2nd edition) which
removes extra spaces in string
example- "test string" will be "test string"

#include<stdio.h>
#include<string.h>
#include<conio.h>
main()
{
char str[20],st[20];
int i=0,j=0;
printf("enter string");
gets(str);

while(str[i]!=NULL)
{
if(str[i]==' ')
{ st[j++]=st[i++];

while(str[i]==' ') i++;

}
else
st[j++]=str[i++];
}
st[j]=NULL;
strcpy(str,st);
puts(str);
}

(compiled in turbo c++ for windows version 3.1)
i know there should be other ways to write this program (thats a bad
program ),can someone help me in writing that program in compact way
and give me some logic and tips.
i want to use gcc but i don`t have linux operating system and one
software which allows gcc compiling in windows (cygwin) is not working.
anyone can advice me such a program that allows compiling with gcc in
windows( this is off topic but advices are always welcome).

thankx

Separate out ewhat you are doing into a function.

In this case you want

/*
turns whitespace spans into single spaces
(and trims leading / trailing white space?)
*/
void onespace(char *out, char *in)

Decide if you want to allow out and in to be the same. This will make your
function
more convenient to use, but you might have to be a little bit more careful
in coding it.

Basically you maintain two pointer, a "write" pointer and a "read" pointer.
If you hit
a non-whitespace you write to the "write" pointer and increment both.
If you hit a whitespace character, you write a single space to the "write"
pointer. Then you increment the "read" pointer whilst it is still pointing
to white space.
--
Buy my book 12 Common Atheist Arguments (refuted)
$1.25 download or $7.20 paper, available www.lulu.com/bgy1mm
Jun 16 '06 #2

P: n/a
ash wrote:
.... snip ...
i want to use gcc but i don`t have linux operating system and one
software which allows gcc compiling in windows (cygwin) is not working.
anyone can advice me such a program that allows compiling with gcc in
windows( this is off topic but advices are always welcome).


Generally Cygwin is a bit complex to set up and use. Use MinGW instead.
It uses native Win32 ports of the GNU toolchain.

http://www.mingw.org/

Jun 16 '06 #3

P: n/a
"ash" <as************@rediffmail.com> writes:
i am writing this program (for exercise1-9 in k&r-2nd edition) which
removes extra spaces in string
example- "test string" will be "test string"

#include<stdio.h>
#include<string.h>
#include<conio.h>
<conio.h> is not a standard header. You don't use it anyway. Delete
the above line.

I find it clearer to leave a space between "include" and "<".
main()
int main(void)
{
char str[20],st[20];
int i=0,j=0;
printf("enter string");
Since this doesn't end in a newline, it's not guaranteed to appear.
Add "fflush(stdout);".

I'd add a blank, or perhaps ": ", at the end of the prompt; it looks
better. Without it, if I type "foo", I see "enter stringfoo" on the
screen.
gets(str);
Never use gets(). Never use gets(). Never use gets().

See question 12.23 in the comp.lang.c FAQ, <http://www.c-faq.com/>.
while(str[i]!=NULL)
NULL is a null pointer constant. You're trying to compare a character
value to a pointer value. It happens to work on your system for
obscure reasons I won't get into, but it's bad style at the very
least. The way to represent a null character is '\0'.
{
if(str[i]==' ')
{ st[j++]=st[i++];
I think you mean "st[j++]=st[i++];"

while(str[i]==' ') i++;

}
else
st[j++]=str[i++];
}
st[j]=NULL;
Again, use '\0', not NULL.
strcpy(str,st);
puts(str);
return 0;
}


And don't underestimate the importance of consistent formatting,
particularly indentation.

Apart from that, the program doesn't seem unreasonable.

--
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.
Jun 16 '06 #4

P: n/a
ash wrote:
i am writing this program (for exercise1-9 in k&r-2nd edition) which
removes extra spaces in string
example- "test string" will be "test string"
That's not the actual exercise:

Exercise 1-9. Write a program to copy its input to its output,
replacing each string of one or more blanks by a single blank.


#include<stdio.h>
#include<string.h>
#include<conio.h>
<conio.h> is not a standard header. You should not use it, as it's not
very portable.
main()
Use the following form:

int main(void)
{
char str[20],st[20];
These fixed buffers are likely a problem.
int i=0,j=0;
printf("enter string");
gets(str);
Never, ever use gets(). It's dangerous. What happens when someone
enters a string with 50 characters? Bad things.

while(str[i]!=NULL)
NULL is a null pointer constant. It might be 0, which would work, but
it could be (void*)0. Either use '\0' or 0 in checking for the null
terminator in a string.
{
if(str[i]==' ')
{ st[j++]=st[i++];

while(str[i]==' ') i++;

}
else
st[j++]=str[i++];
}
st[j]=NULL;
strcpy(str,st);
puts(str);
}

(compiled in turbo c++ for windows version 3.1)
i know there should be other ways to write this program (thats a bad
program ),can someone help me in writing that program in compact way
and give me some logic and tips.
i want to use gcc but i don`t have linux operating system and one
software which allows gcc compiling in windows (cygwin) is not
working. anyone can advice me such a program that allows compiling
with gcc in windows( this is off topic but advices are always
welcome).


Do you want the program that K&R assigned, or the one you tried? It can
be made much more simple by just immediately outputting characters
instead of copying to buffers.

/* algorithm portion */

int c;
int flag = 0;

while ((c = getchar()) != EOF)
{
if (c == ' ')
{
if (flag == 0)
{
putchar(c);
flag = 1;
}
}
else
{
if (flag == 1)
{
flag = 0;
}
putchar(c);
}
}

Brian
Jun 16 '06 #5

P: n/a
ash wrote:
.... snip ...
i want to use gcc but i don`t have linux operating system and one
software which allows gcc compiling in windows (cygwin) is not
working. anyone can advice me such a program that allows compiling
with gcc in windows( this is off topic but advices are always
welcome).


djgpp, at <http://www.delorie.com>. However cygwin should work.

--
"A man who is right every time is not likely to do very much."
-- Francis Crick, co-discover of DNA
"There is nothing more amazing than stupidity in action."
-- Thomas Matthews

Jun 16 '06 #6

P: n/a
Malcolm wrote:
"ash" <as************@rediffmail.com> wrote in message
news:11**********************@i40g2000cwc.googlegr oups.com...
i am writing this program (for exercise1-9 in k&r-2nd edition) which
removes extra spaces in string
example- "test string" will be "test string"

#include<stdio.h>
#include<string.h>
#include<conio.h>
main()
{
char str[20],st[20];
int i=0,j=0;
printf("enter string");
gets(str);

while(str[i]!=NULL)
{
if(str[i]==' ')
{ st[j++]=st[i++];

while(str[i]==' ') i++;

}
else
st[j++]=str[i++];
}
st[j]=NULL;
strcpy(str,st);
puts(str);
}

(compiled in turbo c++ for windows version 3.1)
i know there should be other ways to write this program (thats a bad
program ),can someone help me in writing that program in compact way
and give me some logic and tips.
i want to use gcc but i don`t have linux operating system and one
software which allows gcc compiling in windows (cygwin) is not working.
anyone can advice me such a program that allows compiling with gcc in
windows( this is off topic but advices are always welcome).

thankx

Separate out ewhat you are doing into a function.

In this case you want

/*
turns whitespace spans into single spaces
(and trims leading / trailing white space?)
*/
void onespace(char *out, char *in)

Decide if you want to allow out and in to be the same. This will make your
function
more convenient to use, but you might have to be a little bit more careful
in coding it.

Basically you maintain two pointer, a "write" pointer and a "read" pointer.
If you hit
a non-whitespace you write to the "write" pointer and increment both.
If you hit a whitespace character, you write a single space to the "write"
pointer. Then you increment the "read" pointer whilst it is still pointing
to white space.


I think you also need a little state machine: if you have not hit
a blank you are in character-accepting mode and write that char
to the buffer where you construct the compacted string. Otherwise
if the char is a blank you accept it but shift to a mode where you
no longer accept blank characters. When you hit a non-blank you
switch back to the first mode. In other words,

state\input -> non-blank blank
// --------------------------------------------------------
1 write to buff write to buff and
set state to 2

2 write to buff and drop char
set state to 1
// --------------------------------------------------------

A switch statement and a state variable will accomplish this.
--
Julian V. Noble
Professor Emeritus of Physics
University of Virginia
Jun 17 '06 #7

P: n/a
ash wrote:
can someone help me in writing that program in compact way
and give me some logic and tips.

I don't know whether my program is compact or not, anyway code below
it's my own. Suggestion welcomed.
/* Removes extra spaces in string pointed by src, the result string is
pointed by dst. Return value is the length os the result string or
0 for failure. example: "test string" will be "test string" */
int spacerm(char *dst, char *src)
{
int last_space = 0; /*1: last char is a space char; 0: not*/
int len = 0;
int ret = 1; /*for return value, 0: failure, non-zero: result
string length returned*/

if (src == 0 || dst == 0)
{
ret = 0;
}

if (ret != 0)
{
while (*src != '\0')
{
if (*src == ' ')
{
if (last_space != 1)
{
*dst++ = *src++;
len++;
}
else
{
src++;
}

last_space = 1;

}
else
{
*dst++ = *src++;
len++;
last_space = 0;
}
}

ret = len;
}

return ret;
}

#include <stdio.h>
#include <string.h>
int main(void)
{
char *s = "test string";
char a[20] = {'\0'};
int i = 0;

printf("%i, %s\n", strlen(s), s);
i = spacerm(a, s);
printf("%i, %s\n", i, a);

return 0;
}

$ gcc -W -Wall -pedantic -ansi test.c
$ ./a.out
14, test string
11, test string
$

i want to use gcc but i don`t have linux operating system and one
software which allows gcc compiling in windows (cygwin) is not working.
anyone can advice me such a program that allows compiling with gcc in
windows( this is off topic but advices are always welcome).

Use mingw or Install a Debian Linux on VMware hosted in Windows.

lovecreatesbeauty

Jun 17 '06 #8

P: n/a
lovecreatesbeauty wrote:

/* Removes extra spaces in string pointed by src, the result string is
pointed by dst. Return value is the length os the result string or
0 for failure. example: "test string" will be "test string" */
What if the original string is "". Is that an error? If so, why?
int spacerm(char *dst, char *src)
{
int last_space = 0; /*1: last char is a space char; 0: not*/
int len = 0;
int ret = 1; /*for return value, 0: failure, non-zero: result
string length returned*/
You effectively have two variables for the same thing. This
looks clumsy.
if (src == 0 || dst == 0)
Why bother? [Rehtorical]
{
ret = 0;
}

if (ret != 0)
{
while (*src != '\0')
{
if (*src == ' ')
{
if (last_space != 1)
if (last_space == 0)

Apart from being more efficient on many systems, it's
obvious what the test is. When you test explicitly against
a value like 1, the reader may pause to ponder whether
the variable can other values like 2 or 3 and why 1 is
significant.
{
*dst++ = *src++;
len++;
}
else
{
src++;
}

last_space = 1;

}
else
{
*dst++ = *src++;
len++;
last_space = 0;
}
}
You never write a terminating null byte to dst.
ret = len;
}

return ret;
}

#include <stdio.h>
#include <string.h>
int main(void)
{
char *s = "test string";
char a[20] = {'\0'};
Try...

char a[20] = "xxxxxxxxxxxWhat?";
int i = 0;

printf("%i, %s\n", strlen(s), s);
strlen() returns a size_t value; %i expects an int.

In C99 use %zu to print a size_t. In C90, cast the value
to suitable unsigned type and use %u with an appropriate
length modifier.
i = spacerm(a, s);
printf("%i, %s\n", i, a);

return 0;
}

$ gcc -W -Wall -pedantic -ansi test.c
Not a blip eg? Safe as houses then.

As some non-expert whose comments aren't worth the
em waves they're transmitted in once said "You control
the portability of your code, not gcc." <g>
$ ./a.out
14, test string
11, test string
$


--
Peter

Jun 17 '06 #9

P: n/a
ash posted:
i am writing this program (for exercise1-9 in k&r-2nd edition) which
removes extra spaces in string
example- "test string" will be "test string"

I'd probably approach it something like:

#include <cstddef>

void RetreatStrXPlaces(register char *p, std::size_t const places)
{
/* Consider coding this by copying int's
and checking if any byte is a space
character */

if ( !places ) return;

register char *q = p - places;

while ( *q++ = *p++ );
}

void FixMultipleSpaces( char * const p_start )
{
for(char *p = p_start; ; )
{
switch( *p++ )
{
case 0: return;

case ' ':
{
unsigned places = 0;

while( *p++ == ' ' ) ++places;

RetreatStrXPlaces(--p, places);
}
}
}
}

#include <iostream>
#include <cstdlib>

int main()
{
using std::cout;

char buffer[] = "The man walked over the revine";

FixMultipleSpaces(buffer);

cout << buffer << '\n';

std::system("PAUSE");
}

--

Frederick Gotham
Jun 17 '06 #10

P: n/a
Frederick Gotham posted:

#include <iostream>

Sorry wrong language.

--

Frederick Gotham
Jun 17 '06 #11

P: n/a
Frederick Gotham said:
ash posted:
i am writing this program (for exercise1-9 in k&r-2nd edition) which
removes extra spaces in string
example- "test string" will be "test string"

I'd probably approach it something like:

#include <cstddef>


No such header.

void RetreatStrXPlaces(register char *p, std::size_t const places)


Unknown identifier, std
Syntax error: "::"

Just the first three of many.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Jun 17 '06 #12

P: n/a
ash wrote:
i am writing this program (for exercise1-9 in k&r-2nd edition) which
removes extra spaces in string
example- "test string" will be "test string"
Sounds simple enough. The portable solution would be to encase this
functionality into a function so that you can easily utilize it among
other utilities, but for now I'll keep it simple.

#include<stdio.h>
#include<string.h>
#include<conio.h>
DOS nonsense. This is a non-standard header and looking at your code
below you use nothing in it. Get rid of it.
main()
main returns a value. _ALWAYS_.
{
char str[20],st[20];
int i=0,j=0;
printf("enter string");
The user might not ever see this. If you really want to suppress the
newline (which ensures that the data gets written to the screen) then
consider calling fflush(stdout) immediately after.
gets(str);
Don't use gets(). This function is dangerous. There is a replacement
that one of the regulars of this newsgroup posted a while ago that is a
much safer alternative. Personaly I would use fgets but anything that
accepts a width parameter would be marginally better.

while(str[i]!=NULL)
NULL is a pointer (in most cases it's 0 cast to a pointer to void, but
that's beside the point). While this may work on your system and perhaps
many other systems this is a recipe for UB (what happens if NULL is
defined to (void *)1?).
{
if(str[i]==' ')
{ st[j++]=st[i++];

while(str[i]==' ') i++;

}
else
st[j++]=str[i++];
Bad logic. This will not do what you expect it to do.
Your string "test string" will become "teststring".
}
st[j]=NULL;
Again, it's safer to use \0.
strcpy(str,st);
puts(str);
This is a waste of cpu cycles. Just print out st instead and save the
overhead of the unneeded function call.
}

(compiled in turbo c++ for windows version 3.1)
i know there should be other ways to write this program (thats a bad
program ),can someone help me in writing that program in compact way
and give me some logic and tips.
i want to use gcc but i don`t have linux operating system and one
software which allows gcc compiling in windows (cygwin) is not working.
anyone can advice me such a program that allows compiling with gcc in
windows( this is off topic but advices are always welcome).

thankx


Here is a modified version of your program that should perform better
than the one above. I've tested this however there is always room for
human error so be forewarned.

#include <stdio.h>
#include <string.h>

int main(void)
{
char str[20], st[20];
int i = 0, j = 0;
size_t len = 0;

printf("enter string: ");
fflush(stdout);

/* note that our string will also have
* a newline character at the end of it */
fgets(str, 20, stdin);
len = strlen(str);

/* comment this out if you want to retain the
* newline */
if (str[len - 1] == '\n')
{
str[len - 1] = '\0';
len--;
}

for (i = 0; i < len; i++)
{
/* if the next two characters are spaces then
* we need to condense them into one */
if (str[i] == ' ' && str[i + 1] == ' ')
{
st[j++] = ' '; /* we want to keep one space */
while (str[i] == ' ')
{
i++;
}
}

st[j++] = str[i];
}

st[j] = '\0';

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

return(0);
}
Jun 17 '06 #13

P: n/a
ash
thnankx joe estock, i really like your code.Its wonderful to see "many
logics to solve one question". can u suggest how to develope logics
faster?

Jun 17 '06 #14

P: n/a
ash wrote:
thnankx joe estock, i really like your code.Its wonderful to see "many
logics to solve one question". can u suggest how to develope logics
faster?

What code? Without context I have no idea what you are talking about. >
Please include enough of the previous post in your reply so that
everyone can follow the discussion. It's by chance that I checked this >
thread again today. For those of you who do not have access to the
previous thread I have included it's context below.
ash wrote:
i am writing this program (for exercise1-9 in k&r-2nd edition) which
removes extra spaces in string
example- "test string" will be "test string" Sounds simple enough. The portable solution would be to encase this
functionality into a function so that you can easily utilize it among
other utilities, but for now I'll keep it simple.
[snip code from OP]
{
if(str[i]==' ')
{ st[j++]=st[i++];

while(str[i]==' ') i++;

}
else
st[j++]=str[i++];

Bad logic. This will not do what you expect it to do.
Your string "test string" will become "teststring".
[snip some of my code]
for (i = 0; i < len; i++)
{
/* if the next two characters are spaces then
* we need to condense them into one */
if (str[i] == ' ' && str[i + 1] == ' ')
{
st[j++] = ' '; /* we want to keep one space */
while (str[i] == ' ')
{
i++;
}
}

st[j++] = str[i];
}


I do not fully understand your question "develop logics faster". As per
my original reply I was stating that the logic in your code was
incorrect. In this context logic means the "logical series of events and
results". You wanted to remove extra spaces (in essence you wanted to
condense multiple spaces into one single space). Your original code was
removing *all* spaces.

The only way I can think of to explain logic is by example. Consider the
following line:

10,20,30,40\n

Let's presume that this line is from a file that contains several other
lines like it. We want to read each line in this file and print the
information in a more human-readable format. The logic of our program
would be something like the following:

Open the file for reading.
Ensure open was successful.
Print the column header.
Read a line from the file.
While there are lines left in the file...
Separate the values by splitting the string on ",".
Print out the values.
Read another line from the file.
End while.
Close file.
Return status.
Jun 17 '06 #15

P: n/a
ash wrote:

thnankx joe estock, i really like your code.Its wonderful to see "many
logics to solve one question". can u suggest how to develope logics
faster?


Please don't use silly abbreviations like 'u'. Please do include
adequate context.

A blank suppression routine can be much simpler, if I correctly
recall the subject in the absence of context and the silly changing
of the subject line.

#include <stdio.h>
#define TAB 9 /* for Ascii only */

int main(void) {
int ch, inword;

inword = 0;
while (EOF != (ch = getchar()))
if ((' ' == ch) || (TAB == ch)) {
if (inword) putchar(' ');
inword = 0;
}
else {
putchar(ch);
inword = 1;
}
return 0;
} /* untested */

use via "progname <source [>dest]" on most systems.

--
"A man who is right every time is not likely to do very much."
-- Francis Crick, co-discover of DNA
"There is nothing more amazing than stupidity in action."
-- Thomas Matthews
Jun 17 '06 #16

P: n/a

Peter Nilsson wrote:
lovecreatesbeauty wrote:
What if the original string is "". Is that an error? If so, why?


The string literal "" just includes a delimiter of null terminator, its
string length is 0.
int spacerm(char *dst, char *src)
{ <snip> if (src == 0 || dst == 0)

Why bother? [Rehtorical]


If both src and dst are pointers have null values and caller pass these
null pointers into the function, then code inside the function like
this: *dst++ = *src++; will cause undefined behavior. Doing nothing is
better than causing an undefined behavior in my code, I feel. I still
want to listen to you. Thank you for providing comments on my code,
it's helpful to me.

(Joe Estock's code is better than mine, I think it should be an
expert's piece.)

lovecreatesbeauty

Jun 18 '06 #17

P: n/a
lovecreatesbeauty posted:

If both src and dst are pointers have null values and caller pass these
null pointers into the function, then code inside the function like
this: *dst++ = *src++; will cause undefined behavior.

You have to decide which part of your code is responsible for checking
for "errors". I myself thrive on writing efficient code (I find it
exciting and enjoyable), so if I were to write a function to convert a
decimal digit to an actual integer, I would write:

(I believe a character literal is of type "int" in C... is that right?)

unsigned DigitToInt( int const c )
{
return c - '0';
}
I certainly wouldn't write:

int DigitToInt( int const c )
{
if( c < '0' || c > '9' ) return -1;

return c - '0';
}

I would "delegate the responsibility" to the caller function to make sure
that everything is in order. Nonetheless, asserts are free, so the
finished product might be something like:

inline unsigned DigitToInt( int const c )
{
assert( c >= '0' && c <= '9' );
return c - '0';
}

When I'm writing functions which deal with strings, I never check for
null pointers -- I delegate that responsibility to the calling function.
--

Frederick Gotham
Jun 18 '06 #18

P: n/a
Frederick Gotham wrote:
If both src and dst are pointers have null values and caller pass these
null pointers into the function, then code inside the function like
this: *dst++ = *src++; will cause undefined behavior.

You have to decide which part of your code is responsible for checking
for "errors". I myself thrive on writing efficient code (I find it
exciting and enjoyable), so if I were to write a function to convert a
decimal digit to an actual integer, I would write:


What you call efficient I just call lazy.
(I believe a character literal is of type "int" in C... is that right?)

unsigned DigitToInt( int const c )
{
return c - '0';
}
I certainly wouldn't write:

int DigitToInt( int const c )
{
if( c < '0' || c > '9' ) return -1;

return c - '0';
}

I would "delegate the responsibility" to the caller function to make sure
that everything is in order. Nonetheless, asserts are free, so the
finished product might be something like:
And you'll never write robust code. Trust me, people will pass stupid
things to your functions.

Sure you can't catch all errors but simple checks for NULL or invalid
symbols is a smart thing to do. It also makes debugging simpler when
you trap errors.
inline unsigned DigitToInt( int const c )
{
assert( c >= '0' && c <= '9' );
return c - '0';
}
Not only is this not portable but in 2006 the use of "inline" is
redundant for functions like this. The compiler is smart enough to
figure it out.
When I'm writing functions which deal with strings, I never check for
null pointers -- I delegate that responsibility to the calling function.
Again, you also don't write robust code.
From my experience from my projects and the support email I get, most

people who can't get functions to work don't read the manual. A good
portion of the others are weak C programmers and don't understand
pointers and the like fully. A simple != NULL or other check may seem
to kill performance [hint: they don't] but are totally worth it.

Tom

Jun 18 '06 #19

P: n/a
Tom St Denis posted:
Frederick Gotham wrote:
> If both src and dst are pointers have null values and caller pass
> these null pointers into the function, then code inside the
> function like this: *dst++ = *src++; will cause undefined
> behavior.

You have to decide which part of your code is responsible for
checking for "errors". I myself thrive on writing efficient code (I
find it exciting and enjoyable), so if I were to write a function to
convert a decimal digit to an actual integer, I would write:


What you call efficient I just call lazy.

Think clearly. If I was really that lazy I wouldn't be on this newsgroup
writing code which provides me with no monetary gain.

I would "delegate the responsibility" to the caller function to make
sure that everything is in order. Nonetheless, asserts are free, so
the finished product might be something like:


And you'll never write robust code. Trust me, people will pass
stupid things to your functions.

Then "people" may expect undefined behaviour. I don't write functions to
be used by three year olds.
inline unsigned DigitToInt( int const c )
{
assert( c >= '0' && c <= '9' );
return c - '0';
}


Not only is this not portable but in 2006 the use of "inline" is
redundant for functions like this. The compiler is smart enough to
figure it out.

I'm not sure if the same applies for C, but in C++, the decimal digit
characters are guaranteed to be sequential and in ascending order.

Can someone please clarify if this holds true for C?

When I'm writing functions which deal with strings, I never check for
null pointers -- I delegate that responsibility to the calling
function.


Again, you also don't write robust code.

I do... but it's within the calling function:

#include<...

int main(void)
{
int c = 'r';

if ( isdigit(c) ) DigitToInt(c);
}
Or, wherever possible, I write my code so that it simply can't be
erroneous, for example:
int main(void)
{
int i = 54;

int j = i % 3;

FunctionThatWantsNumberBetweenZeroAndTwoInclusive( j );
}

From my experience from my projects and the support email I get, most
people who can't get functions to work don't read the manual. A good
portion of the others are weak C programmers and don't understand
pointers and the like fully. A simple != NULL or other check may seem
to kill performance [hint: they don't] but are totally worth it.

Yes, in the calling function:

if (p) DoSomething( p );

--

Frederick Gotham
Jun 18 '06 #20

P: n/a
On Sun, 18 Jun 2006 13:27:16 GMT, Frederick Gotham
<fg*******@SPAM.com> wrote:
You have to decide which part of your code is responsible for checking
for "errors". I myself thrive on writing efficient code (I find it
exciting and enjoyable), so if I were to write a function to convert a
decimal digit to an actual integer, I would write:
snipI would "delegate the responsibility" to the caller function to make sure
that everything is in order. Nonetheless, asserts are free, so the
finished product might be something like:

inline unsigned DigitToInt( int const c )
{
assert( c >= '0' && c <= '9' );
return c - '0';
}

So my program incorporates your function and at some point calls it
with a bad value. Instead of letting me decide how to handle the
error, you have decided that the only possible course of action is to
abort the program.

No thank you. I choose to not give you that much authority over my
code.
When I'm writing functions which deal with strings, I never check for
null pointers -- I delegate that responsibility to the calling function.

Remove del for email
Jun 18 '06 #21

P: n/a
Barry Schwarz posted:

So my program incorporates your function and at some point calls it
with a bad value.

I will express to you in plain English that calling the function with a
"bad value" will result in Undefined Behaviour, just like the following
will result in undefined behaviour:

#include <stdlib.h>

int main(void)
{
int i;

free (&i);
}

Instead of letting me decide how to handle the
error, you have decided that the only possible course of action is to
abort the program.

No, I have written an assert to facilitate the debugging process.

--

Frederick Gotham
Jun 18 '06 #22

P: n/a
Frederick Gotham wrote:
Tom St Denis posted:
Frederick Gotham wrote:

.... snip ...
inline unsigned DigitToInt( int const c )
{
assert( c >= '0' && c <= '9' );
return c - '0';
}


Not only is this not portable but in 2006 the use of "inline" is
redundant for functions like this. The compiler is smart enough
to figure it out.


I'm not sure if the same applies for C, but in C++, the decimal
digit characters are guaranteed to be sequential and in ascending
order.

Can someone please clarify if this holds true for C?


It is, as it is also for Pascal. Your function is easily handled
by a simpler operation:

unsigned dig, value, ch;
....
if ((dig = (ch - '0')) > 9) notadigit();
else {
/* use the conversion */
}

Note that this requires unsigned values. Another use might be:

value = 0;
if (isdigit(ch))
while ((value = (ch - '0')) <= 9) {
number = 10 * number + value;
ch = getchar();
}
/* ch holds char that terminated numerical field */

These sort of things are useful for interactive operation.

--
"A man who is right every time is not likely to do very much."
-- Francis Crick, co-discover of DNA
"There is nothing more amazing than stupidity in action."
-- Thomas Matthews
Jun 18 '06 #23

P: n/a
Frederick Gotham <fg*******@SPAM.com> writes:
Tom St Denis posted:
Frederick Gotham wrote: [snip]
inline unsigned DigitToInt( int const c )
{
assert( c >= '0' && c <= '9' );
return c - '0';
}


Not only is this not portable but in 2006 the use of "inline" is
redundant for functions like this. The compiler is smart enough to
figure it out.

I'm not sure if the same applies for C, but in C++, the decimal digit
characters are guaranteed to be sequential and in ascending order.

Can someone please clarify if this holds true for C?


Yes, it's true for C. I think Tom was referring to the "inline"
keyword, which is standard in C99 but not in C90.

--
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.
Jun 18 '06 #24

P: n/a

Tom St Denis wrote:
<snip>
What you call efficient I just call lazy.

And you'll never write robust code. Trust me, people will pass stupid
things to your functions.

Sure you can't catch all errors but simple checks for NULL or invalid
symbols is a smart thing to do. It also makes debugging simpler when
you trap errors.

people who can't get functions to work don't read the manual. A good
portion of the others are weak C programmers and don't understand
pointers and the like fully. A simple != NULL or other check may seem
to kill performance [hint: they don't] but are totally worth it.


Thanks. I admire your knowledge and attitude on coding C programs. I
think if programmers are lazy in composing functions, programmers will
be lazier in calling functions.

lovecreatesbeauty

Jun 19 '06 #25

P: n/a
lovecreatesbeauty wrote:
Peter Nilsson wrote:
lovecreatesbeauty wrote:
What if the original string is "". Is that an error? If so, why?
The string literal "" just includes a delimiter of null terminator, its
string length is 0.


Let's put the context back in. You originally wrote...
/* Removes extra spaces in string pointed by src, the result string is
pointed by dst. Return value is the length os the result string or
0 for failure. example: "test string" will be "test string" */
You've said that 0 is failure. So, your function 'fails' for an empty
string.

Do you really want the caller to have to check the original string to
differentiate a null pointer failure from an empty string?
int spacerm(char *dst, char *src)
{ <snip> if (src == 0 || dst == 0)

Why bother? [Rehtorical] [er... Rhetorical]


If both src and dst are pointers have null values and caller pass these
null pointers into the function, then code inside the function like
this: *dst++ = *src++; will cause undefined behavior. Doing nothing is
better than causing an undefined behavior in my code, I feel.


Even if the pointers are not null, they can still be invalid, so you
still have the
potential to invoke undefined behaviour. There is _no_ portable test
for
valid input in that case!

As the subsequent thread shows, its a debatable issue, but I'd prefer
to use assert() if I had to use anything. At least that can be removed
from the final release.
...
(Joe Estock's code is better than mine, I think it should be an
expert's piece.)


The code that I can see from Joe potentially terminates the string with
a double null byte.

I think most people overcomplicate things. If you just want to
replace two or more spaces with one space, then the following
would do me...

void foo(char *d, const char *s)
{
while (*s)
if ((*d++ = *s++) == ' ')
while (*s == ' ')
s++;
*d = 0;
}

--
Peter

Jun 19 '06 #26

P: n/a
Peter Nilsson wrote:
I think most people overcomplicate things. If you just want to
replace two or more spaces with one space, then the following
would do me...

void foo(char *d, const char *s)
{
while (*s)
if ((*d++ = *s++) == ' ')
while (*s == ' ')
s++;
*d = 0;
}


Thank you the great code you shared! I'm pursuing clear logic, compact
and efficient code like yours. Please be lenience and be my mentor not
just nagging.

lovecreatesbeauty

Jun 19 '06 #27

P: n/a
Frederick Gotham wrote:
What you call efficient I just call lazy.
Think clearly. If I was really that lazy I wouldn't be on this newsgroup
writing code which provides me with no monetary gain.


I don't pretend to know your motives for posting. I'm just speaking
from experience as a designer and implementor.
And you'll never write robust code. Trust me, people will pass
stupid things to your functions.


Then "people" may expect undefined behaviour. I don't write functions to
be used by three year olds.


Yeah, we'd all want smart users of our code. We don't always get that.
And if we dismissed them as stupid you'd find that there are few
people using it. Even something as trivial as say zlib. Still gets
people asking "how do I make a gzip file" questions.

Not only that, but bugs do occur, robust code helps not only curb bugs
by not proceeding on errant paths but detect and report them to the
developer.

I always check the return of mallocs but I've still managed to slip an
unitialized pointer [well I calloc structures] to a function from time
to time. A simple check for NULL picks that up and I'm off to the
races.
Not only is this not portable but in 2006 the use of "inline" is
redundant for functions like this. The compiler is smart enough to
figure it out.

I'm not sure if the same applies for C, but in C++, the decimal digit
characters are guaranteed to be sequential and in ascending order.

Can someone please clarify if this holds true for C?


Maybe that's true. I'd use a table anyways. in my ASN.1 IA5 and
Printable routines I have a table of chars and ints. That way
regardless of the mapping I can move from one to another easily and
portably.

Also the use of "inline" for that function is redundant. Smart
compilers will do it anyways and it isn't portable across all compilers
[yes, supporting non-standard compilers like MSVC and borland are often
desired features.]. Except for things like inlined ASM functions the
"inline" keyword is not terribly useful.
Or, wherever possible, I write my code so that it simply can't be
erroneous, for example:
int main(void)
{
int i = 54;

int j = i % 3;

FunctionThatWantsNumberBetweenZeroAndTwoInclusive( j );
}


I'm not saying all your functions have to be param checking. Just the
user exposed ones. Though as your code base increases in complexity
the checking becomes relevant again.
From my experience from my projects and the support email I get, most
people who can't get functions to work don't read the manual. A good
portion of the others are weak C programmers and don't understand
pointers and the like fully. A simple != NULL or other check may seem
to kill performance [hint: they don't] but are totally worth it.


Yes, in the calling function:


Calling function would be part of the users code. I thought I made it
clear there are a lot of weak developers?

Idealism is cool and all, that is, afterall, why I distribute my
projects [http://libtomcrypt.com]. But if you want people to use your
code you have to deal with really shotty programmers.

Tom

Jun 19 '06 #28

P: n/a
Tom St Denis said:

<snip>
Not only that, but bugs do occur, robust code helps not only curb bugs
by not proceeding on errant paths but detect and report them to the
developer.

I always check the return of mallocs but I've still managed to slip an
unitialized pointer [well I calloc structures] to a function from time
to time. A simple check for NULL picks that up


No, it doesn't. If the pointer is uninitialised, its value is indeterminate.
Even if it is all-bits-zero (perhaps because it's part of a structure whose
storage was allocated via calloc), that is no guarantee that its value is
NULL.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Jun 19 '06 #29

P: n/a

Richard Heathfield wrote:
Tom St Denis said:

<snip>
Not only that, but bugs do occur, robust code helps not only curb bugs
by not proceeding on errant paths but detect and report them to the
developer.

I always check the return of mallocs but I've still managed to slip an
unitialized pointer [well I calloc structures] to a function from time
to time. A simple check for NULL picks that up


No, it doesn't. If the pointer is uninitialised, its value is indeterminate.
Even if it is all-bits-zero (perhaps because it's part of a structure whose
storage was allocated via calloc), that is no guarantee that its value is
NULL.


Thank you mr. pedantic. Except that on my platforms at least NULL is
all zero.

I don't check for NULL in case you calloc'ed a structure. I check for
NULL in case you pass the return of a heap operation without checking.
If malloc or calloc fails it will be NULL.

The fact that on basically every platform 0 == NULL is just an added
bonus.

Tom

Jun 19 '06 #30

P: n/a
"Tom St Denis" <to********@gmail.com> wrote:
Richard Heathfield wrote:
Tom St Denis said:
Not only that, but bugs do occur, robust code helps not only curb bugs
by not proceeding on errant paths but detect and report them to the
developer.

I always check the return of mallocs but I've still managed to slip an
unitialized pointer [well I calloc structures] to a function from time
to time. A simple check for NULL picks that up
No, it doesn't. If the pointer is uninitialised, its value is indeterminate.
Even if it is all-bits-zero (perhaps because it's part of a structure whose
storage was allocated via calloc), that is no guarantee that its value is
NULL.


Thank you mr. pedantic. Except that on my platforms at least NULL is
all zero.


For the time being.
I don't check for NULL in case you calloc'ed a structure. I check for
NULL in case you pass the return of a heap operation without checking.
In some cases, this is a wise precaution; on others, it is superfluous
inefficiency.
Truly uninitialised (or badly arithmeticked) pointers, however, are
allowed to be neither all-bits-zero, nor null. They are allowed to be
trap values, causing your comparison to crash with a segfault or
something similar; they are also allowed to accidentally be equal to a
valid address, causing the comparison to overlook the error and the rest
of the code to write to a completely unrelated area of memory; or
whatever other option the system can think of to embarrass you in front
of your supervisor. Checking for null pointers may catch _some_ of your
errors, but it does not help in the general case.
The fact that on basically every platform 0 == NULL is just an added
bonus.


On _all_ platforms, 0 == NULL. But not on all platforms, a null pointer
is all bits zero. And on some platforms, pointers are larger or smaller
than your prefered integer type; beware printf() errors.

Richard
Jun 19 '06 #31

P: n/a
Tom St Denis said:

Richard Heathfield wrote:
Tom St Denis said:

<snip>
> Not only that, but bugs do occur, robust code helps not only curb bugs
> by not proceeding on errant paths but detect and report them to the
> developer.
>
> I always check the return of mallocs but I've still managed to slip an
> unitialized pointer [well I calloc structures] to a function from time
> to time. A simple check for NULL picks that up
No, it doesn't. If the pointer is uninitialised, its value is
indeterminate. Even if it is all-bits-zero (perhaps because it's part of
a structure whose storage was allocated via calloc), that is no guarantee
that its value is NULL.


Thank you mr. pedantic.


Firstly, that isn't my name. Secondly, even if it were, it would require
upper case 'M' and 'P'. Thirdly, please understand that pedantry is a sine
qua non of good programming practice. If you don't like being corrected in
public, don't make mistakes in public. If you don't like my tone, try
softening your own tone towards newbies, and I'll gladly soften my tone
towards you.

Except that on my platforms at least NULL is all zero.
Great - all the world's a Tom St Denis platform, and everything in the
garden is rosy... until it isn't.
I don't check for NULL in case you calloc'ed a structure.
You misunderstood. I was making the point that you claimed that checking for
NULL made it possible to "pick up" uninitialised pointers, which is utter
nonsense.
I check for
NULL in case you pass the return of a heap operation without checking.
That's not what you said earlier. You said you used it to pick up on
uninitialised pointers.
If malloc or calloc fails it will be NULL.
Indeed.
The fact that on basically every platform 0 == NULL is just an added
bonus.


On /all/ platforms, 0 and NULL will compare equal, but that doesn't mean
all-bits-zero means NULL.

if(0 == NULL)
{
puts("I will always be printed.");
}
memcpy(&p, 0, sizeof p);
if(p == NULL)
{
puts("I will probably be printed, but I might not.");
puts("Are you feeling lucky?");
}
--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Jun 19 '06 #32

P: n/a
Richard Bos posted:

Truly uninitialised (or badly arithmeticked) pointers, however, are
allowed to be neither all-bits-zero, nor null.

Where are you getting that from?

You have no guarantee whatsoever that the following code won't print all
zeros:
#include <stdlib.h>

int main(void)
{

unsigned counter = 0;

do {
int *guinea_pig_pointer;
const unsigned char *p = (const unsigned char*)
&guinea_pig_pointer;
const unsigned char * const p_over =
(const unsigned char*)(&guinea_pig_pointer + 1);
do
{

printf( "%u", (unsigned)*p++ );

} while ( p != p_over );
printf( "\n" );

} while ( ++counter != 5 );
system("PAUSE");
}
--

Frederick Gotham
Jun 19 '06 #33

P: n/a
Frederick Gotham <fg*******@SPAM.com> wrote:
Richard Bos posted:
Truly uninitialised (or badly arithmeticked) pointers, however, are
allowed to be neither all-bits-zero, nor null.
Where are you getting that from?


The Standard. Uninitialised is uninitialised is not guaranteed any value
_or_ non-value.
You have no guarantee whatsoever that the following code won't print all
zeros:


That's what I wrote. Allowed - not required - to be neither. I didn't
write "not allowed to be either".

Richard
Jun 19 '06 #34

P: n/a
Richard Heathfield wrote:
Except that on my platforms at least NULL is all zero.


Great - all the world's a Tom St Denis platform, and everything in the
garden is rosy... until it isn't.


I'd actually like you to point out the market share of platforms where

(void*)0

Isn't for all intents and purposes equal to NULL. And more
importantly,

memset(&mypointer, 0, sizeof(void*))

Doesn't produce NULL in mypointer. I know it's not STANDARD. It's
just REALLY REALLY REALLY common. It isn't the reason I check for NULL
though.
I don't check for NULL in case you calloc'ed a structure.


You misunderstood. I was making the point that you claimed that checking for
NULL made it possible to "pick up" uninitialised pointers, which is utter
nonsense.


When you calloc a structure with pointers, they're VERY LIKELY to be
equal to NULL. this is the "added bonus" I was talking about. As in,
in addition to the original purpose of the check.
I check for
NULL in case you pass the return of a heap operation without checking.


That's not what you said earlier. You said you used it to pick up on
uninitialised pointers.


I said "I've still managed to slip an unitialized pointer [well I
calloc structures]".

I never said it was standard, I just said it was good practice. Again,
because on essentially every platform out there all-zero == NULL.
The fact that on basically every platform 0 == NULL is just an added
bonus.


On /all/ platforms, 0 and NULL will compare equal, but that doesn't mean
all-bits-zero means NULL.

if(0 == NULL)
{
puts("I will always be printed.");
}
memcpy(&p, 0, sizeof p);
if(p == NULL)
{
puts("I will probably be printed, but I might not.");
puts("Are you feeling lucky?");
}


Find me platforms today where that isn't true.

On the one hand you can do a NULL check and trap errors on 99.999% of
platforms in the market. On the other hand you can ignore the check as
frivolous and possibly have unitialized pointers.

I'd recommend to anyone who callocs structures to do a NULL check in
functions. Not because it's standard compliant but just a good
practice and even on not-all-zero NULL platforms the code will still
work [just fail to detect NULL].

Tom

Jun 19 '06 #35

P: n/a
On 2006-06-19, Tom St Denis <to********@gmail.com> wrote:

I'd recommend to anyone who callocs structures to do a NULL check in
functions. Not because it's standard compliant but just a good
practice and even on not-all-zero NULL platforms the code will still
work [just fail to detect NULL].


Why not make a create_null_structure function to replace calloc for your
purposes? In that function you could also set ints to -1 and then you
could see if a function failed to change other data.

m = create_null_structure(1);

function_on_m (m);

if (m.integer == -1 || m.pointer == NULL)
return FUNCTION_FALIED;

Can't do that with calloc.

--
Andrew Poelstra < http://www.wpsoftware.net/blog >
To email me, use "apoelstra" at the above address.
I know that area of town like the back of my head.
Jun 19 '06 #36

P: n/a
Andrew Poelstra wrote:
On 2006-06-19, Tom St Denis <to********@gmail.com> wrote:

I'd recommend to anyone who callocs structures to do a NULL check in
functions. Not because it's standard compliant but just a good
practice and even on not-all-zero NULL platforms the code will still
work [just fail to detect NULL].


Why not make a create_null_structure function to replace calloc for your
purposes? In that function you could also set ints to -1 and then you
could see if a function failed to change other data.


Not a bad idea. Almost constructive even. Thanks!

:-)

Might use that actually.

Look, I wasn't saying it was portable, I just was trying to say that
checking for NULL is a good idea and that on many platforms all-zero ==
NULL is a bonus. You guys read too much into what people say. I'd
gladly trade security for essentially 100% of all applications you'll
touch in your lifetime for a minor portability glitch.

Tom

Jun 19 '06 #37

P: n/a
Andrew Poelstra said:
On 2006-06-19, Tom St Denis <to********@gmail.com> wrote:

I'd recommend to anyone who callocs structures to do a NULL check in
functions. Not because it's standard compliant but just a good
practice and even on not-all-zero NULL platforms the code will still
work [just fail to detect NULL].


Why not make a create_null_structure function to replace calloc for your
purposes?


Because the behaviour of the calloc function is only guaranteed to produce 0
values for integer types, it's not as useful as it might be, so the idea of
replacing calloc is a good one.

The following technique has served me well when creating aggregate objects
of type T:

#include <stdlib.h>
#include "t.h"

T *T_create(int this, double that, long theother)
{
const T blank = {0};

T *new = malloc(sizeof *new);
if(new != NULL)
{
*new = blank; /* get default static initialisers in place */
new->this = this;
new->that = that;
new->theother = theother; /* override specific fields */

/* all other fields in 'new' have their default values */
}
return new;
}

This way guarantees that *either* the allocation fails (in which case 'new'
is NULL) *or* it succeeds and no member object of 'new' will be
uninitialised.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Jun 19 '06 #38

P: n/a
In article <11**********************@i40g2000cwc.googlegroups .com>,
Tom St Denis <to********@gmail.com> wrote:
....
Look, I wasn't saying it was portable, I just was trying to say that
checking for NULL is a good idea and that on many platforms all-zero ==
NULL is a bonus. You guys read too much into what people say. I'd
gladly trade security for essentially 100% of all applications you'll
touch in your lifetime for a minor portability glitch.


This is an argument you can't possibly win here. It's too sensible.

See, the problem is, you've positioned yourself as a reasonable person,
interested in theory, but practical as well. And, presumably, *not*
suffering from Asperger's.

http://en.wikipedia.org/wiki/Aspergers

See, the basic structure of this ng allows for two classes: "newbies"
(aka, cannon fodder) and "regulars". You (and I) fit into neither
category. I have recently coined the term "observers" for us.

Jun 19 '06 #39

P: n/a
Kenny McCormack said:
In article <11**********************@i40g2000cwc.googlegroups .com>,
Tom St Denis <to********@gmail.com> wrote:
...
Look, I wasn't saying it was portable, I just was trying to say that
checking for NULL is a good idea and that on many platforms all-zero ==
NULL is a bonus. You guys read too much into what people say. I'd
gladly trade security for essentially 100% of all applications you'll
touch in your lifetime for a minor portability glitch.
This is an argument you can't possibly win here. It's too sensible.

See, the problem is, you've positioned yourself as a reasonable person,
interested in theory, but practical as well. And, presumably, *not*
suffering from Asperger's.

http://en.wikipedia.org/wiki/Aspergers


It is evident that you are not qualified to diagnose Asperger's Disorder,
because if you were, you would not trivialise it in this way. It is
disquieting that "Asperger's" is becoming a term of abuse aimed at people
who care about correctness, especially so since it can only serve to debase
the term, making it more difficult for physicians to use it dispassionately
to describe those who actually do suffer from it. I am no physician, of
course, but I do know someone - a young child - who really does suffer from
Asperger's Disorder, and I can assure you that it is not a subject for
humour. To use the term as an insult is beneath contempt.
See, the basic structure of this ng allows for two classes: "newbies"
(aka, cannon fodder) and "regulars". You (and I) fit into neither
category. I have recently coined the term "observers" for us.


There are people here who seek high quality help in C programming. There are
people here who provide high quality help in C programming. And then there
are those who, like you, provide nothing but criticism of those who help.
These last are a constant drain on clc's resources, and the group would be
far better off without them.

Instead of continually making a fool of yourself, why not roll your sleeves
up and pitch in to the task of helping people out with high quality C
advice? Or is that too difficult for you?

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Jun 19 '06 #40

P: n/a
Tom St Denis wrote:
.... snip ...
The fact that on basically every platform 0 == NULL is just an
added bonus.


Making that assumption, in any case where it may matter, is
extremely sloppy programming.

--
"A man who is right every time is not likely to do very much."
-- Francis Crick, co-discover of DNA
"There is nothing more amazing than stupidity in action."
-- Thomas Matthews
Jun 19 '06 #41

P: n/a
CBFalconer said:
Tom St Denis wrote:

... snip ...

The fact that on basically every platform 0 == NULL is just an
added bonus.


Making that assumption, in any case where it may matter, is
extremely sloppy programming.


if(0 == NULL)
{
puts("No, it's guaranteed that 0 == NULL.");
puts("This stuff will always be written to stdout.");
}

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Jun 19 '06 #42

P: n/a
In article <44***************@yahoo.com>,
CBFalconer <cb********@maineline.net> wrote:
Tom St Denis wrote:

... snip ...

The fact that on basically every platform 0 == NULL is just an
added bonus.


Making that assumption, in any case where it may matter, is
extremely sloppy programming.


I don't see where you get "extremely" out of this. There is a quote,
attributed to Mark Twain, that goes like this:

Every place where you use the word "very", you should substitute "damn".
Your editor will remove them all, and your writing will be better for it.

I think that goes for most of the silly superlatives used in this ng.

Also, as noted elsethread, there is a difference between asserting that
when we write:

0 == NULL

in a conforming C program, we might as well write:

1

(or whatever other representation of "true" you are comfortable with),
that's not the same as asserting that NULL is all bits zero.

(For whatever that's worth...)

Jun 19 '06 #43

P: n/a

Richard Heathfield wrote:
CBFalconer said:
Tom St Denis wrote:

... snip ...

The fact that on basically every platform 0 == NULL is just an
added bonus.


Making that assumption, in any case where it may matter, is
extremely sloppy programming.


if(0 == NULL)
{
puts("No, it's guaranteed that 0 == NULL.");
puts("This stuff will always be written to stdout.");
}


Assuming he meant "all-zero == NULL" he's wrong anyways. It won't
raise a bug on platforms where NULL != all-zero, since NULL can never
be a valid pointer anyways.

So while it's true on some imaginary [or just plain old and non viable]
platforms NULL is not "all-zero", it is on many and it DOES in fact
result in bugs being caught. So it's at worst "redundant" and at best
a time saver.

In terms of correctness the poster who suggested initializing all
pointers to NULL was correct. Ideally that's the proper way to code.

Irrespective of HOW you make the allocated data [calloc or proper init]
you should still NULL check pointers.

Tom

Jun 19 '06 #44

P: n/a
Richard Bos posted:
Frederick Gotham <fg*******@SPAM.com> wrote:
Richard Bos posted:
> Truly uninitialised (or badly arithmeticked) pointers, however, are
> allowed to be neither all-bits-zero, nor null.


Where are you getting that from?


The Standard. Uninitialised is uninitialised is not guaranteed any
value _or_ non-value.
You have no guarantee whatsoever that the following code won't print
all zeros:


That's what I wrote. Allowed - not required - to be neither. I didn't
write "not allowed to be either".

Sorry, that's the second time today I muddled up the English language...
I made a similar mistake on comp.lang.c++ within the last hour. Consider
when someone asks:

Would you like tea or coffee?

Sometimes you expect a response of "yes" or "no", and other times you
expect "tea" or "coffee".

--

Frederick Gotham
Jun 19 '06 #45

P: n/a
Frederick Gotham wrote:
[...]
Sorry, that's the second time today I muddled up the English language...
I made a similar mistake on comp.lang.c++ within the last hour. Consider
when someone asks:

Would you like tea or coffee?

Sometimes you expect a response of "yes" or "no", and other times you
expect "tea" or "coffee".


"Excuse me... Do you know what time it is?"

And, if you ask a computer for a list of clients in New York and
California, you'll probably get a very small (if not empty) set.

--
+-------------------------+--------------------+-----------------------+
| Kenneth J. Brody | www.hvcomputer.com | #include |
| kenbrody/at\spamcop.net | www.fptech.com | <std_disclaimer.h> |
+-------------------------+--------------------+-----------------------+
Don't e-mail me at: <mailto:Th*************@gmail.com>
Jun 19 '06 #46

P: n/a
"Tom St Denis" <to********@gmail.com> writes:
Richard Heathfield wrote:
> Except that on my platforms at least NULL is all zero.
Great - all the world's a Tom St Denis platform, and everything in the
garden is rosy... until it isn't.


I'd actually like you to point out the market share of platforms where

(void*)0

Isn't for all intents and purposes equal to NULL.


There are none, since (void*)0 is by definition a null pointer
constant. It's guaranteed by the language to yield a null pointer of
type void*, regardless of how a null pointer happens to be
represented.
And more importantly,

memset(&mypointer, 0, sizeof(void*))

Doesn't produce NULL in mypointer. I know it's not STANDARD. It's
just REALLY REALLY REALLY common.
I agree that it's really really really common for null pointers to be
represented as all-bits-zero. There's nothing wrong with code that
happens to take advantage of this (more on that point below), as long
as it doesn't depend on the assumption.

Code that *assumes* that a null pointer is all-bits-zero will probably
happen to work on most existing platforms (if it doesn't also assume,
as such code often does, that all pointers are the same size, or that
pointers are the same size as int) -- but it's still incorrect, and it
will fail if executed on a rare platform where null pointers aren't
all-bits-zero.

Properly written code that *doesn't* assume that a null pointer is
all-bits-zero (or that all pointers are the same size, or that
pointers are the same size as int) will work correctly regardless of
the representation of a null pointer. In particular, it will continue
to work correctly years from now when somebody recompiles it on some
future exotic platform that uses all-bits-one to represent null
pointers. And since it's just as easy to write code that doesn't make
this assumption as to write code that does, there's really no excuse
for writing non-portable code in the first place -- even if it happens
to work on the limited set of platforms you happen to use.
It isn't the reason I check for NULL though.
Good.

[...]
When you calloc a structure with pointers, they're VERY LIKELY to be
equal to NULL. this is the "added bonus" I was talking about. As in,
in addition to the original purpose of the check.


When you calloc a structure with pointer, it's VERY LIKELY that the
author assumed that null pointers are always represented as
all-bits-zero. The author is likely to have made other incorrect
assumptions as well.

It's simple, really: Don't calloc structures with pointers. (Or at
least don't calloc structures with pointers and assume that the
resulting pointers will be null.)

Checking a pointer parameter against NULL (assuming NULL is an invalid
value) is a good idea, assuming you have a decent way to handle the
error. If uninitialized variables happen to be all-bits-zero more
often than not, and if null pointers happen to be all-bits-zero on the
current platform, then this will catch *some* cases of uninitialized
pointers in addition to catching pointers that are being misused after
having been initialized to NULL. I'll grant you that this is a small
bonus (but a very unreliable one).

It's perfectly true that null pointers are all-bits-zero on most
(nearly all?) current platforms. The problem is, too many people use
that fact as a basis for arguing that it's ok for code to *assume*
that null pointers are all-bits-zero. I don't *think* that's what
you're arguing, but someone who reads your articles with insufficient
care might draw that conclusion.

--
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.
Jun 19 '06 #47

P: n/a
Tom St Denis wrote:
Richard Heathfield wrote:

Great - all the world's a Tom St Denis platform, and everything
in the garden is rosy... until it isn't.


I'd actually like you to point out the market share of platforms
where (void*)0 Isn't for all intents and purposes equal to NULL.


It is, by definition in the standard. However a pointer object
with all bits 0 is not necessarily a NULL, as Richard has tried to
explain.

--
"The French have no word for entrepreneur." -- George W. Bush
Jun 19 '06 #48

P: n/a
Richard Heathfield wrote:
CBFalconer said:
Tom St Denis wrote:

... snip ...

The fact that on basically every platform 0 == NULL is just an
added bonus.


Making that assumption, in any case where it may matter, is
extremely sloppy programming.


if (0 == NULL)
{
puts("No, it's guaranteed that 0 == NULL.");
puts("This stuff will always be written to stdout.");
}


Yes, I was sloppy. That is a zero constant in a pointer context.

--
"The French have no word for entrepreneur." -- George W. Bush
Jun 19 '06 #49

P: n/a
Tom St Denis wrote:
.... snip ...
In terms of correctness the poster who suggested initializing all
pointers to NULL was correct. Ideally that's the proper way to code.

Irrespective of HOW you make the allocated data [calloc or proper
init] you should still NULL check pointers.


You still don't seem to have grasped the point that callocing
something including pointers does not make those pointers NULL.

--
"The French have no word for entrepreneur." -- George W. Bush
Jun 19 '06 #50

54 Replies

This discussion thread is closed

Replies have been disabled for this discussion.