Array of structs with strings

G

goodTweetieBird

In C I have seen the idiom

char *name = "Tweety";

and have been assured that it is legit. However I have doubts about
the string assignments in the example below I found on the net. Are
these string assignments valid?

Thanks

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#include <stdio.h>

typedef struct robot ROBOT;

struct robot {
char *name;
int energy;
};

int main() {
int i;

ROBOT robots[3];

robots[0].name = "Lunar Lee";
robots[0].energy = 50;
robots[1].name = "Planetary Pete";
robots[1].energy = 20;

....
 
E

Eric Sosman

goodTweetieBird said:
In C I have seen the idiom

char *name = "Tweety";

and have been assured that it is legit. However I have doubts about
the string assignments in the example below I found on the net. Are
these string assignments valid?

Thanks

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#include <stdio.h>

typedef struct robot ROBOT;

struct robot {
char *name;
int energy;
};

int main() {
int i;

ROBOT robots[3];

robots[0].name = "Lunar Lee";
robots[0].energy = 50;
robots[1].name = "Planetary Pete";
robots[1].energy = 20;

Yes, they are valid. `robots[n].name' is a char*
(for n == 0,1,2), just as `name' is, so anything you
can do with `name' can also be done with `robots[n].name'.
 
G

goodTweetieBird

Yes, they are valid. `robots[n].name' is a char*
(for n == 0,1,2), just as `name' is, so anything you
can do with `name' can also be done with `robots[n].name'.

Thanks for posting but I do not see how it can be valid.
robots[0].name is only a pointer which I thought meant that it is a
few bytes in length. Seems it would soon be writing in unknown areas.

gtb
 
R

rpgfan3233

     Yes, they are valid.  `robots[n].name' is a char*
(for n == 0,1,2), just as `name' is, so anything you
can do with `name' can also be done with `robots[n].name'.

Thanks for posting but I do not see how it can be valid.
robots[0].name is only a pointer which I thought meant that it is a
few bytes in length. Seems it would soon be writing in unknown areas.

gtb

That's very true. Try taking some rather long input and storing it in
robots[0].name. That way, even the best of compilers can't guess how
much memory should be allocated for robots[0].name to allow for
robots[1].name and robots[2].name. After that, output it, and you can
usually find that robots[1].name and robots[2].name are overwritten.

This is the reason for the malloc() function found in <stdlib.h> -
dynamic memory allocation. You don't know how long it is supposed to
be when you code, so you leave it as a char pointer, which can be
thought of as an array of undeclared length. At run-time, you find out
how long it is supposed to be and you use malloc() to allocate enough
space for the string. When you are done with it, you then free() it.
One very important thing to remember is to use free() to deallocate
the memory when you're finished with the string. Otherwise, you can
end up with a memory leak. The same is true for the calloc() and
realloc() functions - free() them when you're done!
 
G

goodTweetieBird

That's very true. Try taking some rather long input and storing it in
robots[0].name. That way, even the best of compilers can't guess how
much memory should be allocated for robots[0].name to allow for
robots[1].name and robots[2].name. After that, output it, and you can
usually find that robots[1].name and robots[2].name are overwritten.

This is the reason for the malloc() function found in <stdlib.h> -
dynamic memory allocation. You don't know how long it is supposed to
be when you code, so you leave it as a char pointer, which can be
thought of as an array of undeclared length. At run-time, you find out
how long it is supposed to be and you use malloc() to allocate enough
space for the string. When you are done with it, you then free() it.
One very important thing to remember is to use free() to deallocate
the memory when you're finished with the string. Otherwise, you can
end up with a memory leak. The same is true for the calloc() and
realloc() functions - free() them when you're done!

Sounds like a source of subtle errors.

Thanx,

gtb
 
E

Eric Sosman

goodTweetieBird said:
Yes, they are valid. `robots[n].name' is a char*
(for n == 0,1,2), just as `name' is, so anything you
can do with `name' can also be done with `robots[n].name'.

Thanks for posting but I do not see how it can be valid.
robots[0].name is only a pointer which I thought meant that it is a
few bytes in length. Seems it would soon be writing in unknown areas.

robots[0].name is a pointer, a char* that can point to
any char anywhere. That char may be the first of a string
of any length whatever; the char* just points to the first
char of the string. It makes no difference how long the
string is; the char* just points to its beginning.

char *name1 = "Peter";
char *name2 = "Linus";
char *name3 = "Anacletus";
char *name4 = "Clement I";
char *name5 = "Evaristus";
...

It doesn't matter how long the string themselves are; the
pointers work the same way anyhow. The pointer name1 points
to P, name2 points to L, and so on, regardless of what comes
after those pointed-to chars.
 
S

santosh

rpgfan3233 said:
Yes, they are valid.  `robots[n].name' is a char*
(for n == 0,1,2), just as `name' is, so anything you
can do with `name' can also be done with `robots[n].name'.

Thanks for posting but I do not see how it can be valid.
robots[0].name is only a pointer which I thought meant that it is a
few bytes in length. Seems it would soon be writing in unknown areas.

gtb

That's very true. Try taking some rather long input and storing it in
robots[0].name. That way, even the best of compilers can't guess how
much memory should be allocated for robots[0].name to allow for
robots[1].name and robots[2].name. After that, output it, and you can
usually find that robots[1].name and robots[2].name are overwritten.

This is false. robots[n].name are all of type char *. They can point to
the start of a char or an array of char. In C the construct "whatever"
is called a "string literal". What it does is effectively tell the
compiler to set aside some unnamed array of char big enough to hold the
string "whatever" and a terminating null character. The string literal
in an expression context evaluates to a value of type char *, which is
what you are assigning to robots[n].name. Storage is automatically
allocated for the string literals elsewhere and no memory overwrite
takes place.
This is the reason for the malloc() function found in <stdlib.h> -
dynamic memory allocation. You don't know how long it is supposed to
be when you code,

In the case of a string literal, you do.
so you leave it as a char pointer, which can be
thought of as an array of undeclared length.
No.

At run-time, you find out
how long it is supposed to be and you use malloc() to allocate enough
space for the string. When you are done with it, you then free() it.
One very important thing to remember is to use free() to deallocate
the memory when you're finished with the string. Otherwise, you can
end up with a memory leak. The same is true for the calloc() and
realloc() functions - free() them when you're done!

You cannot "free" the space taken by a string literal. However not all
strings are string literals. The following are valid constructs:

char *str = "hello";
char arr[] = "hello";
char arr1[2] = "hello";
char arr2[10] = "hello";
char *ptr = malloc(strlen("hello") + 1);
if (ptr) strcpy(ptr, "hello");
else error();

This is where a memory overwrite occurs:

char *ptr;
strcpy(ptr, "hello");
 
C

CBFalconer

Eric said:
goodTweetieBird said:
In C I have seen the idiom

char *name = "Tweety";

and have been assured that it is legit. However I have doubts about
the string assignments in the example below I found on the net. Are
these string assignments valid?

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#include <stdio.h>

typedef struct robot ROBOT;

struct robot {
char *name;
int energy;
};

int main() {
int i;

ROBOT robots[3];

robots[0].name = "Lunar Lee";
robots[0].energy = 50;
robots[1].name = "Planetary Pete";
robots[1].energy = 20;

Yes, they are valid. `robots[n].name' is a char*
(for n == 0,1,2), just as `name' is, so anything you
can do with `name' can also be done with `robots[n].name'.

You have set the pointer for name to point to a non-writable
constant char. string. So you can't diddle the names. They are
just there. However, you can replace them.
 
C

CBFalconer

santosh said:
.... snip ...

This is where a memory overwrite occurs:

char *ptr;
strcpy(ptr, "hello");

No it doesn't. It just blows up, because ptr was never initialized.
 
K

Keith Thompson

goodTweetieBird said:
In C I have seen the idiom

char *name = "Tweety";

and have been assured that it is legit. However I have doubts about
the string assignments in the example below I found on the net. Are
these string assignments valid?

Thanks

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#include <stdio.h>

typedef struct robot ROBOT;

struct robot {
char *name;
int energy;
};

int main() {
int i;

ROBOT robots[3];

robots[0].name = "Lunar Lee";
robots[0].energy = 50;
robots[1].name = "Planetary Pete";
robots[1].energy = 20;

...

Yes.

The comp.lang.c FAQ is at <http://www.c-faq.com/>. See question 1.32
and all of section 6.
 
R

Richard Heathfield

CBFalconer said:
No it doesn't. It just blows up, because ptr was never initialized.

The behaviour is undefined. What santosh said is not unreasonable. In any
case, you describe symptoms, whereas santosh is talking about causes.
 
B

Ben Bacarisse

goodTweetieBird said:
That's very true. Try taking some rather long input and storing it in
robots[0].name. That way, even the best of compilers can't guess how
much memory should be allocated for robots[0].name to allow for
robots[1].name and robots[2].name. After that, output it, and you can
usually find that robots[1].name and robots[2].name are overwritten.
Sounds like a source of subtle errors.

No, you have been misinformed. Please read the other posts carefully.
If you don't understand, ask some more (and read the comp.lang.c FAQ
at http://c-faq.com/).
 
J

Jack Klein

Eric said:
goodTweetieBird said:
In C I have seen the idiom

char *name = "Tweety";

and have been assured that it is legit. However I have doubts about
the string assignments in the example below I found on the net. Are
these string assignments valid?

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#include <stdio.h>

typedef struct robot ROBOT;

struct robot {
char *name;
int energy;
};

int main() {
int i;

ROBOT robots[3];

robots[0].name = "Lunar Lee";
robots[0].energy = 50;
robots[1].name = "Planetary Pete";
robots[1].energy = 20;

Yes, they are valid. `robots[n].name' is a char*
(for n == 0,1,2), just as `name' is, so anything you
can do with `name' can also be done with `robots[n].name'.

You have set the pointer for name to point to a non-writable
constant char. string. So you can't diddle the names. They are
just there. However, you can replace them.

Correction, you have set the pointer for name to point to a string
literal, which is an unnamed array of char (NOT "const char"). Any
attempt to modify a string literal because the C standard specifically
states it does, NOT because it is const qualified.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://c-faq.com/
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.club.cc.cmu.edu/~ajo/docs/FAQ-acllc.html
 
C

CBFalconer

Jack said:
CBFalconer said:
Eric said:
goodTweetieBird wrote:

In C I have seen the idiom

char *name = "Tweety";

and have been assured that it is legit. However I have doubts about
the string assignments in the example below I found on the net. Are
these string assignments valid?

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#include <stdio.h>

typedef struct robot ROBOT;

struct robot {
char *name;
int energy;
};

int main() {
int i;

ROBOT robots[3];

robots[0].name = "Lunar Lee";
robots[0].energy = 50;
robots[1].name = "Planetary Pete";
robots[1].energy = 20;

Yes, they are valid. `robots[n].name' is a char*
(for n == 0,1,2), just as `name' is, so anything you
can do with `name' can also be done with `robots[n].name'.

You have set the pointer for name to point to a non-writable
constant char. string. So you can't diddle the names. They
are just there. However, you can replace them.

Correction, you have set the pointer for name to point to a
string literal, which is an unnamed array of char (NOT "const
char"). Any attempt to modify a string literal because the C
standard specifically states it does, NOT because it is const
qualified.

I didn't say const. I wrote 'constant'. Do you deny that the
pointers are to constant strings?
 
A

Andrey Tarasevich

goodTweetieBird said:
In C I have seen the idiom

char *name = "Tweety";

and have been assured that it is legit.

It is legit. However, the practice of pointing to non-modifiable data
with a non-const-qualified pointer in normally frowned upon, unless you
have a good reason to do so. Without such a good reason it should be

const char *name = "Tweety";
However I have doubts about
the string assignments in the example below I found on the net. Are
these string assignments valid?
...
robots[0].name = "Lunar Lee";
...

Er... Well, they are not in any way different from your first example.
Which brings the question of why you are even asking?
 

Ask a Question

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

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

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top