Thread: New keyword and function scope

  1. #1
    Registered User
    Join Date
    Sep 2009
    Posts
    29

    New keyword and function scope

    Hi guys,

    In the code below, the new keyword creates 5 integers for a pointer. However, whenever I am outside of the createmem() function, I cannot access this memory-- visual studio says that integers's memory address is 0x00000000). Why is this happening? Is there a good workaround for it?

    Thanks!

    -Max

    Code:
    #include <iostream>
    
    using namespace std;
    
    void createmem(int *myints);
    
    void createmem(int *myints)
    {
    	myints = new int[5];
    }
    
    
    int main()
    {
    	int *integers = NULL;
    	createmem(integers);
    
    	delete[] integers;
    }

  2. #2
    Registered User
    Join Date
    Oct 2010
    Posts
    107
    Code:
    #include <iostream>
    
    using namespace std;
    
    void createmem(int *myints);
    
    void createmem(int *myints)
    {
            // 5 ints allocated, but main won't see it because myInts
            // is a copy of the int* in main.
    	myints = new int[5];
    }
    
    
    int main()
    {
    	int *integers = NULL; // No space allocated
            // integers ptr copied in createmem, but integers won't actually point to valid memory after the call returns.
            // furthermore, you will leak memory in createmem because the copy myInts is lost when the calll returns
    	createmem(integers); 
    
    
    	delete[] integers;
    }

    That's not how it works. What you do is say
    Code:
    int* myArrayOfInts = new int[5];
    If you want a function to return some ints, then you should have either
    Code:
    int* createmem() // Returning the array
    {
    	return new int[5];
    }
    or
    Code:
    void createmem(int** ptrToArrayOfInts) // Passing by reference from main
    {
           *myints = new int[5];
    }
    Are you new to pointers?
    Last edited by QuadraticFighte; 10-23-2010 at 02:34 PM.

  3. #3
    Registered User
    Join Date
    Sep 2009
    Posts
    29
    No, I'm not new to pointers. This is actually a much simpler version of what I'm doing... In another program, I have a function which needs to create a 2D array, a single array, and perform some operations on them (like clearing them out).

    This doesn't really address my question, though. Why is this illegal?


    Here's a more full code. inLine is a string pulled from a file, which represents a number of nodes and their edges, ex: 5 (1,2) (2,3) (3,4) represents 5 nodes, with 1<->2, 2<->3, and 3<->4.

    The code then does other things (in other functions) with matrix, and nodeCode.

    Code:
    void fillMatrix(string inLine, int numNodes, int **matrix, int *nodeCode)
    {
    	stringstream tempStream;  //used for extracting formatted text from file
    	int edgeStart;		//node where an edge begins
    	int edgeEnd;		//node where an edge ends
    	int edgeCount = 0;	//number of edges specified by user
    
    	//begin by removing parenthesis and commas from data
    	size_t found;		//used for finding unwanted formatting
    	found = inLine.find_first_of("(),");
    
    	while (found != string::npos)
    	{
    		if (inLine[found] == '(')
    		{
    			edgeCount++;		//count the number of edges we have from the user
    		}
    		inLine[found] = ' '; //replace with a space
    		found = inLine.find_first_of("(),");
    	}
    
    	tempStream << inLine; //put the string onto the temporary stream
    	
    	//Data in tempStream is just numbers now, the first is the 
    	//number of nodes
    	tempStream >> numNodes;
    
    	//create the matricies according to the size
    	nodeCode = new int[numNodes];
    	matrix = new int* [numNodes];
    
    	for (int i = 0; i < numNodes; i++)
    	{
    		matrix[i] = new int[numNodes];
    	}
    	
    	//clear matricies
    	for (int i=0; i < numNodes; i++)
    	{
    		nodeCode[i] = UNVISITED;
    		for (int j=0; j< numNodes; j++)
    		{
    			matrix[i][j] = UNCONNECTED;
    		}
    	}
    	//Everything else specifies an edge
    	
    	for (int i=0; i < edgeCount; i++)
    	{
    		//get the edge node points
    		tempStream >> edgeStart;
    		tempStream >> edgeEnd;
    
    		//Correct for offset (matrix starts at 0, nodes start at 1)
    		edgeStart--; 
    		edgeEnd--;
    
    		//place them in the adjacency matrix
    		matrix[edgeStart][edgeEnd] = CONNECTED;
    		matrix[edgeEnd][edgeStart] = CONNECTED; //since this is an undirected graph
    	}
    	
    }
    EDIT: CONNECTED, UNCONNECTED, VISITED, and UNVISITED are all just enum values for better readability

  4. #4
    Registered User
    Join Date
    Oct 2010
    Posts
    107
    Because it's not the right way of actually initializing the memory. You lost a pointer to allocated memory in createmem. When the call returned, the pointer to the actual memory was not returned in main because the int* myInt is a value copied from main. The int* integers in main is still NULL. C++ is a call by value language. If you want to change the value of integers in main, you have to pass it by reference. Anyway, here's your leak.
    Code:
    ==6483== HEAP SUMMARY:
    ==6483==     in use at exit: 20 bytes in 1 blocks
    ==6483==   total heap usage: 1 allocs, 0 frees, 20 bytes allocated
    ==6483== 
    ==6483== 20 bytes in 1 blocks are definitely lost in loss record 1 of 1
    ==6483==    at 0x4C285EB: operator new[](unsigned long) (vg_replace_malloc.c:305)
    ==6483==    by 0x40082D: main (foo.cpp:9)
    ==6483== 
    ==6483== LEAK SUMMARY:
    ==6483==    definitely lost: 20 bytes in 1 blocks
    ==6483==    indirectly lost: 0 bytes in 0 blocks
    ==6483==      possibly lost: 0 bytes in 0 blocks
    ==6483==    still reachable: 0 bytes in 0 blocks
    ==6483==         suppressed: 0 bytes in 0 blocks
    ==6483== 
    ==6483== For counts of detected and suppressed errors, rerun with: -v
    ==6483== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 4 from 4)
    That's the line: myints = new int[5];

    Also, if I try to dereference your pointer in main, we can see it clearly doesn't work:
    Code:
    #include <iostream>
    
    using namespace std;
    
    void createmem(int *myints);
    
    void createmem(int *myints)
    {
    	myints = new int[5];
    }
    
    
    int main()
    {
    	int *integers = NULL;
    	createmem(integers);
    	integers[0] = 5; // Line I added
    
    	delete[] integers;
    }
    Valgrind output:
    Code:
    ==6506== Invalid write of size 4
    ==6506==    at 0x40082E: main (foo.cpp:17)
    ==6506==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
    ==6506== 
    ==6506== 
    ==6506== Process terminating with default action of signal 11 (SIGSEGV)
    ==6506==  Access not within mapped region at address 0x0
    ==6506==    at 0x40082E: main (foo.cpp:17)
    [...]
    Segmentation fault

  5. #5
    Registered User
    Join Date
    Sep 2009
    Posts
    29
    Great. It doesn't work. I fully understand that. I even understand it's not the proper way of doing this. I still don't see what is the "proper" way of doing it.

    Let me break down the problem for you:

    1. You have two pointers, one is a pointer to a pointer.
    2. You need to create memory for both pointers, inside of a function, and then perform operations on these inside of the main body of the program.

    How would you go about that?

  6. #6
    Registered User
    Join Date
    Oct 2010
    Posts
    107
    Quote Originally Posted by maxsthekat View Post
    Great. It doesn't work. I fully understand that. I even understand it's not the proper way of doing this. I still don't see what is the "proper" way of doing it.

    Let me break down the problem for you:

    1. You have two pointers, one is a pointer to a pointer.
    2. You need to create memory for both pointers, inside of a function, and then perform operations on these inside of the main body of the program.

    How would you go about that?
    Look, I am not giving you attitude. I am taking time out to explain exactly why it didn't work. There is value in that, and if you can't see value in it... Oh dear...

    I will tell you how to fix the basic example. You can extrapolate to your application
    Code:
    #include <iostream>
    
    using namespace std;
    
    void createmem(int **myints);
    
    void createmem(int **myints) // We accept pointer to int*
    {
    	*myints = new int[5]; // Allocate the array and make it "visible" to main
    }
    
    
    int main()
    {
    	int *integers = NULL;
    	createmem(&integers); // We correctly pass the reference of integers*
    	integers[0] = 5; // Voila, now we have valid memory to use
    
    	cout << integers[0] << endl;
    
    	delete[] integers;
    }

  7. #7
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    How about:
    Code:
    #include <iostream>
    
    void createmem(int* & myints);
    
    void createmem(int* & myints) // We accept reference to int*
    {
    	myints = new int[5]; // Allocate the array and make it "visible" to main
    }
    
    
    int main()
    {
    	int* integers = nullptr;
    	createmem(integers); // We correctly pass the reference of integers*
    	integers[0] = 5; // Voila, now we have valid memory to use
    
    	cout << integers[0] << endl;
    
    	delete[] integers;
    }
    Also, QuadraticFighte, be careful with your terminology. You are not passing a reference to a pointer. You are passing the address of a pointer.
    In C, they happen to be the same (although you can argue that it is incorrect), but in C++, they are not the same thing.

    Furthermore, note that you do not have to do manual memory allocation for 2D array. You can simply use a std::vector for that.
    Code:
    std::vector<std::vector<int>> v(size_of_first_dimension, std::vector<int>(size_of_second_dimension));
    Boost.Multiarray also provides some tools for easier creating of 2D arrays. You might check it out if you want.
    Last edited by Elysia; 10-23-2010 at 03:27 PM.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  8. #8
    Registered User
    Join Date
    Oct 2010
    Posts
    107
    Quote Originally Posted by Elysia View Post
    Code:
    void createmem(int* & myints) // We accept pointer to int*
    {
    	myints = new int[5]; // Allocate the array and make it "visible" to main
    }
    Wow, that's super nifty. I never quite understood how the & worked in that context. So that assures that int*'s are passed by reference?

  9. #9
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Yes, everything to the left on the "&" is the type that is passed by reference, just like a pointer is a pointer to the type that's left of the last *.
    int** -> pointer to int*.
    int*& -> reference to int*.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  10. #10
    Registered User
    Join Date
    Sep 2009
    Posts
    29
    Thanks guys. I knew that if you wanted to change variables you could always do a pass by reference. I didn't realize there was a comparable situation for pointers

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Local function keyword
    By mlupo in forum C Programming
    Replies: 8
    Last Post: 05-16-2009, 05:04 AM
  2. Replies: 18
    Last Post: 12-31-2005, 01:56 PM
  3. Replies: 4
    Last Post: 06-15-2005, 08:30 PM
  4. structure vs class
    By sana in forum C++ Programming
    Replies: 13
    Last Post: 12-02-2002, 07:18 AM
  5. error LNK2001: unresolved external symbol
    By Unregistered in forum C Programming
    Replies: 12
    Last Post: 07-12-2002, 08:45 PM