Thread: Quick question about SIGSEGV

Hybrid View

Previous Post Previous Post   Next Post Next Post
  1. #1
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,897
    >I was under the impression that a char* is an array!!!
    This statement warrants a reply of its own.

    Let me begin by saying that arrays and pointers are not the same. Arrays can be simulated with pointers and dynamic memory, and arrays are converted to a pointer to the first element of the array when used in a value context. This seeming equivalence is what confuses people so much, even experienced C programmers with decades of experience.

    So what is an array? An array is a block of memory equivalent to the size of N * sizeof(T) where T is the type of the array and N is the size. This is what an array object is.

    What is a pointer? A pointer is an object that holds an address, nothing more. That's what a pointer object is.

    Now, this is obvious until you see how C treats the two. You'll see pointers with array subscripting notation and arrays being dereferenced with a pointer offset, you'll see functions that take arrays being passed pointers and vice versa, you'll see all kinds of funky stuff (highly technical term!) that would suggest pointers and arrays are actually interchangeable. The problem is context. There are two contexts when it comes to array and pointer equivalence: value context and object context.

    Object context is when you use an array as an array and a pointer as a pointer; a good example of this is the sizeof operator. The following will print what you expect it to because the sizeof operator is working in object context:
    Code:
    #include <stdio.h>
    
    int
    main(void)
    {
      char  array[10];
      char *pointer;
    
      printf("Array:   %lu\n", (unsigned long)sizeof array);
      printf("Pointer: %lu\n", (unsigned long)sizeof pointer);
    
      return 0;
    }
    On my system this prints
    Code:
    Array:   10
    Pointer: 4
    Which is expected because the array is 10 characters, each 1 byte in size and a pointer object is 4 bytes on my system. This is object context, and there aren't many places where it applies in C. The places it applies are the following:

    1) As operands to the sizeof operator.
    2) As operands to the address-of (&) operator.
    3) A string literal initializer for an array.

    That last one is confusing until you realize that the type of a string literal is actually array-of-char. These are the three situations where an array is not equivalent to a pointer. I say "equivalent" because an array is never a pointer, and a pointer is never an array, but the language rules allow for certain conversions that make it seem that way. This brings us to the value context.

    Put simply, in value context, you get the value of an object. If that object is int, you ask for the integer contained within the memory owned by that variable. If the object is a pointer, you ask for the address that the pointer contains. If the pointer is dereferenced, you ask for the value of the type being pointed to that is contained at that address. And if the object is an array, it is converted to a pointer to the first element of the array. This conversion causes no end of confusion because once the array is converted to a pointer, you can use it much like a pointer (but not exactly like one).

    The subscript operator actually works with pointers. It takes a pointer and dereferences an offset of that pointer, that's why you'll hear time and again that [I]a is equivalent to *(a + i) and that because addition is commutitive, i[a] is equivalent to [I]a. For some reason teachers explain that last fact with great pride as if it's useful at all. In fact, array notation underneath is the dereference of an offset. It's merely syntactic sugar to make your life easier.

    When you pass an array to a function, the array notation is also syntactic sugar to tell you that you're going to use the pointer like an array, just like subscripting. These two function declarations are exactly the same:
    Code:
    void foo(char *array);
    Code:
    void foo(char array[]);
    In the end, array is a pointer, not an array. You can test this fact for yourself simply by trying to use array in object context within foo:
    Code:
    #include <stdio.h>
    
    void foo(char array[]);
    
    int
    main(void)
    {
      char array[10];
    
      foo(array);
    
      return 0;
    }
    
    void
    foo(
      char array[]
      )
    {
      printf("Array: %lu\n", (unsigned long)sizeof array);
    }
    You'll be surprised at first to see that the output is 4 (on my system ) instead of 10. That's because when array is passed to foo, it's used in value context and converted to a pointer to the first element. Then sizeof is used on the pointer in object context. Perfectly logical and natural to the trained eye, but hopelessly confusing to the beginner and unwary alike.

    But if an array in value context is a pointer, why can't we assign to it? Because that particular pointer is not an lvalue, so it can never be on the left hand side of an assignment. That's why I said that arrays can be used "much like" pointers, but not "exactly like" pointers. The reason we could modify the array that was passed to foo is because it's a copy of the pointer, not the original pointer, and the copy is an lvalue. But that's getting into function argument passing rules and this explanation is about pointers and arrays.

    So we can break it down into a few simple rules:

    1) Arrays and pointers are not the same.
    2) In value context, an array is a pointer to the first element of the array, but is not an lvalue.
    3) Array notation can work with pointers because it's syntactic sugar covering up pointer operations.
    4) Pointer notation can work with arrays because it's in a value context.
    5) There are three object contexts: sizeof, address-of, and string literal initialization.
    6) Everything else is value context.
    My best code is written with the delete key.

  2. #2
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,897
    Anyway, so if I have
    char p[] = "hello";
    char *s;
    and I want to pass it to reverse, will this work?
    s = reverse(p);
    Yes, it will. If I'm judging your reverse correctly, it takes an array, reverses it, and returns a pointer to the reversed array. So after reverse, p is "olleh" and s points to that string. All is well with the world.

    >if pointers are read-only, then howcome functions like fgets take a
    >pointer as an argument and change it so it points to something different ?
    Pointers aren't read-only, the memory for a string literal is. So if you have a pointer to a string literal, you can't dereference the pointer and modify the contents of the string. If the pointer points to memory that you own and is non-const, you can modify it all you want.
    My best code is written with the delete key.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Very quick math question
    By jverkoey in forum A Brief History of Cprogramming.com
    Replies: 8
    Last Post: 10-26-2005, 11:05 PM
  2. very quick question.
    By Unregistered in forum C++ Programming
    Replies: 7
    Last Post: 07-24-2002, 03:48 AM
  3. quick question
    By Unregistered in forum C++ Programming
    Replies: 5
    Last Post: 07-22-2002, 04:44 AM
  4. Quick Question Regarding Pointers
    By charash in forum C++ Programming
    Replies: 4
    Last Post: 05-04-2002, 11:04 AM
  5. Quick question: exit();
    By Cheeze-It in forum C Programming
    Replies: 6
    Last Post: 08-15-2001, 05:46 PM