tags:

views:

286

answers:

6

I have more than one doubt so please bear with me. Can someone tell me why this code fails?

#include<stdio.h>
void main(int argc,char **argv) /*assume program called with arguments aaa bbb ccc*/
{
    char **list={"aaa","bbb","ccc"};

    printf("%s",argv[1]);/*prints aaa*/
    printf("%s",list[1]); /*fails*/ 
}

I assumed it had something to do with the pointer to pointer stuff, which i do not understand clearly. So i tried:

#include<stdio.h>
void main()
{
char **list={"aaa","bbb","ccc"};
char *ptr;
ptr=list;
printf("%s",ptr);/*this prints the first string aaa*/
    /* My second question is how do i increment the value
       of ptr so that it points to the second string bbb*/
}

What is the difference between char *list[] and char **list and in what situations are both ideal to be used? One more thing confusing me is argv special? when i pass char **list to another function assuming it would let me access the contents the way i could with argv, it also failed.

I realize similar questions have been asked in the past, but i cant seem to find what i need. if so can someone please post the relevant links.

+1  A: 

You might take a look at the accepted answer here.

Amber
+2  A: 

char **x points to an array of char pointers, however this may not be how your compiler stores {"aaa","bbb","ccc"} in memory. char *x[] will cause the correct code to be generated no matter how the compiler stores an array of pointers.

Mick Sharpe
yes i was getting garbage values when i tried working on the assumption that three strings were stored continuously. thank you for clearing that up.
Eby John
+11  A: 

You should use char *list[]={"aaa","bbb","ccc"}; instead of char **list={"aaa","bbb","ccc"};. You use char* list[] = {...}; to declare the array of pointers, but you use char** to pass a pointer to one or more pointers to a function.

  • T* x[] = array of pointers
  • T** x = pointer to pointer

P.S. Responding to ejohn: There is only one use that I can think of for creating a pointer to a pointer (as an actual declared variable, not as a function parameter or temporary created by the unary & operator): a handle. In short, a handle is a pointer to a pointer, where the handl;e is owned by the user but the pointer it points to can be changed as needed by the OS or a library.

Handles were used extensively throughout the old Mac OS. Since Mac OS was developed without virtual memory technology, the only way to keep the heap from quickly getting fragmented was to use handles in almost all memory allocations. This let the OS move memory as needed to compact the heap and open up larger, contiguous blocks of free memory.

Truth is, this strategy at best just "sucked less". There are a huge list of disadvantages:

  • A common bug was when programmers would dereference the handle to a pointer, and use that pointer for several function calls. If any of those function calls moved memory, there was a chance that the pointer would become invalid, and dereferencing it would corrupt memory and possibly crash the program. This is an insidious bug, since dereferencing the bad pointer would not result in a bus error or segmentation fault, since the memory itself was still existent and accessible; it just was no longer used by the object you were using.
  • For this reason, the compiler had to be extra careful and some Common Subexpression Elimination optimizations couldn't be taken (the common subexpression being the handle dereference to a pointer).
  • So, in order to ensure proper execution, almost all accesses through handles require two indirect accesses, instead of one with a plain old pointer. This can hurt performance.
  • Every API provided by the OS or any library had to specify whether it could possibly "move memory". If you called one of these functions, all your pointers obtained via handles were now invalid. There wasn't a way to have the IDE do this for you or check you, since the moves-memory call and the pointer that became invalid might not even be in the same source file.
  • Performance becomes nondeterministic, because you never know when the OS will pause to compact your memory (which involved a lot of memcpy() work).
  • Multithreading becomes difficult because one thread could move memory while another is executing or blocked, invalidating its pointers. Remember, handles have to be used for almost all memory allocation to keep from fragmenting the heap, so threads are still likely to need access to memory via a handle even if they use none of the Mac OS APIs.
  • There were function calls for locking and unlocking the pointers pointed to by handles, however, too much locking hurts performance and fragments the heap.

There's probably several more that I forgot. Remember, all these disadvantages were still more palatable than using only pointers and quickly fragmenting the heap, especially on the first Macs, which only had 128K of RAM. This also gives some insight into why Apple was perfectly happy to ditch all this and go to BSD then they had the chance, once their entire product line had memory management units.

Mike DeSimone
so char** is used ONLY for passing pointers to a function? if thats true that certainly clears up my doubts
Eby John
@asaf,mike,mick : thank you guys, that clears up everything
Eby John
A pointer to pointer is very useful when you want to, for example, need to have a 2-d "array" with the number of rows and columns unknown at compile-time.
Alok
@Alok: I'd argue that that's more a pointer to `malloc()` array, i.e. that `T** ptrList = (T**)malloc(sizeof(T*)*N);` is more similar to `T* ptrArray[N]; T** ptrList = ptrArray;` than `T* ptr = (T*)malloc(sizeof(T)); T** ptrToPtr = *ptr;`, but I see your point.
Mike DeSimone
@Mike: Bringing back the old days.
David Thornley
Good riddance. It's bad enough having to know which routines I can't call from an interrupt service routine.
Mike DeSimone
+1  A: 

The best source for learning the complexities of C is the book Expert C Programming by Peter van der Linden (http://www.amazon.co.uk/Expert-Programming-Peter-van-Linden/dp/0131774298).

The name of the book is misleading because it's very easily read by beginners I think.

Colin Newell
How it answers the question ?
qrdl
This actually answers the question very well. This book has a whole chapter dedicated to the differences between pointers and arrays in C, explains why they exist and what consequences they have. I read it about 15 years ago and I remember that it was the first time I actually understood what was going on here.
x4u
OP asked a question about pointers, not about books. If you cannot or don't want to answer the question - don't bother
qrdl
+2  A: 
John Bode
thank you for taking the time to write such a lengthy explanation! something tells me this is not the last time i will be referring to this, and i am sure this will help many c newbies like me. as for me i just saved it as c_pointers_explained.txt .
Eby John
A: 

"...assumed it had something to do with the pointer to pointer stuff, which i do not understand clearly."

http://stackoverflow.com/questions/1015944/how-does-an-array-of-pointers-to-pointers-work

Tommy