Array and Pointer Tutorial

I

Ian Collins

Chad said:
Hmmm... It looks like got a response before I could correct the grammar
errors in my previous post. Anyhow, I think I managed to pinpoint what
is irking me.

Say I have the following:

/*I omitted checking malloc() for NULL and forgot to use free()*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void) {
char *p = malloc(sizeof *p);
/* incomplete -- malloc's return value not checked */
strcpy(p, "Hello, world!");
Bang! sizeof *p == sizeof char == 1.
return 0;
}

Are you saying that the construction
char *p = malloc(sizeof *p);

would allocate enough space to hold the string ""Hello, world!" versus
allocating memory to hold just one char?
The answer has to be 1.
 
P

pemo

Chad said:
Hmmm... It looks like got a response before I could correct the
grammar errors in my previous post. Anyhow, I think I managed to
pinpoint what is irking me.

Say I have the following:

/*I omitted checking malloc() for NULL and forgot to use free()*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void) {
char *p = malloc(sizeof *p);
/* incomplete -- malloc's return value not checked */
strcpy(p, "Hello, world!");

return 0;
}

Are you saying that the construction
char *p = malloc(sizeof *p);

would allocate enough space to hold the string ""Hello, world!" versus
allocating memory to hold just one char?


As p points to a char, *p is a char, so sizeof *p is 1 [*but* no dereference
is actually performed].

The point being made is, say you have this ...

char *p = malloc(sizeof char);

but later change the *p to this ...

int *p = malloc(sizeof char);

You have an error here, as char is still used with sizeof.


However, if you have this ...

char *p = malloc(sizeof *p);

but later change it to this ...

int *p = malloc(sizeof *p);

things are ok, and the sun still rises every day.
 
F

Flash Gordon

Please snip peoples sigs (the bit usually after a '-- ') unless you are
commenting on them.
Hmmm... It looks like got a response before I could correct the grammar
errors in my previous post. Anyhow, I think I managed to pinpoint what
is irking me.

Say I have the following:

/*I omitted checking malloc() for NULL and forgot to use free()*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void) {
char *p = malloc(sizeof *p);
/* incomplete -- malloc's return value not checked */
strcpy(p, "Hello, world!");

return 0;
}

Are you saying that the construction
char *p = malloc(sizeof *p);

would allocate enough space to hold the string ""Hello, world!" versus
allocating memory to hold just one char?

No, because p is not of type 'pointer to "Hello, world'". Remember that
a string is an array of char, not a single char. C does not have a
string type.
 
R

Richard Heathfield

Chad said:
Are you saying that the construction
char *p = malloc(sizeof *p);

would allocate enough space to hold the string ""Hello, world!"

Which letter of 'n' were you struggling with?
 
P

pete

Richard said:
Chad said:

He said "for n objects of type T"
Which letter of 'n' were you struggling with?

I generally consider three different malloc situations:

1 "n objects of type T"
T *p = malloc(n * sizeof *p);
T *p = malloc(sizeof *p); /* when n == 1 */

2 string
char *p = malloc(length + 1);
char *p = malloc(sizeof "string_literal");

3 pointer to type void
void *p = malloc(sizeof object_identifier);

p = malloc(sizeof car);
*(struct vehicle *)p = car;
 
C

Chad

pete said:
He said "for n objects of type T"


I generally consider three different malloc situations:

1 "n objects of type T"
T *p = malloc(n * sizeof *p);
T *p = malloc(sizeof *p); /* when n == 1 */

2 string
char *p = malloc(length + 1);
char *p = malloc(sizeof "string_literal");

3 pointer to type void
void *p = malloc(sizeof object_identifier);

p = malloc(sizeof car);
*(struct vehicle *)p = car;

The statement "for n objects of type T" didn't immediately register in
my snoodle. Anyhow after sleeping for 3 hours and re-reading the post,
the entire thing makes sense.

Chad
 
C

Chad

pete said:
He said "for n objects of type T"


I generally consider three different malloc situations:

1 "n objects of type T"
T *p = malloc(n * sizeof *p);
T *p = malloc(sizeof *p); /* when n == 1 */

2 string
char *p = malloc(length + 1);
char *p = malloc(sizeof "string_literal");

3 pointer to type void
void *p = malloc(sizeof object_identifier);

p = malloc(sizeof car);
*(struct vehicle *)p = car;

The statement "for n objects of type T" didn't immediately register in
my snoodle. Anyhow after sleeping for 3 hours and re-reading the posts,
the entire thread makes sense.

Chad
 
C

CBFalconer

Tomás said:
CBFalconer posted:
"array[0]" is the same as "*(array+0)" which simplifies to "*array".

When array is passed as a parameter, which this one isn't.

Stop trolling and propogating misinformation.

"array" implicitly converts to a pointer to its first element ALL THE
TIME -- NOT just when passed as an argument to a function, NOT just
when it's a global variable, NOT just when you have porridge instead
of cereal.

You are woefully misinformed. Try:

#include <stdio.h>

int a[5];

int main(void)
{
printf("*a=%lu\n", (unsigned long)sizeof(*a));
printf(" a=%lu\n", (unsigned long)sizeof(a));
return 0;
}

/* expected output on my system:
*a=4
a=20
*/

--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson
More details at: <http://cfaj.freeshell.org/google/>
Also see <http://www.safalra.com/special/googlegroupsreply/>
 
R

Rod Pemberton

Richard Heathfield said:
Chad said:

The canonical way to allocate space for n objects of type T is:

T *p = malloc(n * sizeof *p);

or, if p is already declared, simply this:

p = malloc(n * sizeof *p);

The reason this is the canonical way is that it doesn't rely on the type of
p, except that it must be an object type, not an incomplete type or
function type. If the type of p changes during maintenance, you don't have
to hunt down this line and hack it about. It will automagically work
correctly with the new type.

You should point out the negatives too. If p is already declared, and their
is no comment telling him what file p is declared in. He'll spend forever
trying to answer this question: "What the HELL is p?"

p = malloc(n * sizeof *p); /* p orignially was of type T and declared in
file somedecl.h */


Rod Pemberton
 
R

Richard Heathfield

Rod Pemberton said:
You should point out the negatives too. If p is already declared, and
their
is no comment telling him what file p is declared in. He'll spend forever
trying to answer this question: "What the HELL is p?"

Oh, please try to /think/ before posting. You don't need that crutch with
all your other objects, so why on earth would you need it with objects that
you happen to be pointing at the return value of a malloc call?
 
R

Rod Pemberton

Richard Heathfield said:
Rod Pemberton said:


Oh, please try to /think/ before posting. You don't need that crutch with
all your other objects, so why on earth would you need it with objects that
you happen to be pointing at the return value of a malloc call?
You don't need that crutch with all your other objects

True. But, I wrote the code.
so why on earth would you need it with objects that
you happen to be pointing at the return value of a
malloc call?

Because, you mentioned _maintenance_ of code which the OP likely didn't
write:
RH: "If the type of p changes during maintenance"

Perhaps, you should /remember/ what you wrote before declaring that I need
to /think/.


Rod Pemberton
 
F

Flash Gordon

Rod said:
True. But, I wrote the code.


Because, you mentioned _maintenance_ of code which the OP likely didn't
write:
RH: "If the type of p changes during maintenance"

Perhaps, you should /remember/ what you wrote before declaring that I need
to /think/.

That doesn't invalidate Richard's point. The maintenance programmer
doesn't normally get that for all other object types.
 
R

Richard Heathfield

Rod Pemberton said:
True. But, I wrote the code.

The same, however, is true for maintenance programmers. You don't provide
that crutch for them with other objects, so why provide it here?

Please learn to think before replying.
Because, you mentioned _maintenance_ of code which the OP likely didn't
write:
RH: "If the type of p changes during maintenance"

Perhaps, you should /remember/ what you wrote before declaring that I need
to /think/.

Oh, but I did. And the fact remains that it is inconsistent and pointless to
provide an asinine type-reminder crutch in one special circumstance when
one doesn't provide asinine type-reminder crutches in general. Your
argument falls because, if it made sense at all, it would make sense in all
situations where an object is used - which it clearly doesn't.

But no, I realise there's no point trying to get you to understand this. Be
happy, have fun, and enjoy the colour of the sky on whatever planet you
happen to be occupying right now.
 
R

Rod Pemberton

Richard Heathfield said:
Rod Pemberton said:


The same, however, is true for maintenance programmers.

Not so.
You don't provide
that crutch for them with other objects, so why provide it here?

We were talking about when the allocation and declaration were separated.
Please learn to think before replying.

Please learn to read and remember before replying.
Oh, but I did.

Yeah right...
And the fact remains that it is inconsistent and pointless to
provide an asinine type-reminder crutch in one special circumstance when
one doesn't provide asinine type-reminder crutches in general. Your
argument falls because, if it made sense at all, it would make sense in all
situations where an object is used - which it clearly doesn't.

The argument makes sense. Have you ever programmed? In C? Have you ever
written 500 thousand plus lines of code for the same application? Have you
ever worked on a 3 million plus line program? Have you ever had to deal
with 500+ _identical_ if statements because some maintenance progarmmer 15
years earlier decided not to write a procedure and all others who followed
did the same? I have. I know what I'm talking about. Your inaccurate
perception and downplaying of this issue as triviality is ludicrous.


Rod Pemberton
 
K

Keith Thompson

CBFalconer said:
Charles said:
CBFalconer said:
Chad wrote:

... snip ...

Okay, I'm probably missing this. But say I have the following:

/*I omitted checking for NULL and using free*/

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

int main(void) {
int array[5];

int *q = malloc(sizeof *array);

There is no such thing as *array. array is an array of 5 integers,
not a pointer.

"array[0]" is the same as "*(array+0)" which simplifies to "*array".

When array is passed as a parameter, which this one isn't.

Sorry, you've blown this one.

An expression of array type is implicitly converted to a pointer to its
first element *unless*:
It's the operand of a sizeof operator, or
It's the operand of a unary "&" operator, or
It's a string literal used to initialize an array.

Passing it as a parameter is irrelevant.

The behavior of any one implementation doesn't prove anything, but
this works:

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

int main(void)
{
int array[5];
double another_array[10];
size_t s1 = sizeof *array;
size_t s2 = sizeof *another_array;
printf("s1 = %d, s2 = %d\n", (int)s1, (int)s2);
return 0;
}

and prints "s1 = 4, s2 = 8" on my system (matching sizeof(int) and
sizeof(double)).
 
K

Keith Thompson

Tomás said:
CBFalconer posted:
"array[0]" is the same as "*(array+0)" which simplifies to "*array".

When array is passed as a parameter, which this one isn't.

Stop trolling and propogating misinformation.

If you've been following this newsgroup, you should know that
CBFalconer is no troll. He's made an honest mistake in this case.
It happens.
"array" implicitly converts to a pointer to its first element ALL THE TIME
-- NOT just when passed as an argument to a function, NOT just when it's a
global variable, NOT just when you have porridge instead of cereal.

Oh, look, it just happened again. (An array name is not converted to
a pointer if it's the operand of a "sizeof" or unary "&" operator.)
But even though you don't have anything like CBFalconer's reputation
here, I'm not going to assume you're a troll.
 
N

Nelu

Keith said:
CBFalconer <[email protected]> writes:
When array is passed as a parameter, which this one isn't.

Sorry, you've blown this one.

An expression of array type is implicitly converted to a pointer to its
first element *unless*:
It's the operand of a sizeof operator, or
It's the operand of a unary "&" operator, or
It's a string literal used to initialize an array.

Passing it as a parameter is irrelevant.

The behavior of any one implementation doesn't prove anything, but
this works:

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

int main(void)
{
int array[5];
double another_array[10];
size_t s1 = sizeof *array;
size_t s2 = sizeof *another_array;
printf("s1 = %d, s2 = %d\n", (int)s1, (int)s2);
return 0;
}

and prints "s1 = 4, s2 = 8" on my system (matching sizeof(int) and
sizeof(double)).

Forgive me, but I still think CBFalconer is right. I think it's more of
a discussion related to whether an array is a const pointer or it's an
rvalue which makes it an address value which is what a pointer contains
but it's not a pointer object.

The first idea may be implementation dependent. I tried it with gcc.
Let's say you have int a[10] and try a++. Now, if it were a constant
gcc would complain: increment of read only variable. In this case it
says wrong type of argument to increment. This sounds like it's not a
const pointer but just the address of the pointer (which is correct
since &a, a and &a[0] have the same value, so the pointer (&a) has the
same address as it's value (a). It can be argued that this is
implementation dependent, I guess.
The second idea is to see how it works:

1).
int a[10];
a[2]=3;

2).
int *b=malloc(10*sizeof(int));
b[2]=3;

In the first case we have the address value a, so:
Step 1: Go to positions forward from a[0]
Step 2: At the address put 3

In the second case we have:
Step 1: Get the value contained in b
Step 2: Add two positions to it
Step 3: Set the value the the address 3.

I guess it can be argued that this is also implementation dependent
since you could get the address value of a from &a (since they're
equal) but I doubt that happens.

It seems it may be that the implementation dictates the choice of words
:).

If the array is an rvalue, when passed to a function like f(int *arr),
arr will behave like a pointer in any case, independent of
implementation.
 
N

Nelu

Nelu said:
Keith Thompson wrote:
<snip>

I'm not sure how irrelevant it is. Check this code:

void foo(char b[]) {
b++;
printf("%ld\t%ld\n",sizeof(b),sizeof(char*));
}

int main(void) {
char arr[10];
foo(arr);
printf("%ld\n",sizeof(arr));

return 0;
}

It seems that this is supposed to compile on any compiler (haven't
actually compiled it on every compiler there is, but I heard about it a
long time ago). It doesn't complain when you try to increment b (as an
argument it certainly doesn't seem to be a const pointer) in foo and
sizeof(b) should be different from sizeof(arr).
 
K

Keith Thompson

Nelu said:
Nelu said:
Keith Thompson wrote:
<snip>

I'm not sure how irrelevant it is. Check this code:

void foo(char b[]) {
b++;
printf("%ld\t%ld\n",sizeof(b),sizeof(char*));
}

b is not an array; it's a pointer object. And it's not a const
object; it's merely initialized to the value of the actual argument.

In a parameter declaration, "char b[]" is merely an alias for "char *b".
This is independent of the rules for implicit conversion of array
names to pointer values.

Also, "%ld" is not the correct format for a size_t. You can use "%zu"
if your library conforms to C99, or you can convert the operand to
the expected type:
printf("%d\t%d\n", (int)sizeof b, (int)sizeof(char*));
int main(void) {
char arr[10];
foo(arr);

Here arr is converted to a pointer value, equivalent to &arr[0].
This value is passed to foo and copied to b.
printf("%ld\n",sizeof(arr));

return 0;
}
[snip]
 

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,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top