Char-array vs Char-pointer

This is a discussion on Char-array vs Char-pointer within the C++ Programming forums, part of the General Programming Boards category; I was wondering if there is some advantage of using a char-array over a char-pointer? From were I can see ...

  1. #1
    Veni Vidi Vice
    Join Date
    Aug 2001
    Posts
    343

    Char-array vs Char-pointer

    I was wondering if there is some advantage of using a char-array over a char-pointer? From were I can see char-array are static and in most cases
    consumes more memory than pointers.

    Code:
    #include <iostream>
    
    
    using namespace std;
    
    int main()
    {
    
    	char name[5] = "Eric";
    	char *pname = "Eric";
    	
    	cout << "char-arrays name is " << name << endl;
    	cout << "char-pointers name is " << pname << endl << endl;
    
    	//name = "Alexander";  //Out if bounds
    	pname = "Alexander";  //No problemo
    
    	cout << "After new assignment..." << endl;
    	
    	cout << "char-arrays name is " << name << endl;
    	cout << "char-pointers name is " << pname << endl << endl;
    
    	cout << "And now the size of them" << endl;
    	cout << "char-arrays size is " << sizeof(name) << " bytes" <<endl;
    	cout << "char-pointers size is " << sizeof(*pname) << endl << endl;
    	//Don´t really sure which of them to use, but I guessed that it has to be
    	//the object it points to
    	//cout << "char-pointers size is " << sizeof(pname) << endl << endl;
    
    return 0;
    }
    Why use a char-array?????

  2. #2
    Registered User
    Join Date
    Jun 2002
    Posts
    151
    >Why use a char-array?????

    Because it'll comsume exactly the same amout of memory as a literal string and be guaranteed to be modifyable.

    You're misunderstanding a char pointer. It doesn't contain the whole string in its first byte.

    char* ptr = "Enmeduranki";

    the sizeof ptr will be one (that's the sizeof the ptr, not the string). The sizeof the whole string will be 12.

    "Enmeduranki" is a string of a certain length, no matter where it is stored it'll consume the same amount of memory (assuming that it is stored as the same data type (ANSI and UNICODE) in each section).

  3. #3
    Veni Vidi Vice
    Join Date
    Aug 2001
    Posts
    343
    k, both consumes equal memory.
    Forgot to take the sum of sizeof(pname[0])+sizeof(pname[1)+...sizeof(pname[4]).

    But still isn´t a char-pointer more flexible. You can assign it (multiple times) with strings of different length which you can´t do it with a char-array. Have you once defined a char-array of 5 element there is no way to "extend it". Isn´t this an advantage for using a char-pointers insteed of char-arrays????

  4. #4
    Registered User
    Join Date
    Jun 2002
    Posts
    151
    >You can assign it

    You're not really assigning anything though (apart from the intial address). It's still the same string. If you need a discreet copy then you'll need some memory.

    >Have you once defined a char-array of 5 element there is no way to "extend it". <

    That's how computers work. You ask for a certain amount of memory, and that's what you get back. If you need to extend it then you need more memory. If you're extending literal strings then you stand a good chance of walking into memory that doesn't know that it's allocated, or memory that is used for something else (which could end in tears the next time you need memory).

    >Isn´t this an advantage for using a char-pointers insteed of char-arrays????<

    The only advantage in the present enviroments is when you want a constant string. This may be faster if you're using alot of strings or your brain operates at ~1GHz.
    Last edited by Enmeduranki; 09-07-2002 at 05:50 PM.

  5. #5
    mustang benny bennyandthejets's Avatar
    Join Date
    Jul 2002
    Posts
    1,401
    in my opinion, char pointers are a lot more flexible, because say you want, during the program, to assign the pointer to a string of an unknown length, you can just use malloc() or globalalloc() or whichever you want, and it gives you only as much memory as you need. to use the same pointer again, just free() it, then use malloc() again.

    however, with char arrays, you must set the size when you declare the char[], and you can never change it.

    here is a quick example of the good way of doing it:

    Code:
    char *calloc(long lSize)
    {
        char *tmpPtr;
        
        if ( (tmpPtr=(char*)malloc(lSize))==NULL)
            exit(1);
    
        return tmpPtr;
    }
    What that code does is returns a pointer to a char of lSize bytes length. i find that this is the most efficient way to do chars.
    benforbes@optusnet.com.au
    Microsoft Visual Studio .NET 2003 Enterprise Architect
    Windows XP Pro

    Code Tags
    Programming FAQ
    Tutorials

  6. #6
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,670

    char *pname = "Eric";

    pname = "Alexander"; //No problemo
    No, that's a BIG problemo. You got lucky, and the program didn't crash, but you should not use pointers this way. When you point a pointer at a string literal like that, don't attempt to modify it or even repoint it. It's const, for all practical purposes. This is so important to understand.

    One last thing, and that's about calling malloc and other memory allocation functions. Believe it or not, they can lead to A LOT of memory fragmentation. This is not a problem for small programs, but when you start playing with more memory, you will one day get a big byte in the *** when malloc returns NULL! So what's my point, you say? At some point you should consider large scale allocation and management schema. C++ is perfect for the job because of it's many useful constructs. So how about a simple example?

    For a given program, guestimate how much total memory you'll need. Allocate that much ( but perhaps a bit more, right?) straight from a special class object.


    Code:
    
    class Memory { 
    
    unsigned char *heap;
    
    unsigned char *current;
    
    double heapsize;
    
    double remaining;
    
    bool bailout;
    
    public:
    
    Memory( double initial_size, bool yes_or_no = true )
     :heapsize(initial_size), remaining( initial_size ), 
      current(heap), bailout( yes_or_no )
     {   
       heap = (unsigned char*)malloc(sizeof(unsigned char));
       
       if( heap == NULL )
       {
         if(bailout)
         {
          cerr << "Not Enough Memory!!!";
          abort();    
         }                //...otherwise...
         heap = NULL;
         heapsize = remaining = 0; 
       }
    
      current = heap;    
     
      memset(heap, 0, heapsize);
     }
    
    
    void * malloc( int amount )
     {
       if( amount > remaining + 1)
       {
         if( remaining == 0 ) return NULL;
    
         amount = remaining;     
       }
      amount++;  //...to advance to the next block...
      
      void * chunk = (void*)current;
    
      current += amount;
      
      remaining -= amount;
    
      return chunk;  
     }
    
    
    char * cMalloc( int amount )
     {
       return (char*) Memory::malloc( amount );
     }
    
    int * iMalloc( int amount )
     {
       return (int*) Memory::malloc( amount * sizoef(int) );
     }
    
    ~Memory() 
     {
       if( heap != NULL )
       {
         free(heap);
         heap = NULL; 
       }
     }
    };

    In main, the calling would be familar:


    Code:
    
    Memory mem( 1000000 ); //...get a MB...
    
    int main()
    {
     char * str = mem.cMalloc(100); 
     
     int * array = mem.iMalloc(200);
     
     Employee *emps = (Employee*)mem.malloc( sizeof(Employee) * 10 );
     //...an array of 10 Employees...
    
    return 0;
    } 
    
    //...destuctor is automatically called, hey, that's garbage collection!

    So why go to all the trouble? Simple. First, we can ensure we have enough "startup memory" before going to all the trouble of setting up the program, only to crash 15 minutes later because the system says "no", for instance. But most importantly, we can very easily extend this class to do defragmentation too (automatically, of course, perhaps in our own "free()" method). Third, we have an automatic garbage collector, so we don't have to free up the memory when the program is done ( or crashes for some other reason, etc).



    ITSA
    Socket Library!

  7. #7
    S Sang-drax's Avatar
    Join Date
    May 2002
    Location
    Göteborg, Sweden
    Posts
    2,072

    Perhaps use templates?

    Instead of cMalloc and iMalloc why not create a function like this:
    Code:
    template<typename T> T* Malloc(int amount)
    {
      return reinterpret_cast<T*>(Memory::malloc(amount * sizeof(T)));
    }
    
    
    //Then call it like this:
    
    int* data = memory.Malloc<int>(23);
    Last edited by Sang-drax; 09-08-2002 at 02:07 AM.
    Last edited by Sang-drax : Tomorrow at 02:21 AM. Reason: Time travelling

  8. #8
    S Sang-drax's Avatar
    Join Date
    May 2002
    Location
    Göteborg, Sweden
    Posts
    2,072

    Override new

    Another way is to override the global operator new:

    Code:
    Memory mem; //global object
    
    //override global new operaotr
    void* operator new(size_t size)
    {
        //use global memory object
        return mem.Malloc(size);
    }
    
    int main()
    {
       //init memory;
       mem.init(1000000);
    
      //Very convenient use of the memory class
      int* mynumber = new int;
    }
    Note that the new[] operator must be overrided as well
    Last edited by Sang-drax; 09-08-2002 at 02:46 AM.
    Last edited by Sang-drax : Tomorrow at 02:21 AM. Reason: Time travelling

  9. #9
    Veni Vidi Vice
    Join Date
    Aug 2001
    Posts
    343
    quoted by Sebastiani

    When you point a pointer at a string literal like that, don't attempt to modify it or even repoint it. It's const, for all practical purposes. This is so important to understand.
    Does that mean that is is dangerous to assaign pname = "John" (or a string less than 5 in lenght) so that we overwrite memory?And if it is so dangerous why doesn´t compiler warn us???

  10. #10
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,670
    Not exactly. The main thing is, you are creating strings on the stack that you take no responsibility for. Look at this loop:

    while(1)
    {
    ptr = "Hello World!";
    }

    For each iteration, the pointer is assigned to a brand new string literal, and all connections to the previous string are lost. Yet the loop looks inocuous. That is why I say "bad practice". Also, let's say you do:

    char *ptr = "Hello World";

    ptr[0] = 's';

    This will probably crash your computer! You do not own the memory and thus cannot manipulate it as such.

    So the use of ponters to "anonymous" literals should be avoided unless necessary, and to remind yourself, make it const to boot.



    ITSA
    Socket Library!

  11. #11
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,670
    Also, I want to add that the previous poster did an excellent job of extending the functionality of the memory class, one by templatizing the class, and the second by overloading "new", which was exactly what I was hoping someone would propose. So good job, Sang-Drax!



    ITSA
    Socket Library!

  12. #12
    S Sang-drax's Avatar
    Join Date
    May 2002
    Location
    Göteborg, Sweden
    Posts
    2,072
    Originally posted by Sebastiani
    So good job, Sang-Drax!
    Thanks

    But I doubt that my operator overloding will work.

    The new operator can be called before main, for example in a class constructor or something.
    If it's called before main(), the Mem object will be uninitialized.

    This code can proabably fix it:

    Code:
    void* Memory::Malloc(sizet_t size)
    {
       if (!initialized)
         return malloc(size); //standard way
       else
       {
         //normal alloc code
       }
    }
    For example, if you include <iostream> in VC++, the operator new will be called before main().

    This is going more and more away from the original topic, perhaps a new one should be created?
    Last edited by Sang-drax : Tomorrow at 02:21 AM. Reason: Time travelling

  13. #13
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,670
    Hey that's a great idea...how do we do that again??

    ....also...

    Perhaps you could elaborate on your last post?



    ITSA
    Socket Library!

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. pointers
    By InvariantLoop in forum C Programming
    Replies: 13
    Last Post: 02-04-2005, 08:32 AM
  2. Could somebody please help me with this C program
    By brett73 in forum C Programming
    Replies: 6
    Last Post: 11-25-2004, 01:19 AM
  3. Unknown Memory Leak in Init() Function
    By CodeHacker in forum Windows Programming
    Replies: 3
    Last Post: 07-09-2004, 09:54 AM
  4. convert long to pointer to char array
    By gazmack in forum C++ Programming
    Replies: 5
    Last Post: 09-26-2003, 11:33 AM
  5. simulate Grep command in Unix using C
    By laxmi in forum C Programming
    Replies: 6
    Last Post: 05-10-2002, 04:10 PM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21