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

[C] simple string question

P: n/a
hi all,

I want to define a constant length string, say 4
then in a function at some time, I want to set the string to a constant
value, say a
below is my code but it fails
what is the correct code?
many thx!
char string[4] = {0};

string = 'a '; /* <-- failed */
Nov 14 '05 #1
Share this Question
Share on Google+
51 Replies


P: n/a
Alan wrote:
hi all,

I want to define a constant length string, say 4
then in a function at some time, I want to set the string to a
constant value, say a
below is my code but it fails
what is the correct code?
many thx!
char string[4] = {0};

string = 'a '; /* <-- failed */


memcpy("abcd", string, sizeof(string));

- Pete
Nov 14 '05 #2

P: n/a

"AirPete" wrote:
Alan wrote:
hi all,

I want to define a constant length string, say 4
then in a function at some time, I want to set the string to a
constant value, say a
below is my code but it fails
what is the correct code?
many thx!
char string[4] = {0};

string = 'a '; /* <-- failed */
memcpy("abcd", string, sizeof(string));


sorry, but it doesn't work
when I run the program, the program crashes

- Pete

Nov 14 '05 #3

P: n/a
On Thu, 05 Feb 2004 03:15:29 GMT, "AirPete" <x@x.x> wrote:
Alan wrote:
hi all,

I want to define a constant length string, say 4
then in a function at some time, I want to set the string to a
constant value, say a
below is my code but it fails
what is the correct code?
many thx!
char string[4] = {0};

string = 'a '; /* <-- failed */


memcpy("abcd", string, sizeof(string));

- Pete


memcpy seems overkill for this, plus the usage is:
memcpy(destination, source, no_of_bytes);
On top of that, the memcpy call above would use up every existing
position in the char array, leaving no terminating NUL, which could
definitely lead to serious nastiness.

To initialize the string, an equivalent but in IMO clearer way to do
it would be:
char string[4] = ""; // still all nulled out

The point is to self-document the intention; you're representing an
empty "string" as opposed to "a bunch of numeric bytes". If you really
want to underscore the fact that the first byte is a "NUL" (the
character variety), you can instead say:
char string[4] = {'\0'}; // but please don't.

To change the value of the string, plain old strcpy works:

strcpy(string, "a");

If you're concerned about possibly overwriting the four available
bytes of the array (it wouldn't happen with the call above, but might
if you don't know for sure what the length of the string you're
copying from is), consider strncpy:

strncpy(string, some_source_ptr, 4);

However, this _still_ has the potential of leaving string without a
terminating null. You just have to be careful.

BTW, the 4's sprinkled throughout the code are bad style. In C, use a
#define to set that length up at the top somewhere...

Good luck,
-leor

Leor Zolman
BD Software
le**@bdsoft.com
www.bdsoft.com -- On-Site Training in C/C++, Java, Perl & Unix
C++ users: Download BD Software's free STL Error Message
Decryptor at www.bdsoft.com/tools/stlfilt.html
Nov 14 '05 #4

P: n/a
On Thu, 5 Feb 2004 10:44:58 +0800, Alan <al*************@sinatown.com>
wrote:
hi all,

I want to define a constant length string, say 4
then in a function at some time, I want to set the string to a constant
value, say a
below is my code but it fails
what is the correct code?
many thx!
char string[4] = {0};

string = 'a '; /* <-- failed */


First off, double-quotes are used for string literals. Second off, you
can't assign to arrays. The best you can do is copy the characters from a
string into the array. strcpy() is used for that:

char string[4] = { 0 };
strcpy(string, "abc");

Note that the string "abc" is four characters long: 'a', 'b', 'c', and the
null terminator: '\0'.

--
Josh
Nov 14 '05 #5

P: n/a
Alan wrote:


I want to define a constant length string, say 4
then, in a function at some time,
I want to set the string to a constant value,
say a below is my code but it fails.
What is the correct code?

char string[4] = {0};

string = 'a '; /* <-- failed */


I'm going to assume that you really meant an array of characters.
In C, a *string* must be terminated by a nul character '\0'.

#include <string.h>

char array[4] = {0, 0, 0, 0};

memcpy(array, "a ", 4);
Nov 14 '05 #6

P: n/a
AirPete wrote:
memcpy("abcd", string, sizeof(string));


You got the source and destination arrays confused.

Nov 14 '05 #7

P: n/a
In comp.lang.c Alan <al*************@sinatown.com> wrote:
char string[4] = {0};
string = 'a '; /* <-- failed */
As you've discovered, the first response to your post was completely
bogus. I'll try to do better (clc bogon catches appreciated):
char string[4] = {0};
string (a dubious name, but we'll go with it) as you've declared it is
an array of exactly four characters. You set each of these to zero
with your initialization. All is well.
string = 'a '; /* <-- failed */


This, as you know, is wrong. Strings cannot be assigned to in this
fashion in C. The way to accomplish the same thing is by using the
strcpy() function. Look it up in your friendly C book. Then, observe
that even if you succeeded with your assignment, you would still be
wrong. Your array is four characters, but your assignment needs
*five*, because strings in C must be terminated with '\0'.

Cuddle with your friendly C book, learn the ways of strings, and post
back when you're ready to try again. The fact that you aren't using
the correct string delimiter means you don't know enough about what you're
doing to be posting here.

--
Christopher Benson-Manica | I *should* know what I'm talking about - if I
ataru(at)cyberspace.org | don't, I need to know. Flames welcome.
Nov 14 '05 #8

P: n/a
Mac
On Wed, 04 Feb 2004 19:12:32 +0000, E. Robert Tisdale wrote:
Alan wrote:


I want to define a constant length string, say 4
then, in a function at some time,
I want to set the string to a constant value,
say a below is my code but it fails.
What is the correct code?

char string[4] = {0};

string = 'a '; /* <-- failed */
I'm going to assume that you really meant an array of characters.
In C, a *string* must be terminated by a nul character '\0'.


The OP's code does terminate the string. The assignment is obviously
wrong, but the initialization leaves the string terminated.

#include <string.h>

char array[4] = {0, 0, 0, 0};

This is a verbose way of doing the same thing as the OP.
memcpy(array, "a ", 4);


This leaves array as an array of chars, as you said. I just need to
emphasize to the OP that that is probably not a good idea.
--Mac

Nov 14 '05 #9

P: n/a
"Christopher Benson-Manica" <at***@nospam.cyberspace.org> wrote in message
news:bv**********@chessie.cirr.com...
In comp.lang.c Alan <al*************@sinatown.com> wrote:
char string[4] = {0};
string = 'a '; /* <-- failed */
<<snip>> Cuddle with your friendly C book, learn the ways of strings, and post
back when you're ready to try again. The fact that you aren't using
the correct string delimiter means you don't know enough about what you're
doing to be posting here.


On the other hand, the fact that the OP didn't know enough about what he was
doing may be taken as precisely why he should be posting here.
See the word "learn" in the ng name? (Of course, what he may learn is that
not all responses are correct or helpful.)
--
Gary
Nov 14 '05 #10

P: n/a
Mac wrote:
E. Robert Tisdale wrote:
Alan wrote:
I want to define a constant length string, say 4
then, in a function at some time,
I want to set the string to a constant value,
say a below is my code but it fails.
What is the correct code?

char string[4] = {0};

string = 'a '; /* <-- failed */
I'm going to assume that you really meant an array of characters.
In C, a *string* must be terminated by a nul character '\0'.


The Alan's code does terminate the string.


More precisely, it leaves it *empty*.
The assignment is obviously wrong,
but the initialization leaves the string terminated.
#include <string.h>

char array[4] = {0, 0, 0, 0};


This is a verbose way of doing the same thing as the OP.


Yes.
memcpy(array, "a ", 4);


This leaves array as an array of chars, as you said.
I just need to emphasize to Alan that
that is probably not a good idea.


Agreed, if Alan really believes that
his string array is a character *string*.
His right-hand-side 'a ' contains four non-nul characters
so I can only assume that he believes string is really
just an array of four characters and *not* a string.
Actually, I think that Alan has *not* decided this point
and is still confused.

Nov 14 '05 #11

P: n/a
*** post for FREE via your newsreader at post.newsfeed.com ***

"Gary" <gl*******@comcast.net> wrote in
news:2Y********************@comcast.com:
"Christopher Benson-Manica" <at***@nospam.cyberspace.org> wrote in
message news:bv**********@chessie.cirr.com...
In comp.lang.c Alan <al*************@sinatown.com> wrote:
> char string[4] = {0};
> string = 'a '; /* <-- failed */ <<snip>>
Cuddle with your friendly C book, learn the ways of strings, and post
back when you're ready to try again. The fact that you aren't using
the correct string delimiter means you don't know enough about what
you're doing to be posting here.


On the other hand, the fact that the OP didn't know enough about what
he was doing may be taken as precisely why he should be posting here.
See the word "learn" in the ng name? (Of course, what he may learn is
that not all responses are correct or helpful.)


Yes, well

Notice, in Christopher's post, the line
In comp.lang.c Alan <al*************@sinatown.com> wrote:

^^^^^^^^^^^

As the OP was cross-posting, Christopher offered his reply from the NG
that does *not* contain 'learn' in the name.

Andrew
-----= Posted via Newsfeed.Com, Uncensored Usenet News =-----
http://www.newsfeed.com - The #1 Newsgroup Service in the World!
-----== 100,000 Groups! - 19 Servers! - Unlimited Download! =-----

Nov 14 '05 #12

P: n/a
Leor Zolman wrote:
To change the value of the string, plain old strcpy works:

strcpy(string, "a");

If you're concerned about possibly overwriting the four available
bytes of the array (it wouldn't happen with the call above, but might
if you don't know for sure what the length of the string you're
copying from is), consider strncpy:

strncpy(string, some_source_ptr, 4);

However, this _still_ has the potential of leaving string without a
terminating null. You just have to be careful.


It also has the potential to copy rather less of the data than was intended.
Copying too much data to a target is a bad idea, because it trashes memory,
and you are right to warn against this. But never forget that copying too
/little/ data from a source is /also/ a bad idea, because it generally
isn't what the program is meant to do!

The budding C programmer needs to learn, quite early on in life, that he or
she *must* ensure that the target is large enough for /all/ the data that
it needs to contain. Once you've ensured this, the choice between strcpy
and strncpy hinges entirely on your like, or dislike, for extra keystrokes.

--
Richard Heathfield : bi****@eton.powernet.co.uk
"Usenet is a strange place." - Dennis M Ritchie, 29 July 1999.
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
K&R answers, C books, etc: http://users.powernet.co.uk/eton
Nov 14 '05 #13

P: n/a
"Andrew Clark" <an*****@syr.edu> wrote in message
news:Xn********************@208.33.61.211...
*** post for FREE via your newsreader at post.newsfeed.com ***

"Gary" <gl*******@comcast.net> wrote in
news:2Y********************@comcast.com:
"Christopher Benson-Manica" <at***@nospam.cyberspace.org> wrote in
message news:bv**********@chessie.cirr.com...
In comp.lang.c Alan <al*************@sinatown.com> wrote:

> char string[4] = {0};
> string = 'a '; /* <-- failed */

<<snip>>
Cuddle with your friendly C book, learn the ways of strings, and post
back when you're ready to try again. The fact that you aren't using
the correct string delimiter means you don't know enough about what
you're doing to be posting here.


On the other hand, the fact that the OP didn't know enough about what
he was doing may be taken as precisely why he should be posting here.
See the word "learn" in the ng name? (Of course, what he may learn is
that not all responses are correct or helpful.)


Yes, well

Notice, in Christopher's post, the line
In comp.lang.c Alan <al*************@sinatown.com> wrote:

^^^^^^^^^^^

As the OP was cross-posting, Christopher offered his reply from the NG
that does *not* contain 'learn' in the name.


You are absolutely right! I don't read the comp.lang.c ng because there is
nothing to learn there.
--
Gary
Nov 14 '05 #14

P: n/a
Gary wrote:
I don't read the comp.lang.c ng because there is
nothing to learn there.


That's odd. I thought I was a C expert until I started using the comp.lang.c
newsgroup. Its regular contributors taught me an immense amount about the
language.

If you wish to learn about C, perhaps you should look at comp.lang.c a
little harder.

--
Richard Heathfield : bi****@eton.powernet.co.uk
"Usenet is a strange place." - Dennis M Ritchie, 29 July 1999.
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
K&R answers, C books, etc: http://users.powernet.co.uk/eton
Nov 14 '05 #15

P: n/a
E. Robert Tisdale wrote:
AirPete wrote:
memcpy("abcd", string, sizeof(string));


You got the source and destination arrays confused.


Oops, thanks for pointing it out!
I even looked at the documentation twice :)

- Pete
Nov 14 '05 #16

P: n/a
Christopher Benson-Manica wrote:
In comp.lang.c Alan <al*************@sinatown.com> wrote:
char string[4] = {0};
string = 'a '; /* <-- failed */


As you've discovered, the first response to your post was completely
bogus. I'll try to do better (clc bogon catches appreciated):


Except for my accidental argument misordering, what was wrong/incorrect?
Alan (OP) asked how to move a *constant* length string, which memcpy does
quite nicely.
There is plenty of uses for constant length strings; sometimes they're more
suitable for the task.

[snip]
Nov 14 '05 #17

P: n/a
Alan wrote:
[snip]

memcpy("abcd", string, sizeof(string));
sorry, but it doesn't work
when I run the program, the program crashes


Sorry, I got the arguments misordered, it should be:
memcpy(string, "abcd", sizeof(string));

- Pete


Nov 14 '05 #18

P: n/a
In comp.lang.c AirPete <x@x.x> wrote:
Except for my accidental argument misordering, what was wrong/incorrect?
As others pointed out, you missed a '\0' character at the end of the
string.
Alan (OP) asked how to move a *constant* length string, which memcpy does
quite nicely.


strcpy() does it even more nicely, assuming the destination is
sufficiently large. Among other things, it prevents the above mistake
entirely.

--
Christopher Benson-Manica | I *should* know what I'm talking about - if I
ataru(at)cyberspace.org | don't, I need to know. Flames welcome.
Nov 14 '05 #19

P: n/a
On Thu, 5 Feb 2004 05:51:45 +0000 (UTC), Richard Heathfield
<do******@address.co.uk.invalid> wrote:
Leor Zolman wrote:
To change the value of the string, plain old strcpy works:

strcpy(string, "a");

If you're concerned about possibly overwriting the four available
bytes of the array (it wouldn't happen with the call above, but might
if you don't know for sure what the length of the string you're
copying from is), consider strncpy:

strncpy(string, some_source_ptr, 4);

However, this _still_ has the potential of leaving string without a
terminating null. You just have to be careful.
It also has the potential to copy rather less of the data than was intended.
Copying too much data to a target is a bad idea, because it trashes memory,
and you are right to warn against this. But never forget that copying too
/little/ data from a source is /also/ a bad idea, because it generally
isn't what the program is meant to do!


But in the case of copying into a "string" (char array) buffer, it
seems to me that copying "too little" is exactly what you'd _want_ it
to do. As the subject of the post is "simple string question", I don't
see the point of reading extra requirements into the problem; I didn't
see any indication in the OP's (admittedly sparse) code that "string"
was to be used in any way other than as a nul-terminating string, and
in that context I'd vote for strcpy/strncpy being the best choice.
The budding C programmer needs to learn, quite early on in life, that he or
she *must* ensure that the target is large enough for /all/ the data that
it needs to contain. Once you've ensured this, the choice between strcpy
and strncpy hinges entirely on your like, or dislike, for extra keystrokes.


IMO, a budding C programmer also needs to understand the concept of
nul-terminated strings and all of the implication of using them,
including fundamental efficiency issues that are in the spirit of C...
I'd place the order of importance of all the things we've discussed
as:
1. not overflowing buffers
2. doing things efficiently
3. filling in dead space (?)
Cheers,
-leor
Leor Zolman
BD Software
le**@bdsoft.com
www.bdsoft.com -- On-Site Training in C/C++, Java, Perl & Unix
C++ users: Download BD Software's free STL Error Message
Decryptor at www.bdsoft.com/tools/stlfilt.html
Nov 14 '05 #20

P: n/a
On Thu, 5 Feb 2004 02:20:43 -0500, "Gary" <gl*******@comcast.net>
wrote:

As the OP was cross-posting, Christopher offered his reply from the NG
that does *not* contain 'learn' in the name.


You are absolutely right! I don't read the comp.lang.c ng because there is
nothing to learn there.


Wow. I'm not sure which has more shock value, the statement above or
Janet Jackson's stunt last Sunday...

But moral outrage notwithstanding ;-) , check out Agent for reading
your news. I was pleasantly surprised the first time I hit "post
follow-up message" to a cross-posted post: it immediately informed me
of the cross-posting, and offered me the choice (via several buttons)
of whether I wanted my reply to go to just the current group or to
all. Nice feature.
-leor
Leor Zolman
BD Software
le**@bdsoft.com
www.bdsoft.com -- On-Site Training in C/C++, Java, Perl & Unix
C++ users: Download BD Software's free STL Error Message
Decryptor at www.bdsoft.com/tools/stlfilt.html
Nov 14 '05 #21

P: n/a
Christopher Benson-Manica wrote:
In comp.lang.c AirPete <x@x.x> wrote:
Except for my accidental argument misordering, what was
wrong/incorrect?
As others pointed out, you missed a '\0' character at the end of the
string.


Which is just a waste of space in a constant length string.
Alan (OP) asked how to move a *constant* length string, which memcpy
does quite nicely.


strcpy() does it even more nicely, assuming the destination is
sufficiently large. Among other things, it prevents the above mistake
entirely.


strcpy() relies on the terminating '\0', which was not needed.
- Pete


Nov 14 '05 #22

P: n/a
In comp.lang.c AirPete <x@x.x> wrote:
Which is just a waste of space in a constant length string.
An array of characters not followed by a NUL character isn't a
"string" as far as C is concerned. Without the NUL, you can't print
the array or pass it to any of the <string.h> functions. Sounds like
a problem to me.
strcpy() relies on the terminating '\0', which was not needed.


Unless you want to actually *use* the string for something, of course.

--
Christopher Benson-Manica | I *should* know what I'm talking about - if I
ataru(at)cyberspace.org | don't, I need to know. Flames welcome.
Nov 14 '05 #23

P: n/a
"Richard Heathfield" <do******@address.co.uk.invalid> wrote in message
news:bv**********@hercules.btinternet.com...
Gary wrote:
I don't read the comp.lang.c ng because there is
nothing to learn there.
That's odd. I thought I was a C expert until I started using the

comp.lang.c newsgroup. Its regular contributors taught me an immense amount about the
language.

If you wish to learn about C, perhaps you should look at comp.lang.c a
little harder.


Good Lord, it was a joke. (Well, it was supposed to be. Clearly all ng's
have some teaching value, except for those that purposely misspell stuff,
like warez, etc.)
--
Gary
Nov 14 '05 #24

P: n/a
On Thu, 05 Feb 2004 14:00:20 GMT, "AirPete" <x@x.x> wrote:
Christopher Benson-Manica wrote:
In comp.lang.c AirPete <x@x.x> wrote:
Except for my accidental argument misordering, what was
wrong/incorrect?


As others pointed out, you missed a '\0' character at the end of the
string.


Which is just a waste of space in a constant length string.


I think the problem here is that the OP has not (yet?) clarified
whether his "constant length string" is required to be nul-terminated,
and most of us have been going under the assumption that it is,
because that's the usual MO of C... So I hear your point, but until we
get a clarification on his intent, this horse has pretty much expired.
-leor

Leor Zolman
BD Software
le**@bdsoft.com
www.bdsoft.com -- On-Site Training in C/C++, Java, Perl & Unix
C++ users: Download BD Software's free STL Error Message
Decryptor at www.bdsoft.com/tools/stlfilt.html
Nov 14 '05 #25

P: n/a
Christopher Benson-Manica wrote:
In comp.lang.c AirPete <x@x.x> wrote:
Which is just a waste of space in a constant length string.
An array of characters not followed by a NUL character isn't a
"string" as far as C is concerned. Without the NUL, you can't print
the array or pass it to any of the <string.h> functions. Sounds like
a problem to me.


If the string is constant length, there isn't much use for <string.h>
functions, anyway.
They mostly modify a string's length, making it not constant length, and
strlen() isn't needed because you already know how long it is.
strcpy() relies on the terminating '\0', which was not needed.


Unless you want to actually *use* the string for something, of course.


fwrite(string, sizeof(char), sizeof(string)/sizeof(char), stdout);
fread(string, sizeof(char), sizeof(string)/sizeof(char), stdin);
if(memcmp(string, "abcd", 4)==0);

I can't think of much else you would need to do with a constant length
string, and anything else could be /very/ easily written.

- Pete
Nov 14 '05 #26

P: n/a
In article <26********************************@4ax.com> Leor Zolman <le**@bdsoft.com> writes:
....
I think the problem here is that the OP has not (yet?) clarified
whether his "constant length string" is required to be nul-terminated,
and most of us have been going under the assumption that it is,
because that's the usual MO of C... So I hear your point, but until we
get a clarification on his intent, this horse has pretty much expired.


Well, considering the original snippet, which was something like:
char string[4] = {};
string = 'a ';
I would say it was clear (count the number of characters in the
"string"-literal).
--
dik t. winter, cwi, kruislaan 413, 1098 sj amsterdam, nederland, +31205924131
home: bovenover 215, 1025 jn amsterdam, nederland; http://www.cwi.nl/~dik/
Nov 14 '05 #27

P: n/a
In comp.lang.c Dik T. Winter <Di********@cwi.nl> wrote:
char string[4] = {};
string = 'a ';
I would say it was clear (count the number of characters in the
"string"-literal).


That's if we assume the OP realized there was a NUL character to
contend with, which I doubt.

--
Christopher Benson-Manica | I *should* know what I'm talking about - if I
ataru(at)cyberspace.org | don't, I need to know. Flames welcome.
Nov 14 '05 #28

P: n/a
On Thu, 5 Feb 2004 14:57:49 GMT, "Dik T. Winter" <Di********@cwi.nl>
wrote:
In article <26********************************@4ax.com> Leor Zolman <le**@bdsoft.com> writes:
...
I think the problem here is that the OP has not (yet?) clarified
whether his "constant length string" is required to be nul-terminated,
and most of us have been going under the assumption that it is,
because that's the usual MO of C... So I hear your point, but until we
get a clarification on his intent, this horse has pretty much expired.
Well, considering the original snippet, which was something like:
char string[4] = {};
string = 'a ';


My point exactly ;-)
I would say it was clear (count the number of characters in the
"string"-literal).


If you also count in the '=' operator and single quotes, it doesn't
add up to a large degree of confidence in the OP's intentions.
-leor


Leor Zolman
BD Software
le**@bdsoft.com
www.bdsoft.com -- On-Site Training in C/C++, Java, Perl & Unix
C++ users: Download BD Software's free STL Error Message
Decryptor at www.bdsoft.com/tools/stlfilt.html
Nov 14 '05 #29

P: n/a
Leor Zolman wrote:
On Thu, 5 Feb 2004 05:51:45 +0000 (UTC), Richard Heathfield
<do******@address.co.uk.invalid> wrote:
Leor Zolman wrote:
To change the value of the string, plain old strcpy works:

strcpy(string, "a");

If you're concerned about possibly overwriting the four available
bytes of the array (it wouldn't happen with the call above, but might
if you don't know for sure what the length of the string you're
copying from is), consider strncpy:

strncpy(string, some_source_ptr, 4);

However, this _still_ has the potential of leaving string without a
terminating null. You just have to be careful.
It also has the potential to copy rather less of the data than was
intended. Copying too much data to a target is a bad idea, because it
trashes memory, and you are right to warn against this. But never forget
that copying too /little/ data from a source is /also/ a bad idea, because
it generally isn't what the program is meant to do!


But in the case of copying into a "string" (char array) buffer, it
seems to me that copying "too little" is exactly what you'd _want_ it
to do.


Not at all. Think about what "too little" means. It means "not enough",
"less than is good". Imagine a computer program that kept sending letters
addressed to:

Mr Leor Zol
12 West Lex
San Francis

(Made up address, obviously.)
As the subject of the post is "simple string question", I don't
see the point of reading extra requirements into the problem;
Neither did I, but I don't think "make sure you have enough space" counts as
an /extra/ requirement. It's just a requirement, and a fundamental one,
when dealing with any kind of data.
I didn't
see any indication in the OP's (admittedly sparse) code that "string"
was to be used in any way other than as a nul-terminating string,
Nor did I.
and
in that context I'd vote for strcpy/strncpy being the best choice.
I'd agree with strcpy. I'm still not sure why you think strncpy is
appropriate.
The budding C programmer needs to learn, quite early on in life, that he
or she *must* ensure that the target is large enough for /all/ the data
that it needs to contain. Once you've ensured this, the choice between
strcpy and strncpy hinges entirely on your like, or dislike, for extra
keystrokes.


IMO, a budding C programmer also needs to understand the concept of
nul-terminated strings and all of the implication of using them,


Of course. Er, I agree, and whoever said anything different?
including fundamental efficiency issues that are in the spirit of C...
I'd place the order of importance of all the things we've discussed
as:
1. not overflowing buffers
Right! So make sure the target buffer has enough room for all the data that
the program will attempt to store in it.
2. doing things efficiently
Yes, and is it not inefficient to learn as one's primary method of copying
strings a technique that can so easily drop important data without notice?
3. filling in dead space (?)


Why is that important?
--
Richard Heathfield : bi****@eton.powernet.co.uk
"Usenet is a strange place." - Dennis M Ritchie, 29 July 1999.
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
K&R answers, C books, etc: http://users.powernet.co.uk/eton
Nov 14 '05 #30

P: n/a
On Thu, 5 Feb 2004 18:13:54 +0000 (UTC), Richard Heathfield
<do******@address.co.uk.invalid> wrote:
Leor Zolman wrote:

If you're concerned about possibly overwriting the four available
bytes of the array (it wouldn't happen with the call above, but might
if you don't know for sure what the length of the string you're
copying from is), consider strncpy:

strncpy(string, some_source_ptr, 4);

However, this _still_ has the potential of leaving string without a
terminating null. You just have to be careful.

It also has the potential to copy rather less of the data than was
intended. Copying too much data to a target is a bad idea, because it
trashes memory, and you are right to warn against this. But never forget
that copying too /little/ data from a source is /also/ a bad idea, because
it generally isn't what the program is meant to do!
But in the case of copying into a "string" (char array) buffer, it
seems to me that copying "too little" is exactly what you'd _want_ it
to do.


Not at all. Think about what "too little" means. It means "not enough",
"less than is good". Imagine a computer program that kept sending letters
addressed to:

Mr Leor Zol
12 West Lex
San Francis

(Made up address, obviously.)


I was basing my comments on the assertion that the OP had intended
(whether he knew it or not) for "string" to be nul-terminated. If
you're in the "he meant const length string to mean there's no
nul-terminator" camp, we've been arguing at cross-purposes, and I
agree with all your points in that context...
As the subject of the post is "simple string question", I don't
see the point of reading extra requirements into the problem;
Neither did I, but I don't think "make sure you have enough space" counts as
an /extra/ requirement. It's just a requirement, and a fundamental one,
when dealing with any kind of data.


Sorry, if I ever gave the impression I wasn't concerned about making
sure we had enough space, I sure never meant to say that.
I didn't
see any indication in the OP's (admittedly sparse) code that "string"
was to be used in any way other than as a nul-terminating string,
Nor did I.
and
in that context I'd vote for strcpy/strncpy being the best choice.


I'd agree with strcpy. I'm still not sure why you think strncpy is
appropriate.


I thought I made that clear as well earlier: In the general case when
you don't know the length of the source string, it is safer than using
strcpy. And I believe I explicitly said it wasn't necessary in this
particular case if you're copying from a fixed string you know isn't
going to be too long.
The budding C programmer needs to learn, quite early on in life, that he
or she *must* ensure that the target is large enough for /all/ the data
that it needs to contain. Once you've ensured this, the choice between
strcpy and strncpy hinges entirely on your like, or dislike, for extra
keystrokes.
IMO, a budding C programmer also needs to understand the concept of
nul-terminated strings and all of the implication of using them,


Of course. Er, I agree, and whoever said anything different?

I never implied you said differently. I was embarking on a new point,
sort of...
including fundamental efficiency issues that are in the spirit of C...
I'd place the order of importance of all the things we've discussed
as:
1. not overflowing buffers
Right! So make sure the target buffer has enough room for all the data that
the program will attempt to store in it.
2. doing things efficiently


Yes, and is it not inefficient to learn as one's primary method of copying
strings a technique that can so easily drop important data without notice?


Again, wouldn't you only be dropping important data if you didn't
consider string to be nul-terminated? What did the OP _really_ mean by
"const length string"?? That's the crux of the question. I sure wish
he'd answer it. _I_ interpreted it to mean a fixed length char array
containing a "variable length nul-terminated sequence of characters".
Maybe that was assuming too much. When the OP says "Oh, I'm using all
four bytes and not expecting to use them with any functions that
expect nul termination", my assumption will have been proven wrong.
3. filling in dead space (?)


Why is that important?


Because under my assumptions, characters after the first nul and
before the end of the array are dead space. [And yes, I _do_ know what
happens when you "assume" ;-) ]
Cheers,
-leor


Leor Zolman
BD Software
le**@bdsoft.com
www.bdsoft.com -- On-Site Training in C/C++, Java, Perl & Unix
C++ users: Download BD Software's free STL Error Message
Decryptor at www.bdsoft.com/tools/stlfilt.html
Nov 14 '05 #31

P: n/a
Leor Zolman wrote:
On Thu, 5 Feb 2004 18:13:54 +0000 (UTC), Richard Heathfield
<do******@address.co.uk.invalid> wrote:
Leor Zolman wrote:
<lots of misunderstanding snipped!>
and
in that context I'd vote for strcpy/strncpy being the best choice.
I'd agree with strcpy. I'm still not sure why you think strncpy is
appropriate.


I thought I made that clear as well earlier:


No, this is the heart of the matter.
In the general case when
you don't know the length of the source string, it is safer than using
strcpy.
No, it isn't. The only safe and correct thing to do, if you don't know the
length of the source string, is to ***find out***.
And I believe I explicitly said it wasn't necessary in this
particular case if you're copying from a fixed string you know isn't
going to be too long.
Sure; I'm talking general case. And, in the general case, if you don't know
whether your target buffer is big enough for all the data you need, strncpy
is *not* a good enough solution. Yes, it's safe enough *if* you use it
right - but then, so is strcpy *if* you use it right. And strcpy copies
/all/ the data you need, not just the first chunk. Therefore, as a general
purpose tool it is superior. (And quicker to type.)

The budding C programmer needs to learn, quite early on in life, that he
or she *must* ensure that the target is large enough for /all/ the data
that it needs to contain. Once you've ensured this, the choice between
strcpy and strncpy hinges entirely on your like, or dislike, for extra
keystrokes.

IMO, a budding C programmer also needs to understand the concept of
nul-terminated strings and all of the implication of using them,


Of course. Er, I agree, and whoever said anything different?

I never implied you said differently. I was embarking on a new point,
sort of...


Fine. Misunderstandings all round! :-)
2. doing things efficiently


Yes, and is it not inefficient to learn as one's primary method of copying
strings a technique that can so easily drop important data without notice?


Again, wouldn't you only be dropping important data if you didn't
consider string to be nul-terminated?


Non-issue. If it's not null-terminated, it's not a string. End of story.
What did the OP _really_ mean by
"const length string"??


Who cares? Arguing about strncpy vs. strcpy is far more interesting. :-)
3. filling in dead space (?)


Why is that important?


Because under my assumptions, characters after the first nul and
before the end of the array are dead space. [And yes, I _do_ know what
happens when you "assume" ;-) ]


Anything after the null terminating character is of little interest, IMHO.

--
Richard Heathfield : bi****@eton.powernet.co.uk
"Usenet is a strange place." - Dennis M Ritchie, 29 July 1999.
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
K&R answers, C books, etc: http://users.powernet.co.uk/eton
Nov 14 '05 #32

P: n/a
AirPete wrote:
Christopher Benson-Manica wrote:

As others pointed out, you missed a '\0' character at the end of the
string.
Which is just a waste of space in a constant length string.


But in C, the term 'string' is defined as 'a contiguous sequence of
characters terminated by and including the first null character.' (C
standard clause 7.1.1/1).
Without the nul-terminator, you can not call it a string, regardless of what
you do with it.

- Pete


Bart v Ingen Schenau
--
a.c.l.l.c-c++ FAQ: http://www.snurse-l.org/acllc-c++/faq.html (currently
unavailable)
a.c.l.l.c-c++ FAQ mirror: http://www.inglorion.com/acllcc++.html
c.l.c FAQ: http://www.eskimo.com/~scs/C-faq/top.html
c.l.c++ FAQ: http://www.parashift.com/c++-faq-lite/
Nov 14 '05 #33

P: n/a
In comp.lang.c AirPete <x@x.x> wrote:
They mostly modify a string's length, making it not constant length, and
strlen() isn't needed because you already know how long it is.


Many functions, such as strcmp() and strchr(), in no way affect the
length of their arguments. Of course, you can use memcmp() and
memchr() to get the same results, but there is no mem* analogue to
strstr(). The bottom line is that the byte you save by not appending
a '\0' to character arrays is more than offset by the hoops you have
to jump through to compensate for its absence. I'm really not sure
why you seem to be obsessed with avoiding the str* functions. I'm
certainly willing to listen to valid reasons; I just can't think of
any.

--
Christopher Benson-Manica | I *should* know what I'm talking about - if I
ataru(at)cyberspace.org | don't, I need to know. Flames welcome.
Nov 14 '05 #34

P: n/a
On Thu, 5 Feb 2004 19:01:08 +0000 (UTC), Richard Heathfield
<do******@address.co.uk.invalid> wrote:
In the general case when
you don't know the length of the source string, it is safer than using
strcpy.
No, it isn't. The only safe and correct thing to do, if you don't know the
length of the source string, is to ***find out***.


Yes, I believe I see what you mean now re. strncpy, after taking
another look at the Standard's description of it. If the length of the
source text is greater than the capacity of the destination as
conveyed via the size argument, a NUL won't get appended. You're
right, sorry.
And I believe I explicitly said it wasn't necessary in this
particular case if you're copying from a fixed string you know isn't
going to be too long.
Sure; I'm talking general case. And, in the general case, if you don't know
whether your target buffer is big enough for all the data you need, strncpy
is *not* a good enough solution.


In this discussion, situations where you don't know the size of the
target (that means destination, right? Just making sure...) weren't
even on my radar screen. I was only talking about not knowing the size
of the source.
Yes, it's safe enough *if* you use it
right - but then, so is strcpy *if* you use it right. And strcpy copies
/all/ the data you need, not just the first chunk. Therefore, as a general
purpose tool it is superior. (And quicker to type.)
Terms like "data you need" start to get rather subjective; if you saw
a piece of code such as:
strncpy(dest, source, 50);
it would be hard to argue that the coder "needs" stuff past the first
50 characters, But I have a hard time thinking of strcpy as "safer"
when it could easily lead to a buffer overrun, whereas with strncpy
the worst thing likely to happen (assuming the size you provide is
actually sufficient for the destination buffer you're providing), not
that it would be "acceptable", would be a NUL not getting written.

I think of strcpy being to strncpy as gets is to fgets.

Fine. Misunderstandings all round! :-)
yah, I thought I read and understood what the docs were saying about
strncpy and I wasn't quite with it there with them. Sorry again.

Again, wouldn't you only be dropping important data if you didn't
consider string to be nul-terminated?


Non-issue. If it's not null-terminated, it's not a string. End of story.


I didn't say "a string", I said "string" (as in the OP's array of that
name...and as of this writing, unless more has landed from him while I
was composing this, we still don't know his thinking was in that
regard.)
What did the OP _really_ mean by
"const length string"??
Who cares? Arguing about strncpy vs. strcpy is far more interesting. :-)

Heh.
3. filling in dead space (?)

Why is that important?


Because under my assumptions, characters after the first nul and
before the end of the array are dead space. [And yes, I _do_ know what
happens when you "assume" ;-) ]


Anything after the null terminating character is of little interest, IMHO.


Which was my rationale for preferring strcpy over the other functions;
it doesn't end up taking time to fill in that area that is of little
interest.

Take care,
-leor
Leor Zolman
BD Software
le**@bdsoft.com
www.bdsoft.com -- On-Site Training in C/C++, Java, Perl & Unix
C++ users: Download BD Software's free STL Error Message
Decryptor at www.bdsoft.com/tools/stlfilt.html
Nov 14 '05 #35

P: n/a
Leor Zolman wrote:
On Thu, 5 Feb 2004 19:01:08 +0000 (UTC), Richard Heathfield
<do******@address.co.uk.invalid> wrote:
In the general case when
you don't know the length of the source string, it is safer than using
strcpy.
No, it isn't. The only safe and correct thing to do, if you don't know the
length of the source string, is to ***find out***.


Yes, I believe I see what you mean now re. strncpy, after taking
another look at the Standard's description of it. If the length of the
source text is greater than the capacity of the destination as
conveyed via the size argument, a NUL won't get appended. You're
right, sorry.


That's one of the problems with strncpy. There are plenty more. For a start,
what if you incorrectly specify the third parameter? (It happens, believe
me.)
And I believe I explicitly said it wasn't necessary in this
particular case if you're copying from a fixed string you know isn't
going to be too long.


Sure; I'm talking general case. And, in the general case, if you don't
know whether your target buffer is big enough for all the data you need,
strncpy is *not* a good enough solution.


In this discussion, situations where you don't know the size of the
target (that means destination, right? Just making sure...)


Right.
weren't
even on my radar screen. I was only talking about not knowing the size
of the source.
Finding out how big the source is, is easy. strlen() does it. Presumably you
know how big your target is. So call strlen on your source, and check that
the receiving buffer is big enough. If it isn't, well, Houston, we have a
problem. We might have been clever enough to make the target buffer
dynamic, in which case we can resize. If not, well, we're stuck.

Yes, it's safe enough *if* you use it
right - but then, so is strcpy *if* you use it right. And strcpy copies
/all/ the data you need, not just the first chunk. Therefore, as a general
purpose tool it is superior. (And quicker to type.)


Terms like "data you need" start to get rather subjective; if you saw
a piece of code such as:
strncpy(dest, source, 50);
it would be hard to argue that the coder "needs" stuff past the first
50 characters,


It would be hard to argue that the coder thought the problem through. If he
only wants the first 50 characters, why can the source buffer hold more
than 50? (If it can't, strcpy will work fine.) And why not just nail it:

source[49] = '\0';
strcpy(dest, source);

In the majority of cases (i.e. strlen(source) < 50), this code will be
quicker, since it will have to write fewer bytes. And it's never slower.
But I have a hard time thinking of strcpy as "safer"
when it could easily lead to a buffer overrun,
Only if you are silly enough not to check that your receiving buffer is big
enough. And so can strncpy lead to a buffer overrun, for the same reason.

whereas with strncpy
the worst thing likely to happen (assuming the size you provide is
actually sufficient for the destination buffer you're providing), not
that it would be "acceptable", would be a NUL not getting written.
That's enough. But look at just a few of the things that could go wrong:

strncpy(target, source, sizeof target); /* possibly no null terminator */
strncpy(target, source, sizeof source); /* tyop in third parameter! */
strncpy(target, source, strlen(target)); /* less data than you hoped? */
strncpy(target, source, sizeof target + 1); /* instead of - 1 */

Three of these four can lead to a buffer overrun.
I think of strcpy being to strncpy as gets is to fgets.


The comparison is invalid. The gets() function /cannot/ be used safely,
whereas strcpy can be. It's a sharp tool, and you can cut yourself on it if
you're not careful, but it is a powerful and legitimate tool in the hands
of a competent practitioner.

The fgets/strncpy comparison is probably fair. I rarely use fgets() in real
code, because it's too awkward.

Have a look at http://users.powernet.co.uk/eton/c/fgetdata.html if you want
to see what I wrote for use in "quickie" programs. For real programs, I use
the CLINT library - http://www.rjgh.co.uk/prg/c/wnn/index.php - so that my
target buffer is *always* big enough (because it stretches).

--
Richard Heathfield : bi****@eton.powernet.co.uk
"Usenet is a strange place." - Dennis M Ritchie, 29 July 1999.
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
K&R answers, C books, etc: http://users.powernet.co.uk/eton
Nov 14 '05 #36

P: n/a
nrk
Richard Heathfield wrote:
Leor Zolman wrote:
On Thu, 5 Feb 2004 19:01:08 +0000 (UTC), Richard Heathfield
<do******@address.co.uk.invalid> wrote:

In the general case when
you don't know the length of the source string, it is safer than using
strcpy.

No, it isn't. The only safe and correct thing to do, if you don't know
the length of the source string, is to ***find out***.
Yes, I believe I see what you mean now re. strncpy, after taking
another look at the Standard's description of it. If the length of the
source text is greater than the capacity of the destination as
conveyed via the size argument, a NUL won't get appended. You're
right, sorry.


That's one of the problems with strncpy. There are plenty more. For a
start, what if you incorrectly specify the third parameter? (It happens,
believe me.)


The first problem is a strawman. Since the third argument is well known,
and due to the way standard specifies strncpy must behave, you only have to
check and see if dst[n-1] is '\0' or not, to tackle this situation.

The second is a bogeyman that you can use to scare anyone off any library
function. Idiots can wreck havoc with anything. By your logic, we should
probably never use snprintf, fgets, fread, fwrite, memcpy, memmove,
strncmp, strncat, malloc, realloc and such like. I am not saying that this
mistake is not made, but only that a fear of such mistakes will result in
total paralysis that prevents you from writing any meaningful program. C
does not have bounds checking. You should be aware of the risks you take
when you program in this language.

strncpy is pretty useful when you know that most of the time your input is
going to be less than a certain amount of characters. It can be used
safely by those who pay due care to what it is supposed to do.
And I believe I explicitly said it wasn't necessary in this
particular case if you're copying from a fixed string you know isn't
going to be too long.

Sure; I'm talking general case. And, in the general case, if you don't
know whether your target buffer is big enough for all the data you need,
strncpy is *not* a good enough solution.


In this discussion, situations where you don't know the size of the
target (that means destination, right? Just making sure...)


Right.
weren't
even on my radar screen. I was only talking about not knowing the size
of the source.


Finding out how big the source is, is easy. strlen() does it. Presumably
you know how big your target is. So call strlen on your source, and check
that the receiving buffer is big enough. If it isn't, well, Houston, we
have a problem. We might have been clever enough to make the target buffer
dynamic, in which case we can resize. If not, well, we're stuck.


If I know that most of the time my input is between 18-20 characters, why
waste time with strlen, malloc and strcpy? I would go for an array of 21
characters, try to strncpy 21 characters into it, and check if array[20] is
'\0' or not after the strncpy to see if I've hit the rare case.
Yes, it's safe enough *if* you use it
right - but then, so is strcpy *if* you use it right. And strcpy copies
/all/ the data you need, not just the first chunk. Therefore, as a
general purpose tool it is superior. (And quicker to type.)


Terms like "data you need" start to get rather subjective; if you saw
a piece of code such as:
strncpy(dest, source, 50);
it would be hard to argue that the coder "needs" stuff past the first
50 characters,


It would be hard to argue that the coder thought the problem through. If
he only wants the first 50 characters, why can the source buffer hold more
than 50? (If it can't, strcpy will work fine.) And why not just nail it:

source[49] = '\0';
strcpy(dest, source);


I qualify my input parameters with const as far as possible. Modifying the
source unnecessarily is not only not an option, but is also bad style in my
books. Also, if this is a solution, so is:
dst[49] = 0;
strncpy(dst, src, 49);
In the majority of cases (i.e. strlen(source) < 50), this code will be
quicker, since it will have to write fewer bytes. And it's never slower.
But I have a hard time thinking of strcpy as "safer"
when it could easily lead to a buffer overrun,
Only if you are silly enough not to check that your receiving buffer is
big enough. And so can strncpy lead to a buffer overrun, for the same
reason.


I can twist that argument around to tackle your bogeyman "third argument
incorrect" argument against strncpy: "Only if you're silly enough to pass
the wrong size for the receiving buffer", as you yourself go on to point
out. So, there we go: that argument is a bogeyman by your own admission
:-)

Barring that bogeyman argument, if I used strncpy, I *don't* have to check.
All I have to check is that the src was no longer than I expected, which
can be done in a very straight-forward and simple manner. In fact, you can
(and I do), wrap these operations into a function and use it safely. IMHO,
creating a buffer overrun with strncpy is less likely than with strcpy.
YMMSTV. Of course, if you always wanted all of the source regardless of
size, well, that's what strcpy is for :-)
whereas with strncpy
the worst thing likely to happen (assuming the size you provide is
actually sufficient for the destination buffer you're providing), not
that it would be "acceptable", would be a NUL not getting written.
That's enough. But look at just a few of the things that could go wrong:

strncpy(target, source, sizeof target); /* possibly no null terminator */

strawman.
strncpy(target, source, sizeof source); /* tyop in third parameter! */ bogeyman.
strncpy(target, source, strlen(target)); /* less data than you hoped? */ bogeyman. malloc(strlen(target))... One sees the mushroom cloud.
strncpy(target, source, sizeof target + 1); /* instead of - 1 */ Nope. sizeof target is perfectly fine. It is because of misunderstanding
strncpy that you're playing around with the -1, +1 stuff. Also, if you
ever see that code and don't realize you're making a mistake, you probably
shouldn't be programming in C. (That's a metaphorical you, not "you" RJH).

Three of these four can lead to a buffer overrun.

strcpy(dst, src);

gives me no information about possible errors. Atleast, strncpy tells me
how much will be written.
I think of strcpy being to strncpy as gets is to fgets.


The comparison is invalid. The gets() function /cannot/ be used safely,
whereas strcpy can be. It's a sharp tool, and you can cut yourself on it
if you're not careful, but it is a powerful and legitimate tool in the
hands of a competent practitioner.


Yes. That is not a fair comparison. But strncpy is a perfectly safe and
useful function, that you should try to use if appropriate, just as you
should use strcpy when appropriate.
The fgets/strncpy comparison is probably fair. I rarely use fgets() in
real code, because it's too awkward.

This comparison is also not fair. fgets is idiotic. It may or may not
leave a newline in your buffer and may or may not consume a complete line
of input. All the while, it gives you the false illusion that you can use
it to read one "line" from the input stream. There is no easy way to check
how much exactly was read by fgets. If I had a choice, I would make fgets
return the number of characters read instead of uselessly returning the dst
pointer. scanf is complicated and its usage is error-prone (by me
atleast). However, I usually try to take the time to get a working scanf
solution when it is feasible and shun fgets. strncpy on the other hand
suffers none of those drawbacks. You know exactly, in one comparison,
whether you had enough space for all of the source, and whether your dst is
a valid string or not.

My point is that all library functions have pros and cons. Some like gets
are hopelessly broken. But being dogmatic about rejecting one and favoring
the other without thinking the issues through is ridiculous. So, yes,
there are good, valid situations where strncpy is an excellent fit for the
problem. Don't blindly reject it in favor of strcpy.

-nrk.
Have a look at http://users.powernet.co.uk/eton/c/fgetdata.html if you
want to see what I wrote for use in "quickie" programs. For real programs,
I use the CLINT library - http://www.rjgh.co.uk/prg/c/wnn/index.php - so
that my target buffer is *always* big enough (because it stretches).


--
Remove devnull for email
Nov 14 '05 #37

P: n/a

"Alan" <al*************@sinatown.com> bl
news:bv**********@news.hgc.com.hk g...
hi all,

I want to define a constant length string, say 4
then in a function at some time, I want to set the string to a constant
value, say a
below is my code but it fails
what is the correct code?
many thx!
char string[4] = {0};

string = 'a '; /* <-- failed */


sorry, maybe I did not make the question clear so there are confusions and
discussions about the "nul-terminated". In fact, I did not take too much
notice about the "nul-terminated" I must admit.

what I want to do is,
copy characters from some fixed positions at a source file, and then write
those fixed length characters to a new binary file. And there are times that
I assign values directly to those fixed length characters instead of reading
from a source file and then write to the binary file.
After writing the binary file, I will read the fixed length characters base
of the length of characters.
Here is how I do it:

char array[10] = {0};

....
fgets(line, sizeof(line), sourceFile); // get the beginning position of the
characters from source file
strncpy(array, line+27, 10); // and copy to "array"
array[10] = 0;

....
strcpy(array, "abcde "); // assign values myself

....
if (fwrite(&array, sizeof(array), 1, binaryFile) != 1)
{
printf("Error writing array to binary file!\n");
}
Nov 14 '05 #38

P: n/a
Richard Heathfield wrote:
Leor Zolman wrote:
Richard Heathfield wrote:
Leor Zolman wrote:


.... self-recursively about strncpy, strcpy, strlen, gets, etc ...

As far as I am concerned a better solution exists in the BSD
strlcpy and strlcat routines. I have published an implementation
(see URL below, download section), and that includes references to
the original BSD description and rationale. They are much harder
to misuse, and generally will do just what you wish.

--
Chuck F (cb********@yahoo.com) (cb********@worldnet.att.net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net> USE worldnet address!

Nov 14 '05 #39

P: n/a
Mac
On Wed, 04 Feb 2004 20:42:49 +0000, E. Robert Tisdale wrote:
Mac wrote:
E. Robert Tisdale wrote:
Alan wrote:

I want to define a constant length string, say 4
then, in a function at some time,
I want to set the string to a constant value,
say a below is my code but it fails.
What is the correct code?

char string[4] = {0};

string = 'a '; /* <-- failed */

I'm going to assume that you really meant an array of characters.
In C, a *string* must be terminated by a nul character '\0'.
The Alan's code does terminate the string.
Why did you change "The OP's" to "The Alan's?" I'm sure I make grammatical
mistakes from time to time, but I would appreciate it if you did not add
new ones when quoting me.

More precisely, it leaves it *empty*.
The assignment is obviously wrong,
but the initialization leaves the string terminated.
#include <string.h>

char array[4] = {0, 0, 0, 0};
This is a verbose way of doing the same thing as the OP.


Yes.
memcpy(array, "a ", 4);


This leaves array as an array of chars, as you said.
I just need to emphasize to Alan that
that is probably not a good idea.


Well, at least you didn't change the sentence to a grammatically incorrect
one.

Agreed, if Alan really believes that
his string array is a character *string*.
His right-hand-side 'a ' contains four non-nul characters
so I can only assume that he believes string is really
just an array of four characters and *not* a string.
Actually, I think that Alan has *not* decided this point
and is still confused.


I agree that the OP is probably confused.

--Mac

Nov 14 '05 #40

P: n/a
"B. v Ingen Schenau" <ba**@ingen.ddns.info> wrote in message news:<bv*************@ID-135549.news.uni-berlin.de>...
AirPete wrote:
Christopher Benson-Manica wrote:

As others pointed out, you missed a '\0' character at the end of the
string.


Which is just a waste of space in a constant length string.


But in C, the term 'string' is defined as 'a contiguous sequence of
characters terminated by and including the first null character.' (C
standard clause 7.1.1/1).
Without the nul-terminator, you can not call it a string, regardless of what
you do with it.

- Pete
Bart v Ingen Schenau


With using constant string like char[80] you should use 'n'-funcs
from std library like strncmp, strncpy. Note that s="Test string" is
already null-terminated.
Melnikov Oleg, ki**********@mail.ru

Nov 14 '05 #41

P: n/a
Mac <fo*@bar.net> scribbled the following
on comp.lang.c:
On Wed, 04 Feb 2004 20:42:49 +0000, E. Robert Tisdale wrote:
Mac wrote:
E. Robert Tisdale wrote:
Alan wrote:
>I want to define a constant length string, say 4
>then, in a function at some time,
>I want to set the string to a constant value,
>say a below is my code but it fails.
>What is the correct code?
>
> char string[4] = {0};
>
> string = 'a '; /* <-- failed */

I'm going to assume that you really meant an array of characters.
In C, a *string* must be terminated by a nul character '\0'.

The Alan's code does terminate the string.
Why did you change "The OP's" to "The Alan's?" I'm sure I make grammatical
mistakes from time to time, but I would appreciate it if you did not add
new ones when quoting me.


You're lucky he only did that. He's been known to alter other people's
arguments, and to alter their code, introducing errors that weren't
present in the original code.

--
/-- Joona Palaste (pa*****@cc.helsinki.fi) ------------- Finland --------\
\-- http://www.helsinki.fi/~palaste --------------------- rules! --------/
"The question of copying music from the Internet is like a two-barreled sword."
- Finnish rap artist Ezkimo
Nov 14 '05 #42

P: n/a
In article <bv***********@news.hgc.com.hk>, al*************@sinatown.com
says...

[ ... ]
what I want to do is,
copy characters from some fixed positions at a source file, and then write
those fixed length characters to a new binary file. And there are times that
I assign values directly to those fixed length characters instead of reading
from a source file and then write to the binary file.
After writing the binary file, I will read the fixed length characters base
of the length of characters.
Here is how I do it:


Roughly 90% of the code you've given is more or less pointless. First
of all, to accomplish this you don't need to (and generally don't want
to) make extra copies of the characters at all. To copy N characters
from one file to another, you can do something like this:

char buffer[N];
FILE *infile, *outfile;

// ... open files, fseek to starting points in files.

int characters_read = fread(infile, buffer, 1, N);

if (characters_read != N)
; // couldn't read that many characters.

fwrite(outfile, buffer, 1, characters_read);

If you want to create and write the data, you just set up the contents
of buffer, and then write it out. In the end, it comes down to this:
you're using NUL-terminated strings, and string I/O functions to work
with non-string data. You may be able to make that work, but even at
best it probably won't work very well -- at the very least, it leads the
reader to believe that you're dealing with string-like data, which
apparently isn't the case.

--
Later,
Jerry.

The universe is a figment of its own imagination.
Nov 14 '05 #43

P: n/a
Joona I Palaste wrote:
Mac <fo*@bar.net> scribbled the following
E. Robert Tisdale wrote:
.... snip ...

The Alan's code does terminate the string.

Why did you change "The OP's" to "The Alan's?" I'm sure I make
grammatical mistakes from time to time, but I would appreciate
it if you did not add new ones when quoting me.


You're lucky he only did that. He's been known to alter other
people's arguments, and to alter their code, introducing errors
that weren't present in the original code.


I think it's a new trick he learned in the past few months. I
don't recall him performing it earlier than that. He may be
playing the game "See how many I can sneak in without getting
caught".

--
Chuck F (cb********@yahoo.com) (cb********@worldnet.att.net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net> USE worldnet address!
Nov 14 '05 #44

P: n/a
In article <bv*********@sparta.btinternet.com>,
do******@address.co.uk.invalid says...

[ ... ]
It would be hard to argue that the coder thought the problem through. If he
only wants the first 50 characters, why can the source buffer hold more
than 50? (If it can't, strcpy will work fine.) And why not just nail it:

source[49] = '\0';
strcpy(dest, source);


I don't seem to have the original post, so it's hard for me to guess at
all the details here, but I can imagine situations where it's legitimate
to have a larger string, and under some circumstances you want a shorter
version (e.g. with column headers, it's fairly common to truncate or
wrap a name at the width of the column).

The code you've given above truncates the original string, which is
rarely what's wanted. If you want to copy the first N characters of a
string, strncat usually does the job quite nicely:

dest[0] = '\0';
strncat(dest, source, N);

strncat requires that you start with a terminated string, but otherwise
it mostly does what most people expect strncpy to do.

--
Later,
Jerry.

The universe is a figment of its own imagination.
Nov 14 '05 #45

P: n/a
Jerry Coffin wrote:
al*************@sinatown.com says...

[ ... ]
what I want to do is, copy characters from some fixed positions
at a source file, and then write those fixed length characters
to a new binary file. And there are times that
.... snip ...
char buffer[N];
FILE *infile, *outfile;

// ... open files, fseek to starting points in files.

int characters_read = fread(infile, buffer, 1, N);

if (characters_read != N)
; // couldn't read that many characters.

fwrite(outfile, buffer, 1, characters_read);

If you want to create and write the data, you just set up the
contents of buffer, and then write it out. In the end, it
comes down to this: you're using NUL-terminated strings, and
string I/O functions to work with non-string data. You may be
able to make that work, but even at best it probably won't
work very well -- at the very least, it leads the reader to
believe that you're dealing with string-like data, which
apparently isn't the case.


Why the complications? Assuming the streams infile and outfile
are open and appropriately positioned, and you want to copy n
chars where n is non-negative and in a variable, all you need is:

int ch, n;
....
while (n-- && (EOF != (ch = fgetc(infile))))
fputc(ch, outfile);

No need to think about nul bytes, cr, lf, tabs, whatever. Should
there happen to be efficiency problems in the final application,
that is the time to consider further. Not now.

A few more benefits: If it fails (with n non-negative) the values
in ch, n, and ferror allow you to diagnose things fairly well.
You don't need to think about buffer sizes. Odds are high that
the above will be more efficient than the buffered version on many
implementations.

--
Chuck F (cb********@yahoo.com) (cb********@worldnet.att.net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net> USE worldnet address!
Nov 14 '05 #46

P: n/a
On Thu, 5 Feb 2004 09:23:52 -0500, "Gary" <gl*******@comcast.net>
wrote:
"Richard Heathfield" <do******@address.co.uk.invalid> wrote in message
news:bv**********@hercules.btinternet.com...
Gary wrote:
> I don't read the comp.lang.c ng because there is
> nothing to learn there.


That's odd. I thought I was a C expert until I started using the

comp.lang.c
newsgroup. Its regular contributors taught me an immense amount about the
language.

If you wish to learn about C, perhaps you should look at comp.lang.c a
little harder.


Good Lord, it was a joke. (Well, it was supposed to be. Clearly all ng's
have some teaching value, except for those that purposely misspell stuff,
like warez, etc.)


Humour is off topic here, and thus will not be tolerated.

Begone!

Nov 14 '05 #47

P: n/a
nrk
Richard Heathfield wrote:
nrk wrote:
Richard Heathfield wrote:
Leor Zolman wrote:

On Thu, 5 Feb 2004 19:01:08 +0000 (UTC), Richard Heathfield
<do******@address.co.uk.invalid> wrote:

>
>> In the general case when
>> you don't know the length of the source string, it is safer than
>> using strcpy.
>
>No, it isn't. The only safe and correct thing to do, if you don't know
>the length of the source string, is to ***find out***.

Yes, I believe I see what you mean now re. strncpy, after taking
another look at the Standard's description of it. If the length of the
source text is greater than the capacity of the destination as
conveyed via the size argument, a NUL won't get appended. You're
right, sorry.

That's one of the problems with strncpy. There are plenty more. For a
start, what if you incorrectly specify the third parameter? (It happens,
believe me.)

The first problem is a strawman. Since the third argument is well known,
and due to the way standard specifies strncpy must behave, you only have
to check and see if dst[n-1] is '\0' or not, to tackle this situation.


That doesn't /tackle/ the problem - it merely /detects/ it.


Well, detecting the problem is all you can do if you don't want to find out
the source length before copying. However, it is important to note that
detecting the problem is both easy and safe in this case. Harken back to
where you say:
>> In the general case when
>> you don't know the length of the source string, it is safer than
>> using strcpy.
>
>No, it isn't. The only safe and correct thing to do, if you don't know
>the length of the source string, is to ***find out***.

If you do understand strncpy, then using it is a perfectly safe and valid
alternative to trying and finding out the length of the source string, then
doing a malloc and then doing a strcpy.

If you think about it, the fact that strncpy doesn't put a terminating null
character when the source is longer, and that it fills the rest of the
target buffer with nulls when the source is shorter is unavoidable, since
the return value is useless. Without that, it is impossible with a single,
simple last element check on the target to find out whether you got all of
the source or not. A better design of course is the strlcpy in *BSD. For
no discernible reason, someone decided that strncpy's return value should
be absolutely useless, and therefore we have the tricky null termination
semantics.

Again, if you always wanted all of the source regardless of the source
length, you should go for the malloc+strcpy route. But think of situations
where:

If my input is larger than x, it is an error and I simply quit. Here, I
don't want to see if the source is larger than x before issuing the copy.
For instance, such a large source potentially indicates a malicious input
and I wouldn't want to trust it to be a well-formed string with a null
terminator. I simply use strncpy, and see if my destination has a null at
position x or not. If not, I can't handle that input and report it as such
to the user. While this is not bullet-proof, it is atleast better than
running through a possible malicious string in search of a non-existent
null character.

99% of the time, I know that my input is exactly of length x +/- epsilon.
Also, I find that dynamic memory allocation overheads are prohibitive. One
can then think of devising a string pool. Since I know my input profile, I
would design my pool so that by default it is capable of storing strings of
length x+epsilon or less. The usage of this pool would be to get a default
object from the pool, use strncpy and see if you get all of the source, if
not ask for an object big enough to hold the source. You may ask why not
use strlen to start with. Well you see, this happens to be a frequent
operation and I don't want to traverse the source twice all the time. And
I know, my strncpy is not wasted 99% of the time, and is a good choice
provided epsilon isn't significant.
The second is a bogeyman that you can use to scare anyone off any library
function.


I know. I don't intend to take it very far; I'm just pointing out that
/any/ library function - including strcpy AND strncpy - can be misused,
and that many such functions will be unsafe if misused, including both
those two.


Yes. But you also seemed to be implying that malloc+strcpy is superior and
strncpy was in someway more unsafe (atleast that was my reading). IMHO, it
is the other way around and strncpy is safer than strcpy, if you know how
to use it. Too often, you see something like:

char str[64];

...
/* no sanity check on haxorinput */
strcpy(str, haxorinput);

which is no better than gets.
<snip>
strncpy is pretty useful when you know that most of the time your input
is
going to be less than a certain amount of characters. It can be used
safely by those who pay due care to what it is supposed to do.
Sure, of course it can. And so can strcpy. The objection I am making in
this thread is not to strncpy per se, but strncpy as "the safe equivalent
of the unsafe strcpy function". That is what I consider to be wrong.


I agree. strncpy is not a replacement for strcpy. But it is a safe
alternative when you don't want to go through the strlen+malloc+strcpy
route, or take that route only if strncpy fails to fit the bill. Look at
the argument from a maintenance POV again:

char str[64];

...

strcpy(str, haxorinput);
...
strncpy(str, haxorinput, sizeof str);
assert(str[sizeof str - 1] == 0);

For the strcpy, when I look at that code, I have to make sure that
haxorinput has been properly validated to fit into str before that point.
This may or may not be close to the strcpy statement itself. It may even
be done in some other function in some other file (This happens more
frequently than an incorrect 3rd argument to strncpy in my limited
experience).
However, for the strncpy+assert (or strncpy+some other validation), I don't
need to know anything about *haxorinput* except that it is a valid pointer
(which we assume normally). If the validation doesn't immediately follow
that strncpy, you'd have to strongly suspect that something must be wrong,
for there is no logical reason to not validate the result of a function
call immediately afterwards.
<snip>
Finding out how big the source is, is easy. strlen() does it. Presumably
you know how big your target is. So call strlen on your source, and
check that the receiving buffer is big enough. If it isn't, well,
Houston, we have a problem. We might have been clever enough to make the
target buffer dynamic, in which case we can resize. If not, well, we're
stuck.
If I know that most of the time my input is between 18-20 characters, why
waste time with strlen, malloc and strcpy?


That depends how robust and correct you want your program to be on those
occasions when the input is longer.


It can be made just as robust and just as correct as any alternative that
you suggest with strlen+malloc+strcpy.
I would go for an array of 21
characters, try to strncpy 21 characters into it, and check if array[20]
is '\0' or not after the strncpy to see if I've hit the rare case.


Would you not find it easier just to handle the rare case /all/ the time,
since that would result in shorter code than "other cases + rare case"?


No. There can be legitimate reasons to optimize for the common case. It is
not a question of ease of coding.
I qualify my input parameters with const as far as possible. Modifying
the source unnecessarily is not only not an option, but is also bad style
in my books.


I agree. My preferred solution would be to make sure the target buffer
/is/ big enough.
Also, if this is a solution, so is:
dst[49] = 0;
strncpy(dst, src, 49);


Yes, but it takes longer to type. :-)

<snip>
Barring that bogeyman argument, if I used strncpy, I *don't* have to
check. All I have to check is that the src was no longer than I expected,
which
can be done in a very straight-forward and simple manner. In fact, you
can
(and I do), wrap these operations into a function and use it safely.
IMHO, creating a buffer overrun with strncpy is less likely than with
strcpy.
YMMSTV. Of course, if you always wanted all of the source regardless of
size, well, that's what strcpy is for :-)


Right! And if you didn't want all the source, why did you bother to
capture it?


Well, maybe it wasn't me (a library) that captured it. There can be several
layers between user input and your code, not all under your control.
whereas with strncpy
the worst thing likely to happen (assuming the size you provide is
actually sufficient for the destination buffer you're providing), not
that it would be "acceptable", would be a NUL not getting written.

That's enough. But look at just a few of the things that could go wrong:

strncpy(target, source, sizeof target); /* possibly no null terminator
*/

strawman.
strncpy(target, source, sizeof source); /* tyop in third parameter! */

bogeyman.
strncpy(target, source, strlen(target)); /* less data than you hoped? */

bogeyman. malloc(strlen(target))... One sees the mushroom cloud.


I'll buy all those objections to my objections - because they apply
equally to similar objections to strcpy (that is, the arguments against
strcpy are equally strawlike).


strcpy makes me look at code harder to see if things are really ok. Other
than that, I don't have objections to its use. I only have objections to
objections to strncpy (unless those objections are accompanied by a
suggestion to strlcpy or like alternatives). strncpy is a perfectly safe
function to use.
strncpy(target, source, sizeof target + 1); /* instead of - 1 */

Nope. sizeof target is perfectly fine. It is because of
misunderstanding strncpy that you're playing around with the -1, +1
stuff.


sizeof target is all very well, but doesn't guarantee you a
null-terminated string at the end, whereas sizeof target - 1 does.


No. sizeof target - 1 doesn't guarantee a null terminated target either
(not unless you said target[sizeof target - 1] = 0 before or after). You
can see by checking the last character in your target whether your target
buffer was big enough or not.
Also, if you
ever see that code and don't realize you're making a mistake, you
probably shouldn't be programming in C. (That's a metaphorical you, not
"you" RJH).


Thanks for the vote of confidence. :-)


Anytime :-) This discussion is merely an effort to learn more. I have an
opinion. By airing it somewhat stridently, I am trying to provoke you and
other clueful regulars into expanding my knowledge :-)
Three of these four can lead to a buffer overrun.


strcpy(dst, src);

gives me no information about possible errors.


Agreed, but code doesn't exist in a vacuum. In typical code that I've
written, code will exist /before/ the strcpy, that makes sure the target
is large enough.


See argument above. Your code might be well written so that you don't have
to search long and hard for the pre-condition validation. My limited view
suggests that a lot of people tend to spread their pre-condition
validations somewhat more aribitrarily (in time and space) than they would
validate the result of a function call.
I've recently been doing a lot of work on a portable code library called
CLINT. I just grepped the latest source for strcpy, and sure enough, in
over 17000 lines of code, there /is/ a call - one call - to strcpy. Here
it is, in context:

for(i = 0; i < sizeof objname / sizeof objname[0]; i++)
{
assert(sizeof
wnn_GlobalConfig->ObjectCount.ObjectName[i] >
strlen(objname[i]));

strcpy(wnn_GlobalConfig->ObjectCount.ObjectName[i],
objname[i]);
}

(Please understand that we're dealing with fixed size arrays here, arrays
that are not accessible to the user-programmer under normal circumstances.
So I adjudged an assertion to be appropriate.)

Why only one call to strcpy (and no calls to strncpy) in 17000+ lines?
Well, that's because CLINT includes a stretchy string library with its own
string copying routines. But, in the one place I do use it, I think it's
fair to say that I use it appropriately.

I think it is fair to say that you missed a good opportunity to investigate
a strncpy (or like) alternative :-)

for(i = 0; i < sizeof objname / sizeof objname[0]; i++)
{
/* this dst is merely because your original name is too long :-) */
char *dst = wnn_GlobalConfig->ObjectCount.ObjectName[i];
/* this len for same reasons as above */
size_t len = sizeof wnn_GlobalConfig->ObjectCount.ObjectName[i];

strncpy(dst, objname[i], len);
assert(dst[len-1] == 0);
}
The only argument against strncpy here would be the fact that you will
always write len characters. As long as this is less expensive than an
additional function call and traversing the source once more, the strncpy
alternative is better. An even better alternative is to use something akin
to the non-standard strlcpy. There are no real arguments against using an
alternative like strlcpy here (you could easily roll your own if it is not
part of your platform already, or if you plan to distribute your code wider
than your current platform). Here's the strlcpy alternative:

size_t ret = strlcpy(wnn_GlobalConfig->ObjectCount.ObjectName[i],
objname[i],
sizeof
wnn_GlobalConfig->ObjectCount.ObjectName[i]);
assert(ret < sizeof wnn_GlobalConfig->ObjectCount.ObjectName[i]);

If you'd given strncpy a fair think, you might've even thought of a strlcpy
like alternative :-)
Atleast, strncpy tells me
how much will be written.


With strcpy, you already know, because you already checked. :-)
I think of strcpy being to strncpy as gets is to fgets.

The comparison is invalid. The gets() function /cannot/ be used safely,
whereas strcpy can be. It's a sharp tool, and you can cut yourself on it
if you're not careful, but it is a powerful and legitimate tool in the
hands of a competent practitioner.


Yes. That is not a fair comparison. But strncpy is a perfectly safe and
useful function, that you should try to use if appropriate, just as you
should use strcpy when appropriate.


I can buy that.
The fgets/strncpy comparison is probably fair. I rarely use fgets() in
real code, because it's too awkward.


This comparison is also not fair. fgets is idiotic.


Not as idiotic as gets(). :-)
It may or may not
leave a newline in your buffer and may or may not consume a complete line
of input.


Similarly, strncpy may or may not leave a null terminator in your output,
and may or may not copy the entire source string.


Yes. But unlike fgets where there is no easy way to tell other than
travelling through the string again, strncpy gives you an easy fool-proof
way to resolve all those may/may not issues.

-nrk.

ps: Aplogies. I didn't realize that in my original post, clc was removed
from the follow-up list.
<snip>


--
Remove devnull for email
Nov 14 '05 #48

P: n/a
In article <40***************@yahoo.com>, cb********@yahoo.com says...

[ ... ]
int characters_read = fread(infile, buffer, 1, N);

if (characters_read != N)
; // couldn't read that many characters.

fwrite(outfile, buffer, 1, characters_read);

[ ... ]
Why the complications? Assuming the streams infile and outfile
are open and appropriately positioned, and you want to copy n
chars where n is non-negative and in a variable, all you need is:

int ch, n;
....
while (n-- && (EOF != (ch = fgetc(infile))))
fputc(ch, outfile);
At least to me, this looks substantially more complicated than one call
to fread followed by one to fwrite.
No need to think about nul bytes, cr, lf, tabs, whatever.
What code do you see that DOES force one to think about nul bytes, cr,
lf, tabs, etc?
A few more benefits: If it fails (with n non-negative) the values
in ch, n, and ferror allow you to diagnose things fairly well.
You don't need to think about buffer sizes. Odds are high that
the above will be more efficient than the buffered version on many
implementations.


I doubt it'll often matter, and your implementation isn't nearly as much
slower as many people expect, but I've yet to see an implementation with
which it's really as fast as using fread and fwrite to work in big
chunks. In theory I can see reasons it _could_ be, but I've yet to
actually see it in reality.

--
Later,
Jerry.

The universe is a figment of its own imagination.
Nov 14 '05 #49

P: n/a
Jerry Coffin wrote:
cb********@yahoo.com says...

[ ... ]
int characters_read = fread(infile, buffer, 1, N);

if (characters_read != N)
; // couldn't read that many characters.

fwrite(outfile, buffer, 1, characters_read);

[ ... ]
Why the complications? Assuming the streams infile and outfile
are open and appropriately positioned, and you want to copy n
chars where n is non-negative and in a variable, all you need is:

int ch, n;
....
while (n-- && (EOF != (ch = fgetc(infile))))
fputc(ch, outfile);


At least to me, this looks substantially more complicated than one
call to fread followed by one to fwrite.


The primary advantage is that the buffer is one integer, rather
than some possibly humungous array of char. For efficiency lets
use getc/putc in place of fgetc/fputc. The run-time is probably
able to optimize buffers much better than you can.
No need to think about nul bytes, cr, lf, tabs, whatever.
What code do you see that DOES force one to think about nul bytes,
cr, lf, tabs, etc?


For this particular usage, none.
A few more benefits: If it fails (with n non-negative) the values
in ch, n, and ferror allow you to diagnose things fairly well.
You don't need to think about buffer sizes. Odds are high that
the above will be more efficient than the buffered version on many
implementations.


I doubt it'll often matter, and your implementation isn't nearly as
much slower as many people expect, but I've yet to see an
implementation with which it's really as fast as using fread and
fwrite to work in big chunks. In theory I can see reasons it
_could_ be, but I've yet to actually see it in reality.


When you get to embedded systems and minimum load modules, the
difference may really show up. Any code inefficiencies are almost
certainly lost in the actual i/o time.

--
Chuck F (cb********@yahoo.com) (cb********@worldnet.att.net)
Available for consulting/temporary embedded and systems.
<http://cbfalconer.home.att.net> USE worldnet address!
Nov 14 '05 #50

51 Replies

This discussion thread is closed

Replies have been disabled for this discussion.