Wierd Visual Studio Problem

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • inhaler
    New Member
    • Mar 2009
    • 1

    Wierd Visual Studio Problem

    Hi,

    I have the following code that I run and compile successfully on Visual Studio 2008 using C, but the problem is when the program tries to run the first free call it just hangs there and does nothing :S. In GNU Linux the program runs fine but windows shows a very strange behavior with this.

    here is the code

    Create a 2D array dynamically
    Code:
    // now that we have our choice, let's create our dynamic string pointer
    		// array using the specified size
    		char **sptrTable = (char**)calloc( (tabSize+1), sizeof(int) );
    
    		// check for valid allocation
    		if( sptrTable == NULL )
    		{
    			fprintf( stdout,"\nNo memory was allocated due to insufficient memory, please free up some memory and try again\nThe program will now exit\n");
    			return ERROR_CODE;
    		}
    
    		// set our exit code for the allocation size
    		sptrTable[tabSize] = (char*)calloc( 1, sizeof(int) );
    		sptrTable[tabSize][0] = ALLOCATION_LIMIT;
    Now we later on we will the array:
    Code:
    while ( allocCheck )
    		{
    
                            // create the string in the table and
    			// check if the memory was allocated ok
    			if ( (ptr[index] = (char *)calloc( strlen(buff), sizeof(char) ) ) == NULL )
    			{
    				return ERROR_CODE;
    			}
    
                            // advance the pointer to next value
    				ptr[index++];
    
    				// check for allocation limit
    				if ( ptr[index] != NULL && ptr[index][0] == (ALLOCATION_LIMIT) )
    				{
    
                                      allocCheck = TRUE;
                                    }
    }
    And finally this is the free function used which shows the strange behavious on windows (it stops in the first iteration of the free function):

    Code:
    void freeChunks( int **ptr, int tabSize )
    {
    
    	int index = 0;
    	int i = 0;
    
    		// free the columns
    		while( index <= tabSize && ( ptr[index] != NULL) )
    		{
    			free( ptr[index] );
    			index++;
    		}
    
    		// free the rows
    		free( ptr );
    }
    The code is corrent and should run fine (it does on Linux using gcc but windows is ><)

    Waiting for your responces!
  • Andr3w
    New Member
    • Nov 2007
    • 42

    #2
    Hey m8,

    Well as it seems maybe linux has a better memory management (and smarter) but it's kinda off the standard to perform such actions. Your code is correct and absolutely right but with one exception, the size needed for allocation of the string.

    Picture this:

    Code:
    char *str = "aaaa";
    
    printf("%d", strlen(str));
    The code above would return 4 which is correct by all means but as we know strings in C have the following byte syntax (in reality)

    1st B -> "a"
    2nd B -> "a"
    3rd B -> "a"
    4th B -> "a"
    5th B -> "\0" (a.k.a. NULL termination string)

    To free a string the free MUST find a null terminated string in order to de-allocate the memory successfully. Maybe linux libraries are a bit more lenient on this restriction but it must be done (as per C standard).

    So the only correction you have to do mate to your code is the following:

    Code:
     if ( (ptr[index] = (char *)calloc( strlen(buff)+1 /* +1 byte for \0 */, sizeof(char) ) ) == NULL )
                 {
                     return ERROR_CODE;
                 }
    Cheers!

    Comment

    • weaknessforcats
      Recognized Expert Expert
      • Mar 2007
      • 9214

      #3
      Actually, you are creating a one-dimensional array of char*.

      All arrays in C/C++ are one dimensional.

      Read this: http://bytes.com/topic/c/insights/77...rrays-revealed.

      Pay attention ot the last example.

      Comment

      • Andr3w
        New Member
        • Nov 2007
        • 42

        #4
        Technically speaking yea I agree, but in this case he created a one-dimensional array of string pointers that point to the actual string. That's why he also had a problem during free because it didn't find where to end deallocation and caused the function to lock ;)

        Comment

        • weaknessforcats
          Recognized Expert Expert
          • Mar 2007
          • 9214

          #5
          Originally posted by Andr3w
          That's why he also had a problem during free because it didn't find where to end deallocation and caused the function to lock ;)
          What do you mean? The size of an allocated piece of memory is prepended to the address returned by the allocator. You just free the pointer without ever saying how big the allocation is.

          If you have a one-dimensional array of char* pointers that point to alocated strings you just loop throught the array and free each pointer and then free the array of pointers.

          Comment

          • donbock
            Recognized Expert Top Contributor
            • Mar 2008
            • 2427

            #6
            Originally posted by inhaler
            Code:
                char **sptrTable = (char**)calloc( (tabSize+1), sizeof(int) );
                ...
                sptrTable[tabSize] = (char*)calloc( 1, sizeof(int) );
                sptrTable[tabSize][0] = ALLOCATION_LIMIT;
            In sptrTable you store a pointer to a buffer of size (tabSize+1)*siz eof(int) bytes. That is, a buffer sized to hold an array of tabSize+1 int's, but you declare sptrTable as an array of char-pointers. This only works if int and char* happen to be the same size. You should use sizeof(char*) rather than sizeof(int).

            Later, you store a pointer to a buffer of size 1*sizeof(int) in the last sptrTable slot. There's not enough information to tell if sizeof(int) is the correct type in this case. If you truly intend for each sptrTable slot to point at a single int then you should have declared sptrTable as an int** rather than a char**. If so, then you need to use sizeof(int*) in the first calloc.

            Comment

            • donbock
              Recognized Expert Top Contributor
              • Mar 2008
              • 2427

              #7
              Originally posted by inhaler
              And finally this is the free function used which shows the strange behavious on windows (it stops in the first iteration of the free function)
              "It stops" -- do you mean your program ends, error messages are displayed, and you have a command prompt; or do you mean that your computer hangs and has to be rebooted? Please provide any error messages.

              Comment

              • Andr3w
                New Member
                • Nov 2007
                • 42

                #8
                Hey guys,

                First of all the weakness of cats, if you run the code in a example and try to free it the way the code is posted the program just hangs, while being responsive (i mean the console cursor is flashing) no crashes occur and no exception either. If you are in debugger more in VS you have to either press Cntl + F5 to exit the program or press X to close it while in release build you have to press X to exit it.

                If you run the program using GCC and Linux it doesn't stop and continues execution as planned becuase it's a bit more lenient.

                Now to donbock, I think you are wrong there the size of a pointer in a 32-bit operating system is 32 bits regardless of the size of the pointed value, and that's why it works.

                Now I've compiled an example that demonstrates this, I've tested it in Windows Vista 64 bit using VS2k8 and in Debian Linux using GCC and Vim

                I compiled it as a CPP file but I think it's C syntax valid also so...and I tried to use as much as I could the same variables as the initial provided code
                Code:
                //////////////////////////////////////////////////////////////////////////
                //																		//
                // Parent Project Name: sample project for bytes
                //																		//
                // Project file: boom.cpp							//
                // 																		//
                // Description: Demonstrate offset needed in allocaton					//
                //																		//
                //																		//
                // Notes:	-															//															
                //																		//	
                // Date Edited: 2009/03/20												//
                // Version:	1.0r														//
                //																		//
                // Coder: Andrew Grammenos (andreas.grammenos@gmail.com)				//
                //																		//
                // License:	BSD License													//									
                //																		//
                //////////////////////////////////////////////////////////////////////////
                
                #include <stdlib.h>
                #include <string.h>
                #include <malloc.h>
                
                // set the codes
                #define		ERROR_CODE 1
                #define		ALLOCATION_LIMIT -1
                
                // disable this in nix and legacy versions of VS
                #pragma warning ( disable : 4996 )
                
                // set true false macros
                #define TRUE 0;
                #define FALSE 1;
                
                // forward function declarations
                
                int createTable();
                
                void freeChunks( char **ptr, int tabSize );
                
                int addStringsToTable(char **ptr);
                
                int main(int argc, char* argv[])
                {
                	createTable();
                
                	return TRUE;
                }
                
                
                int createTable()
                {
                	// example size
                	int tabSize = 5;
                
                	// now that we have our choice, let's create our dynamic string pointer
                	// array using the specified size
                	char **sptrTable = (char**)calloc( (tabSize+1), sizeof(int) );
                
                	// check for valid allocation
                	if( sptrTable == NULL )
                	{
                		fprintf( stdout,"\nNo memory was allocated due to insufficient memory, please free up some memory and try again\nThe program will now exit\n");
                		return ERROR_CODE;
                	}
                
                	// set our exit code for the allocation size
                	sptrTable[tabSize] = (char*)calloc( 1, sizeof(int) );
                	sptrTable[tabSize][0] = ALLOCATION_LIMIT;
                
                
                	// pass the address of the pointer table to our function
                	// that adds the strings
                	addStringsToTable( sptrTable );
                
                
                	// free up what we used
                	freeChunks(sptrTable, tabSize);
                
                	return TRUE;
                
                }
                
                void freeChunks( char **ptr, int tabSize )
                {
                
                	int index = 0;
                
                	// free the columns
                	while( index <= tabSize && (ptr[index] != NULL) )
                	{
                		free( ptr[index] );
                		index++;
                	}
                
                	// free the rows
                	free( ptr );
                }
                
                int addStringsToTable(char **ptr)
                {
                
                	// create  a buffer to store the string that the user will input
                	char buff[BUFSIZ];
                	char inB = 0;
                
                	int allocCheck = FALSE;
                
                	int index = 0;
                
                	while ( allocCheck )
                	{
                		// prompt the user for input
                		fprintf(stdout, "\nPlease enter a string (max length is: %d)", BUFSIZ);
                
                		// get the input
                		fscanf( stdin, "%s", &(buff) );
                
                		// create the string in the table and
                		// check if the memory was allocated ok
                		if ( (ptr[index] = (char *)calloc( strlen(buff) /* + 1 uncomment to run fine ;) */, sizeof(char) ) ) == NULL )
                		{
                			return ERROR_CODE;
                		}
                
                		// copy the actual string
                		strcpy( ptr[index], buff );
                
                		// print diagnostic message
                		fprintf(stdout, "\nString successfully inserted\nPlease type any key to continue or E to terminate and press enter\n\n");
                
                		// advance the pointer to next value
                		ptr[index++];
                
                		// check for allocation limit
                		if ( ptr[index] != NULL && ptr[index][0] == (ALLOCATION_LIMIT) )
                		{
                			fprintf(stdout, "\n\nLimit reached exiting now");
                			allocCheck = TRUE;
                		}
                	}
                
                
                	return TRUE;
                
                }

                Comment

                • donbock
                  Recognized Expert Top Contributor
                  • Mar 2008
                  • 2427

                  #9
                  Originally posted by Andr3w
                  Now to donbock, I think you are wrong there the size of a pointer in a 32-bit operating system is 32 bits regardless of the size of the pointed value, and that's why it works.
                  Your program depends on sizeof(int) being the same as sizeof(void*). That is certainly true in some environments; but it is just as certainly false in others. The fact that your program works for one compilers and fails for another suggests a portability problem. I advise you to get in the habit of writing portable code whenever possible.

                  Hey! What's that pragma on line 30? It looks like you're suppressing a warning. Unsuppress it so we can see if it is a clue to your problems. For that matter, turn on all of the compile-time warnings you can. I trust you will tell us if there are any warnings.

                  Comment

                  • donbock
                    Recognized Expert Top Contributor
                    • Mar 2008
                    • 2427

                    #10
                    Originally posted by Andr3w
                    Code:
                    // set true false macros
                    #define TRUE 0;
                    #define FALSE 1;
                    It is virtually universal practice to use a nonzero value for true (typically "1") and "0" for false. Was this a typo or did you intend to do it this way? Statements like if(TRUE){...} or while(FALSE){.. .} will do the exact opposite of what you expect. The hangs you're experiencing might be caused by inadvertently infinite loops.

                    Comment

                    • Andr3w
                      New Member
                      • Nov 2007
                      • 42

                      #11
                      Well, in unix systems true is supposed to be 0 (if a thread is successful it returns 0) and most main function do so. Also most ANSI C functions return 0 when they succeed and a non-zero value if they don't or want to indicate a status (like strlen) Please try to compile the program and see what I am saying by uncommenting the +1 offset that I have in line 122.

                      Now for the pragma in newer versions of visual studio microsoft has new more "secure" function to replace the legacy printf, fprintf and so on using printf_s, fprintf_s etc, if you don't disable that is nugs you with a warning during compile time in newer versions which is annoying and I tend to disable it all the time :P

                      We chat so much while the original user hasn't responded yet!! kewl!! ^_* haha

                      Comment

                      • donbock
                        Recognized Expert Top Contributor
                        • Mar 2008
                        • 2427

                        #12
                        Originally posted by Andr3w
                        Well, in unix systems true is supposed to be 0 (if a thread is successful it returns 0) and most main function do so. Also most ANSI C functions return 0 when they succeed and a non-zero value if they don't or want to indicate a status (like strlen)
                        I would be happier if you used the terms SUCCESS and FAILURE rather than TRUE and FALSE. The C Standard is clear and unambiguous: an integer value of zero means false and any nonzero value means true.

                        Comment

                        • Andr3w
                          New Member
                          • Nov 2007
                          • 42

                          #13
                          Well, in any case whatever differences we have in our coding style in this post we are not here to debate on how we write code :P at least I think that...

                          Comment

                          • donbock
                            Recognized Expert Top Contributor
                            • Mar 2008
                            • 2427

                            #14
                            I would like to continue this discussion of the advantages and disadvantages associated with the values you decide to use for TRUE and FALSE; but I realized that we're hijacking this thread. I copied the relevant posts to the new TRUE/FALSE values: Point / Counterpoint thread where we can continue if you like.

                            Comment

                            Working...