0

Both display 23. But what is the difference between the two?

code-1

main()
{
    int *ar[10];

    **(ar+0) = 23;
    printf( "%d", **(ar+0) );

    return 0;
}

Code-2

main()
{
    int *ar[10];

    *(ar+0) = (int*) malloc(sizeof(int));
    **(ar+0) = 23;   
    printf( "%d", **(ar+0) );

    return 0;
}
Kiril Kirov
  • 37,467
  • 22
  • 115
  • 187
Dave Black
  • 65
  • 8
  • 1
    Nice homework question ;) – blue Apr 01 '14 at 13:31
  • 1
    In first code `**(ar+0) = 23;` call [undefined behaviour](http://en.wikipedia.org/wiki/Undefined_behavior) – Grijesh Chauhan Apr 01 '14 at 13:31
  • What do you think? What happens when you run them? Why do you think one of them potentially causes your computer to crash & burn? – Lundin Apr 01 '14 at 13:33
  • Not homework..just me bro ;) – Dave Black Apr 01 '14 at 13:33
  • Instead of `ar+0`, write `ar[0]`. – mic_e Apr 01 '14 at 13:34
  • Actually, in Win8.1 console, both assignments work. – Dave Black Apr 01 '14 at 13:34
  • possible duplicate of [Why does a program accessing illegal pointer to pointer not crash?](http://stackoverflow.com/questions/17852212/why-does-a-program-accessing-illegal-pointer-to-pointer-not-crash) – ElmoVanKielmo Apr 01 '14 at 13:38
  • 1
    The Windows 8.1 console has absolutely nothing to do with it, and the behaviour of the first snippet is most definitely undefined. It is perfectly valid `C++` behaviour if the program uploads your harddrive contents to the internet in the background. While circumventing your firewall. – mic_e Apr 01 '14 at 13:39
  • k. thx for all the answers guys. :) – Dave Black Apr 01 '14 at 13:45
  • The proposed duplicate question (Why does a program accessing illegal pointer to pointer not crash) is not a good duplicate; it is dealing with an initialized pointer, not an unininitialized pointer. – Jonathan Leffler Apr 01 '14 at 14:27

3 Answers3

3
int *ar[10];
**(ar+0) = 23;

This is undefined behavior (you assign 23 to some "random" memory) because you don't have allocated space for this 23 int element (ar is array of pointers).


int *ar[10]; (ar+0) = (int) malloc(sizeof(int)); printf( "%d", **(ar+0) );

Allocates memory for an int at the first ar element, but should print "garbage", as this int is not initialized.

As the question was edited and the initialization is added: the second version is perfectly fine (if malloc succeeds).


*(ar+0) is the same as ar[ 0 ]

Kiril Kirov
  • 37,467
  • 22
  • 115
  • 187
  • please update your answer -- the question has been updated in an incompatible way. – mic_e Apr 01 '14 at 14:09
  • 1
    Note: The implementation is only file if the `malloc()` succeeds. – mic_e Apr 01 '14 at 14:15
  • Ok, so just to be perfectly clear...my book is showing me a (*int) cast for malloc. Is this really not good practice? Is it a C version difference? say, ANSI C vs C99 or something? – Dave Black Apr 01 '14 at 14:17
  • @DaveBlack - sorry, I'm not sure about this one, I've (almost) never used `malloc`, as I use `C++` primary. You could as unwind for this and try to understand the link, he quoted. – Kiril Kirov Apr 01 '14 at 14:23
  • 1
    @Kiril - Yeah, thx. I peeked around and got the answer. Thx again. – Dave Black Apr 01 '14 at 14:25
1

The first one is undefined behavior. It defines a to be an array of 10 pointers to integers, but doesn't initialize the pointers before using the first one (a[0]) in a write. This is undefined behavior.

The second one first sets the pointer to the return value of malloc() (with a really bad cast) so it has a better chance of not invoking UB. Of course, if the allocation fails and returns NULL, it's undefined behavior all over again.

Community
  • 1
  • 1
unwind
  • 391,730
  • 64
  • 469
  • 606
  • IS this better?: main() { int *ar[10]; ar[0] = malloc(sizeof(int)); *ar[0] = 5; printf( "%d", *ar[0] ); return 0; } – Dave Black Apr 01 '14 at 13:40
  • 1
    @DaveBlack Did you click the link, to read about casting `malloc()`'s return value? No, I don't think it's acceptable. And yes, the variant without the cast is of course better. It'd be even better to have `ar[0] = malloc(sizeof *ar[0]);` to remove the repeat of the type. Also, one seldom really allocates that little memory. – unwind Apr 01 '14 at 13:44
  • Yes, I read it. TY. I am learning from 'Understanding and Using C Pointers' by Oreilly. Their example used the (int*) cast. – Dave Black Apr 01 '14 at 13:51
0

Both samples first specify an array of ten integer pointers.

The first sample then goes on to write to a value to the first pointer -- without even allocating it. This is undefined behaviour and will most likely segfault.

The second sample allocates memory for the first pointer, and then writes a value there. It is has perfectly defined behaviour. That is, If the malloc() succeeds, which you need to check.

mic_e
  • 5,594
  • 4
  • 34
  • 49