CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 10 of 10
  1. #1
    Join Date
    Jun 2015
    Posts
    175

    My problem with pointers

    Hello to all,

    please consider this code:

    Code:
    #include <iostream>
    using namespace std;
    
    char* strdup(const char*_a) 
     {
    	 char* pch = new char[4];
    	 for(int i=0; i<4; i++){
    		 *(pch+i) = *(_a+i);
    	 }
         return pch;
     }
    
    int main()
    {  
    	char a[] = "test";
    	cout << strdup(a) << endl;
    	return 0;
    }
    It shows "test" and some extra characters instead of the only "test"!
    What is the problem please?

  2. #2
    Join Date
    Jan 2006
    Location
    Singapore
    Posts
    6,765

    Re: My problem with pointers

    Quote Originally Posted by tomy12
    It shows "test" and some extra characters instead of the only "test"!
    What is the problem please?
    You duplicated a null terminated string but forgot to null terminate your duplicate, and in fact you did not even allocate enough space for the null character (having hard coded 4 instead of using std::strlen or something like it). Besides this, you forgot to delete[].

    Solution: use std::string instead.
    C + C++ Compiler: MinGW port of GCC
    Build + Version Control System: SCons + Bazaar

    Look up a C/C++ Reference and learn How To Ask Questions The Smart Way
    Kindly rate my posts if you found them useful

  3. #3
    2kaud's Avatar
    2kaud is offline Super Moderator Power Poster
    Join Date
    Dec 2012
    Location
    England
    Posts
    7,822

    Re: My problem with pointers

    What if a was initialised to a longer set of chars eg char a[] = "string"; ? c/c++ provides a comprehensive library for functions relating to c-style null terminated strings. See http://www.cplusplus.com/reference/cstring/

    However, as laserlight pointed out, why not use c++ string class instead. See http://www.cplusplus.com/reference/string/
    All advice is offered in good faith only. All my code is tested (unless stated explicitly otherwise) with the latest version of Microsoft Visual Studio (using the supported features of the latest standard) and is offered as examples only - not as production quality. I cannot offer advice regarding any other c/c++ compiler/IDE or incompatibilities with VS. You are ultimately responsible for the effects of your programs and the integrity of the machines they run on. Anything I post, code snippets, advice, etc is licensed as Public Domain https://creativecommons.org/publicdomain/zero/1.0/ and can be used without reference or acknowledgement. Also note that I only provide advice and guidance via the forums - and not via private messages!

    C++23 Compiler: Microsoft VS2022 (17.6.5)

  4. #4
    Join Date
    May 2007
    Location
    Scotland
    Posts
    1,164

    Re: My problem with pointers

    I utterly agree with laserlight and 2kaud, use std::string instead. However, from the perspective of learning, there are a number of issues.

    1) Remembering that the function should assume that it knows nothing about who called it and with what data, your strdup function doesn't check the length of the char array that has been passed, consider what would happen if strdup was called with a null parameter or something that has an allocation of less than 4 bytes - the result is undefined behaviour. Your conclusion should be that you need a method that will get the size of the passed char array, (strlen will do this for you).
    2) You are returning a raw pointer from a function, and this has a number of issues, i)the caller may incorrectly assume that it was allocated with malloc, and therefore incorrectly attempt to deallocate it with free or ii) the caller may not realise that they have to deallocate the memory themselves, or iii) the caller may completely forget to deallocate the memory, or iv) the pointer might get passed to a number of classes and the idea of which is responsible for deallocation might get completely lost. This should lead you to the point of realising that memory should be owned by something and that something should be responsible for allocating the memory and ensuring that it is properly cleared up. Enter a pattern known as RAII (Resource Aquisition Is Initialisation). The premise is that resources are allocated in a classes constructor and deallocated in its destructor. If we mold what you have written into a class and make some modifications then we'd end up with something like:

    Code:
    class my_string {
    public:
      my_string(const char* str)
        :size_(strlen(str))
        ,buffer_(new char[size_ + 1]) //plus one for a null terminator
      {
        std::copy(str, str+size_, buffer_);
        buffer_[size_] = 0; // add the null terminator
      }
    
      ~my_string() {
        delete [] buffer_;
      }
    
      const char* c_str() const {
        return buffer_;
      }
    
    private:
      size_t size_;
      char* buffer_;
    };
    So the above now will allocate the memory and correctly copy str when you construct it, and deallocate it when the class goes away, but the above code has its own problems. The first is copying issues:

    Code:
     
    {
      my_string a(“hello”);
    
      {//reduce the life time of b using scoping braces
        my_string b(a); //copy construct b from a – the default copy constructor does the wrong thing here – now a.buffer_ and b.buffer_ point to the same allocation 
              std::cout << a.c_str() << std::endl; //prints “hello”
         } // b goes out of scope here deallocating the memory
     
         std::cout << b.c_str() << std::endl;// undefined behavior – might print ok, might blow up, might corrupt your OS
    } // a goes out of scope resulting in a double deletion error
    The problem with the current my_string implementation is that a and b end up sharing the same pointer to the memory allocated to buffer_ and therefore when the first class is destroyed it will deallocate the memory pointed to by the second class instance – this poses two issues i) if anyone attempts to access the memory, the result is undefined behavior ii) when the second class is destroyed it will cause a double deletion error when it calls delete[] because the memory has already been deallocated. To fix this, we can make the following changes:

    Code:
    #include <iostream>
    #include <cstring>
     
    class my_string {
    public:
      my_string(const char* str) 
        :size_(strlen(str))
        ,buffer_(new char[size_ + 1]) //plus one for a null terminator
      {
        std::copy(str, str+size_, buffer_);
        buffer_[size_] = 0; // add the null terminator
      }
     
      my_string(const my_string& other)  //copy constructor
        :size_( other.size_)
        ,buffer_(new char[other.size_ + 1]) //plus one for a null terminator
      {
        std::copy(other.buffer_,  other.buffer_+size_, buffer_);
        buffer_[size_] = 0; // add the null terminator
      }
     
      void swap(my_string& other) {
         std::swap(size_, other.size_);
         std::swap(buffer_, other.buffer_);
      }
     
      my_string& operator=(const my_string& rhs) { 
        //implement copy assignment via copy construction
        my_string(rhs).swap(*this);
       return *this;
      }
     
      ~my_string() {
        delete [] buffer_;
      }
     
      const char* c_str() const {
        return buffer_;
      }
     
    private:
      size_t size_;
      char* buffer_;
    };
     
     
    int main()
    {
      my_string a("hello");
      {
        my_string b(a); //copy construct b from a - now a.buffer_ and b.buffer_ point to different allocations 
        std::cout << b.c_str() << std::endl; //prints “hello”
      } // b goes out of scope here deallocating its copy memory, leaving a's in tact
     
      std::cout << a.c_str() << std::endl;// ok
     
    }
    So, now you have something that manages memory for you in a dedicated object, but wait, you are now going down the road of implementing your own std::string class, only the above is not as good and nowhere near as feature packed. Moral of the story is…. use std::string.
    Last edited by PredicateNormative; August 14th, 2015 at 04:45 PM. Reason: grammar

  5. #5
    Join Date
    Jan 2006
    Location
    Singapore
    Posts
    6,765

    Re: My problem with pointers

    Quote Originally Posted by PredicateNormative
    the caller may incorrectly assume that it was allocated with malloc, and therefore incorrectly attempt to deallocate it with free
    Especially since there is a POSIX standard function named strdup which has the same parameter list and return type, and which does obtain storage using malloc.
    C + C++ Compiler: MinGW port of GCC
    Build + Version Control System: SCons + Bazaar

    Look up a C/C++ Reference and learn How To Ask Questions The Smart Way
    Kindly rate my posts if you found them useful

  6. #6
    Join Date
    May 2007
    Location
    Scotland
    Posts
    1,164

    Re: My problem with pointers

    Quote Originally Posted by laserlight View Post
    Especially since there is a POSIX standard function named strdup which has the same parameter list and return type, and which does obtain storage using malloc.
    Very true... something tells me the OP was possibly just trying to figure out how strdup works by having a go at implementing it themselves.

  7. #7
    Join Date
    Apr 2000
    Location
    Belgium (Europe)
    Posts
    4,626

    Re: My problem with pointers

    Quote Originally Posted by laserlight View Post
    Besides this, you forgot to delete[].
    I was just about to call you out on that one when I noticed he indeed forgot a delete[]

    but I'd also like to point out it's typically a bad idea to make functions that have names that already exist in the C/C++ library, even if you're not including the appropriate headers to get into an actual conflict, anyone reading your code might make the same mistake I initially did, namely that you're using strdup() from the C lib.

  8. #8
    Join Date
    Jan 2006
    Location
    Singapore
    Posts
    6,765

    Re: My problem with pointers

    Quote Originally Posted by OReubens
    I'd also like to point out it's typically a bad idea to make functions that have names that already exist in the C/C++ library
    Well, that is what namespaces are for, though I am not sure if strdup would also be in the std namespace since being POSIX standard only it is not part of the standard library, and besides there is that using directive in effect.
    C + C++ Compiler: MinGW port of GCC
    Build + Version Control System: SCons + Bazaar

    Look up a C/C++ Reference and learn How To Ask Questions The Smart Way
    Kindly rate my posts if you found them useful

  9. #9
    Join Date
    Jun 2015
    Posts
    208

    Re: My problem with pointers

    Quote Originally Posted by tomy12 View Post
    please consider this code:
    You don't have to learn C before you learn C++.

    C is good but C++ is even better so why struggle with C when heaven's just around the corner.
    Last edited by tiliavirga; August 15th, 2015 at 01:35 AM.

  10. #10
    Join Date
    Jun 2015
    Posts
    175

    Re: My problem with pointers

    Thank YOU all very much. The problem is solved now.
    I appreciate all of you nice guys for those many responses

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured