NULL?? How come??

M

mike79

Hi all,

I have a the following simple piece of code which has taken me hours
to try and sort out the problem, but still unable to find what is
wrong.

void main( void )
{
char (*string)[20]; .......................(1)

string = malloc(10 * sizeof *string); .....(2)
string[0] = NULL; .........................(3)
}

Basically, I am allocating memory to an array of strings of 20 chars
max, and setting element 0 of the array to be a NULL value.
Lines (1) to (2) work OK, but line (3) does not work. I wish to set
the string of element 0 to be a NULL value, but keeps getting an error
saying:

"left operand must be l-value"

Please help me, I dont understand what's wrong.

Thank you all in advance,
mike79
 
R

rihad

Hi all,

I have a the following simple piece of code which has taken me hours
to try and sort out the problem, but still unable to find what is
wrong.

void main( void )
{
char (*string)[20]; .......................(1)

string = malloc(10 * sizeof *string); .....(2)

/* set the first element of the array to an empty string */
if (string != NULL) {
string[0][0] = '\0';
}
Basically, I am allocating memory to an array of strings of 20 chars
max, and setting element 0 of the array to be a NULL value.
Lines (1) to (2) work OK, but line (3) does not work. I wish to set
the string of element 0 to be a NULL value, but keeps getting an error
saying:

"left operand must be l-value"

Each element of the array has type (char [20]), array of 20 chars. You can't
assign to arrays! See the corrections to your code above
 
R

Rune Flaten Værnes

I have a the following simple piece of code which has taken me hours
to try and sort out the problem, but still unable to find what is
wrong.

void main( void )
{
char (*string)[20]; .......................(1)

string = malloc(10 * sizeof *string); .....(2)
string[0] = NULL; .........................(3)
}

Try
(*string)[0] = NULL;
 
R

rihad

I have a the following simple piece of code which has taken me hours
to try and sort out the problem, but still unable to find what is
wrong.

void main( void )
{
char (*string)[20]; .......................(1)

string = malloc(10 * sizeof *string); .....(2)
string[0] = NULL; .........................(3)
}

Try
(*string)[0] = NULL;

Let's see. *string is of type (char [20]). **string (which is the same thing as
(*string)[0] and even *string[0] (in this case)) is of type (char). Why are you
assigning NULL to a char?

(as a side note, using NULL over 0 here is advantageous because the compiler
will catch the incorrect assignment (assuming NULL does not expand to just 0)
and possibly a bug in your reasoning).
 
I

Irrwahn Grausewitz

I have a the following simple piece of code which has taken me hours
to try and sort out the problem, but still unable to find what is
wrong.

Provide a correct prototype for malloc():

#include said:
void main( void )

main() always returns an int:

int main( void )
{
char (*string)[20]; .......................(1)

string = malloc(10 * sizeof *string); .....(2)

Check the return value of malloc here!
string[0] = NULL; .........................(3)

string[0] is an array to which you cannot assign directly; write:

string[0][0] = '\0';

or (after inclusion of string.h):

strcpy( string[0], "" );

to make string[0] contain an empty string.

main() always returns an int:

return 0;
}

Basically, I am allocating memory to an array of strings of 20 chars
max, and setting element 0 of the array to be a NULL value.
Lines (1) to (2) work OK, but line (3) does not work. I wish to set
the string of element 0 to be a NULL value,

As I said above, you cannot assign to an array. Assuming that you want
string[0] to contain an empty string, remember that NULL is a null
pointer constant and neither an empty string nor a null character.
but keeps getting an error
saying:

"left operand must be l-value"

Funny enough, in C99 string[0] /is/ an lvalue, yet not a modifiable one,
thus you still cannot assign to it.

HTH
Regards.
 
B

Bruno Desthuilliers

mike79 said:
Hi all,

I have a the following simple piece of code which has taken me hours
to try and sort out the problem, but still unable to find what is
wrong.

void main( void )

it's int main(void) or int main(int argc, char **argv).
{
char (*string)[20]; .......................(1)

Not an expert, but I'm not sure the above is correct (any guru out there
?).

But well, let's pretend it is and it really means what you want...
string = malloc(10 * sizeof *string); .....(2)
string[0] = NULL; .........................(3)
}

Basically, I am allocating memory to an array of strings of 20 chars
max, and setting element 0 of the array to be a NULL value.

Lines (1) to (2) work OK, but line (3) does not work. I wish to set
the string of element 0 to be a NULL value, but keeps getting an error
saying:
"left operand must be l-value"
> Please help me, I dont understand what's wrong.

<gurus, please correct me if I'm wrong>

This last line is basically the same as writing :
int main(void)
{
char str20[20];
str20 = NULL;
return 0;
}

This gives me (gcc 3.x, with -Wall -ansi -pedantic switches) :
'incompatible types in assignment'

This does not surprise me, since, while sharing some mechanisms, an
automatic array and a pointer to a dynamically allocated memory block
are two different things.

You can consider str20 as a pointer to the first element of a 20 chars
array (and yes it is, technically), but it's a 'read-only' pointer, in
the meaning that you *can not* modify the *address* it points to.

If what you want is to init each element in the 'string' array to the
empty string, you may want to have a look at calloc() or memset() :

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

int main(void)
{
char (*strings)[20];
int i;
int j;
size_t size = 10 * sizeof *strings;

strings = malloc(size);
memset(strings, 0, size);

for (i = 0; i < 10; i++) {
printf("strings[%d] : \n", i);
for (j = 0; j < 20; j++) {
printf(" '%c' ", strings[j] + '0');
}
printf("\n");
}

free(strings);
return 0;
}


Note that it *may* not be necessary (at least it *seems* not to be on
Linux with gcc 3.2.2 : commenting out the 'memset()' call doesn't seems
to change the output), but as this could be an UB, I would not rely on
this without the enlightening advices of some guru here (any guru around ?-)

HTH,
Bruno
 
B

Bruno Desthuilliers

Bruno Desthuilliers wrote:

sorry, code needed a bit correction before posting...
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main(void)
{
char (*strings)[20];
int i;
int j;
size_t size = 10 * sizeof *strings;

strings = malloc(size); if (strings != NULL) {
memset(strings, 0, size);

for (i = 0; i < 10; i++) {
printf("strings[%d] : \n", i);
for (j = 0; j < 20; j++) {
printf(" '%c' ", strings[j] + '0');
}
printf("\n");
}

free(strings);

}
else {
printf("malloc() failed \n");
}
return 0;
}

Bruno
 
I

Irrwahn Grausewitz

Bruno Desthuilliers said:
mike79 said:
char (*string)[20]; .......................(1)

Not an expert, but I'm not sure the above is correct (any guru out there
?).

Not an expert too, but if OP wants to declare a pointer to array of
20 chars: yes, it's correct.
But well, let's pretend it is and it really means what you want...
string = malloc(10 * sizeof *string); .....(2)
string[0] = NULL; .........................(3)
}

<gurus, please correct me if I'm wrong>

This last line is basically the same as writing :
int main(void)
{
char str20[20];
str20 = NULL;
return 0;
}

Not a guru, but it is similar in that in both cases an attempt is made
to assign to something that is not an (modifiable) lvalue.
This gives me (gcc 3.x, with -Wall -ansi -pedantic switches) :
'incompatible types in assignment'

This does not surprise me, since, while sharing some mechanisms, an
automatic array and a pointer to a dynamically allocated memory block
are two different things.

You can consider str20 as a pointer to the first element of a 20 chars
array (and yes it is, technically), but it's a 'read-only' pointer, in
the meaning that you *can not* modify the *address* it points to.
Yup.

If what you want is to init each element in the 'string' array to the
empty string, you may want to have a look at calloc() or memset() :

Note: the code below not only sets the strings to empty strings,
it 'zeroes' out the whole array.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main(void)
{
char (*strings)[20];
int i;
int j;
size_t size = 10 * sizeof *strings;

strings = malloc(size);

Better check the return value of malloc here.
(OK, I noticed you have already corrected this in a followup post)
memset(strings, 0, size);

for (i = 0; i < 10; i++) {
printf("strings[%d] : \n", i);
for (j = 0; j < 20; j++) {
printf(" '%c' ", strings[j] + '0');


This produces misleading output. Better write:

printf(" %d", strings[j] );
}
printf("\n");
}

free(strings);
return 0;
}


Note that it *may* not be necessary (at least it *seems* not to be on
Linux with gcc 3.2.2 : commenting out the 'memset()' call doesn't seems
to change the output), but as this could be an UB, I would not rely on
this without the enlightening advices of some guru here (any guru around ?-)

Still not a guru, but malloc just happens to have allocated some memory
that was filled with zeros coincidentally. Relying on this is calling
for nasal demons (aka undefined behaviour).

HTH
Regards
 
T

TheDruid

Hi mike79.

I am french so my English isn't good. First, I don't understand what
this code means. Can you tell me what is your workstation. I am using
Linux and gcc.
Your code doesn't compile on my box. The error is "incompatible types
assignment in (3)". Tell me what you want to do, maybe I can help you
 
N

Nick Keighley

I have a the following simple piece of code which has taken me hours
to try and sort out the problem, but still unable to find what is
wrong.

I think you're confused (or I'm confused!)
void main( void )

int main (void)

main() returns an int. Always.
{
char (*string)[20]; .......................(1)

this doesn't mean what you think it means (I think).

string is a ptr-to-array-of-char

it's pretty unusual to use ptrs-to-array (they give me a headache).

did you mean
char *string [20];

ie. array-of-ptr-to-char

or what people normally call an array of strings
string = malloc(10 * sizeof *string); .....(2)

well if you meant ptr-to-array
string = malloc (sizeof *string);

and if you meant array-of-ptr (array of strings)
string [0] = malloc (10 * sizeof *(string [0]);
string[0] = NULL; .........................(3)

if you meant a single pointer to an array
(*string) = '\0'; /* don't use NULL here */

if you meant an array of strings
string [0] = NULL; /* first string is empty */

or
string [0][0] = '\0'; /* first string is zero length */

I'm bound to have got one of these wrong...
}

Basically, I am allocating memory to an array of strings of 20 chars
max,

that sounds like an array-of-ptr-to-char but this doesn't limit the
string length.
and setting element 0 of the array to be a NULL value.

element 0 of the array or element 0 of the first string?
Lines (1) to (2) work OK, but line (3) does not work. I wish to set
the string of element 0 to be a NULL value, but keeps getting an error
saying:

"left operand must be l-value"

Please help me, I dont understand what's wrong.

If you still don't understand (or I mis-explained) K&R is pretty good
on pointers and C declarations.


--
Nick Keighley

It's probably not the quickest method around,
but it uses plenty of trees, and that's what counts.
Richard Heathfield
 
B

Bruno Desthuilliers

Irrwahn said:
Note: the code below not only sets the strings to empty strings,
it 'zeroes' out the whole array.

Yeps. But the result is technically the same, or IMHO even better since
you're sure to not have garbage trailing in the strings (my 2 cents...).

Or am I wrong ?

(snip code)
Still not a guru, but malloc just happens to have allocated some memory
that was filled with zeros coincidentally. Relying on this is calling
for nasal demons (aka undefined behaviour).

Yeps, I guessed it may not be defined behavior (hence my advice not to
rely on this).

Bruno
 
D

Dan Pop

In said:
I have a the following simple piece of code which has taken me hours
to try and sort out the problem, but still unable to find what is
wrong.

void main( void )
^^^^
You should have read the FAQ *before* posting!
{
char (*string)[20]; .......................(1)

What do you think string (as declared above) is?
string = malloc(10 * sizeof *string); .....(2)
string[0] = NULL; .........................(3)

What do you get by dereferencing string? Is it a modifiable lvalue?
}

Basically, I am allocating memory to an array of strings of 20 chars
max, and setting element 0 of the array to be a NULL value.
Lines (1) to (2) work OK, but line (3) does not work. I wish to set
the string of element 0 to be a NULL value, but keeps getting an error
saying:

"left operand must be l-value"

Please help me, I dont understand what's wrong.

Do NOT declare and use pointers to arrays until you understand what they
really are and how they really work.

string[0] is an array of 20 char's, you can't assign anything to it.

Try to use an array of pointers instead. It's a much easier to grasp
concept, in C.

Dan
 
I

Irrwahn Grausewitz

Bruno Desthuilliers said:
Yeps. But the result is technically the same,

Right, I just found it worth mentioning, for the sake of completeness.
or IMHO even better since
you're sure to not have garbage trailing in the strings (my 2 cents...).

An array filled with zeros is a "even more empty" string? ;-))
Or am I wrong ?

Nope.
(snip code)

Yeps, I guessed it may not be defined behavior (hence my advice not to
rely on this).

And you were dead on.
 
M

Minti

Hi all,

I have a the following simple piece of code which has taken me hours
to try and sort out the problem, but still unable to find what is
wrong.

void main( void )
^^^^^^^^^^^^^

What is the above void doing here. Don't you think your program must
returing some thank you note to the OS for doing it's job.
{
char (*string)[20]; .......................(1)

string = malloc(10 * sizeof *string); .....(2)
^^^^^^

Again you are not expressive enough. Albeit here for the compiler, you
are not telling it to include <stdblib.h> which has the prototype for
the malloc.


string[0] = NULL; .........................(3)
}

Basically, I am allocating memory to an array of strings of 20 chars
max, and setting element 0 of the array to be a NULL value.
Lines (1) to (2) work OK, but line (3) does not work. I wish to set
the string of element 0 to be a NULL value, but keeps getting an error
saying:

"left operand must be l-value"

Please help me, I dont understand what's wrong.

The problem is again in expression you are not expressing what you
want when you write

char (*str) [20];

You are declaring a single pointer not an array of pointers, here str
is pointer to an "array" of 20 characters.

so (*str) is effectively is an array of 20 characters. You can't
modify an array which is a l-value.


ITYM

char (*str)[20];

HTH
 
J

John Bode

Hi all,

I have a the following simple piece of code which has taken me hours
to try and sort out the problem, but still unable to find what is
wrong.

void main( void )

int main (void) /* main always returns int */
{
char (*string)[20]; .......................(1)

This doesn't do what you think it does. You are declaring a pointer
to a single 20-element array of char.

Here's a handy chart that may help:

char h; /* h is a single char */
char *h; /* h is a pointer to char */
char **h; /* h is a pointer to a pointer to char */
char h[N]; /* h is an N-element array of char */
char *h[N]; /* h is an N-element array of pointers to
char */
char **h[N]; /* h is an N-element array of pointers to
pointers to char */
char (*h)[N]; /* h is a pointer to an N-element array of
char */
char h[M][N]; /* h is an M-element array of N-element
arrays of char */
char *h[M][N]; /* h is an M-element array of N-element
arrays of pointers to char */
char (*h)[M][N]; /* h is a pointer to an M-element array
of N-element arrays of char */
char *(*h)[M][N]; /* h is a pointer to an M-element array
of N-element arrays of pointers to char
*/
char (*h[M])[N]; /* h is an M-element array of pointers
to N-element arrays of char */
char *(*h[M])[N]; /* h is an M-element array of pointers
to N-element arrays of pointer to char
*/
char (**h)[N]; /* h is a pointer to a pointer to an
N-element array of char */

....and then it starts getting ugly, but I think you can work out the
pattern from there.

To do what you want to do, you don't want to mess with pointers to
arrays. Trust me. There's a reason they aren't used much.

Here's a method that's 70% less headache-inducing:

#include <stdlib.h>

#define STRSIZE 20
#define ARRSIZE 10

int main (void)
{
char **p; /* p will become an array of pointers to char */

int i;

/*
** allocate a block of memory big enough to hold 10 pointers to
char,
** assign the address to p.
*/
p = malloc (ARRSIZE * sizeof *p)

if (p)
{
/*
** allocate the individual 20-element arrays of char, assign
each
** address to p
*/
p[0] = NULL; /* make the first array element NULL */
for (i = 1; i < ARRSIZE; i++)
{
p = malloc (sizeof **p * STRSIZE);
}
}

return 0;
}

Of course, this doesn't guarantee that all the memory is contiguous.
If that's a requirement, you'll have to do something else. Personally
I'd allocate a single huge block of ARRSIZE * STRSIZE characters, and
set up a separate array of pointers into it:

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

#define STRSIZE 20
#define ARRSIZE 10

int main (void)
{
char *p; /* single big array of bytes */
char *h[ARRSIZE]; /* array of pointers into p */

p = malloc (STRSIZE * ARRSIZE * sizeof *p);
if (p)
{
int i;
h[0] = NULL;
for (i = 1; i < arrsize; i++)
{
/*
** get the address of each 20-element substring in p,
assign
** to h; h[1] = &p[20], h[2] = &p[40], etc.
*/
h = &p[i*STRSIZE];
}
}

return 0;
}

It looks ugly, but it's still less of a pain in the ass than dealing
with pointers to arrays.
string = malloc(10 * sizeof *string); .....(2)
string[0] = NULL; .........................(3)
}

Basically, I am allocating memory to an array of strings of 20 chars
max, and setting element 0 of the array to be a NULL value.
Lines (1) to (2) work OK, but line (3) does not work. I wish to set
the string of element 0 to be a NULL value, but keeps getting an error
saying:

"left operand must be l-value"

This is going to be a bit twisted, and I'll probably botch it, but
here goes.

Remember that you have declared string as a pointer to a 20-element
array of char. Remember that the subscript expression a is
evaluated as *(a + i); the type of that expression is the base type of
a. IOW, string[0] is evaluated as *(string + 0), or just *string, and
the type of *string is 20-element array of char.

An object of array type may not appear on the left-hand side of an
assignment expression, which is why you got the error above. It's the
equivalent of writing

int a[10];
a = NULL;

Such an operation is not allowed in C. Array objects cannot be
assigned to.

Yet another reason why you don't want to use pointers to arrays. In
almost 15 years of writing code professionally I've never had occasion
to use them. I'm sure they're useful in some obscure context, but I
haven't found it yet.
 
A

Al Bowers

John said:
#include <stdio.h>
#include <stdlib.h>

#define STRSIZE 20
#define ARRSIZE 10

int main (void)
{
char *p; /* single big array of bytes */
char *h[ARRSIZE]; /* array of pointers into p */

p = malloc (STRSIZE * ARRSIZE * sizeof *p);
if (p)
{
int i;
h[0] = NULL;
Why are you assigning h[0] NULL?
This would be a disaster if you then do something like:
strcpy(h[0],"Hello World");
for (i = 1; i < arrsize; i++)
{
/*
** get the address of each 20-element substring in p,
assign
** to h; h[1] = &p[20], h[2] = &p[40], etc.
*/
h = &p[i*STRSIZE];
}
}

return 0;
}


I think what you are getting at is this:

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

#define STRSIZE 20
#define ARRSIZE 10

int main (void)
{
char **p;
int i;

if((p = malloc(ARRSIZE*(sizeof *p))) == NULL) return EXIT_FAILURE;
if((*p = malloc(ARRSIZE * STRSIZE *(sizeof **p))) == NULL)
{
free(p);
return EXIT_FAILURE;
}
for(i = 1; i < ARRSIZE;i++) p = *p+(i*STRSIZE);
strcpy(p[0], "Abe Lincoln");
strcpy(p[1], "George Washington");
strcpy(p[2], "George Bush");
/* On and on to assign the full array of 10 char *'s */
puts(p[0]);
puts(p[1]);
puts(p[2]);
/* And to free */
free(*p);
free(p);
return EXIT_SUCCESS;
}
 
B

Bruno Desthuilliers

Irrwahn said:
Right, I just found it worth mentioning, for the sake of completeness.
Right.



An array filled with zeros is a "even more empty" string? ;-))

Lol !-)

Bruno
 

Ask a Question

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

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

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,094
Messages
2,570,615
Members
47,231
Latest member
Satyam

Latest Threads

Top