Checking NULL Pointer In C Doesn't Work - c

I have a function which returns a multiple indirection pointer as result like so:
typedef struct {
int id;
char *name;
} user;
user **myfn(int users_count) {
user **a;
a = malloc(sizeof(user) * user_counts);
for(int i = 0 ; i<user_counts ; i++) {
*(a+i) = malloc(sizeof(user));
(*(a+i))->id = 1;
(*(a+i))->name = malloc(sizeof(char) * 25);
strncpy((*(a+i))->name, "Morteza", 25); // just for example
}
return a;
}
Now, I when I want to crawl in this result in main function, it will show all users name, but at the end it will encounter with Segmentation fault error.
int main() {
user **a = myfn(10);
int i = 0;
while((*(a+i)) != NULL) {
printf("ID: %d \t %s\n", (*(a+i))->id, (*(a+i))->name);
i++;
}
}
Results:
ID: 1 Morteza
ID: 2 Morteza
...
...
ID: 10 Morteza
Segmentation fault (core dumped)
Why condition of while doesn't work fine?

First of all,
a = malloc(sizeof(user) * user_counts);
has a problem - you want to allocate user_counts instances of pointers to user, not instances of user, so that line should be
a = malloc(sizeof(user *) * user_counts);
However, there's an easier way around this - the sizeof operator can take expressions as arguments as well as type names. So you can rewrite that line as
a = malloc( sizeof *a * user_counts );
The expression *a has type user *, so sizeof *a is equivalent to sizeof (user *). This makes your life a bit simpler, in that you don't have to puzzle out the type that a points to - make the compiler do the hard work.
You should always check the result of a malloc call.
a = malloc( sizeof *a * users_count );
if ( a )
{
// do stuff with a
}
Second of all, don't use *(a+i) to index into a - use a[i] instead. Makes things a bit easier to read. So,
*(a+i) = malloc(sizeof(user));
(*(a+i))->id = 1;
(*(a+i))->name = malloc(sizeof(char) * 25);
becomes
a[i] = malloc(sizeof *a[i]);
if ( a[i] )
{
a[i]->id = 1;
a[i]->name = malloc(sizeof *a[i]->name * 25);
}
else
{
/* deal with memory allocation failure */
}
Now, to your actual problem. Your code is crashing for one of the following reasons:
the initial malloc of a failed, so you're crashing on the first line that uses a[i];
the malloc of one of your a[i] failed, so you're crashing on a[i]->id = 1;
you've successfully allocated memory for all users_count elements of a - no a[i] is NULL, so you loop past the last element of your array and try to dereference the object immediately following it, which is most likely not a valid pointer.
In addition to adding the checks after each malloc call, you should probably loop based on users_count:
for ( i = 0; i < users_count; i++ )
printf("ID: %d \t %s\n", a[i]->id, a[i]->name);
Or, you need to allocate one extra element for a and set it to NULL:
a = malloc( sizeof *a * (users_count + 1) );
if ( a )
{
a[users_count] = NULL;
for ( i = 0; i < users_count; i++ )
...
}
Note that calloc initializes all allocated memory to 0, so you can use that and not worry about explicitly setting an element to NULL:
a = calloc( users_count + 1, sizeof *a );
if ( a )
{
for ( i = 0; i < users_count; i++ )
...
}

Related

Problems freeing memory using free()

I have been trying to write a function that will insert commas into a binary number.
Below is my best attempt. It does work if I do NOT try to free() the memory.
If I try to free() the memory, I get an error.
I am puzzled. Please let me know what I am doing wrong.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int insertCommasIntoBinaryNumber(char* outstring, char* instring)
{
char *ptr, *optr;
int i, length, commas;
// move ptr to end of instring
for ( ptr = instring; *ptr; ptr++ );
//calculate offset with commas
length = ptr - instring;
commas = ( length - 1 ) / 8;
optr = outstring + length + commas;
//copy instring into outstring backwards inserting commas
*optr-- = *ptr--;
for ( i = 1; ptr >= instring; i++ )
{
*optr-- = *ptr--;
if ( ( i % 8 ) == 0 )
*optr-- = ',';
}
}
int main (void)
{
const int arrayDimension = 100;
char* instring = (char*) malloc(sizeof(char) * arrayDimension);
char* outstring = (char*) malloc(sizeof(char) * arrayDimension);
strncpy(instring, "111111110101010100001100", arrayDimension-1);
insertCommasIntoBinaryNumber(outstring, instring);
/* show the result */
printf ( "%s\n", outstring );
free(instring);
free(outstring);
}
Here is the output:
11111111,01010101,00001100
*** Error in `./a.out': free(): invalid next size (fast): 0x0000000000bc8010 ***
P.S. Many thanks for letting me know where the code was crashing on the 24th iteration. I soon realized that I was not calculating the number of commas needed correctly and not keeping track of the number of commas being inserted. After I did that, the code below appears to work fine now.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
int insertCommasIntoBinaryNumber(char* const outString, const char* const inString)
{
char const *iptr; // iptr will be a pointer to the
// constant inString char array.
char *optr;
int i, commaCount;
// move iptr to end of inString
for ( iptr = inString; *iptr; iptr++ );
// Calculate Number of Commas Needed
const int inStringLength = iptr - inString;
const double totalNumberOfCommasFP = (( inStringLength ) / 8.0) - 1.0;
const int totalNumberOfCommas = (int) ceil(totalNumberOfCommasFP);
// Set optr
optr = outString + inStringLength + totalNumberOfCommas;
//copy inString into outString backwards inserting commas
*optr-- = *iptr--;
commaCount = 0;
for ( i = 1; iptr >= inString; i++ )
{
*optr-- = *iptr--;
if ( ( ( i % 8 ) == 0 ) && (commaCount < totalNumberOfCommas) )
{
*optr-- = ',';
commaCount++;
}
}
}
int main (void)
{
const char testString[] = "111111110101010100001100";
const int inStringArrayDimension = strlen(testString) + 1;
char * inString = (char*) malloc(sizeof(char) * inStringArrayDimension);
strncpy(inString, testString, inStringArrayDimension);
const int inStringLength = (int) strlen(inString);
const double totalNumberOfCommasFP = (( inStringLength ) / 8.0) - 1.0;
const int totalNumberOfCommas = (int) ceil(totalNumberOfCommasFP);
const int outStringArrayDimension = inStringArrayDimension + totalNumberOfCommas;
char* outString = (char*) malloc(sizeof(char) * outStringArrayDimension);
insertCommasIntoBinaryNumber(outString, inString);
/* show the result */
printf ( "%s\n", outString );
free(inString);
free(outString);
exit (EXIT_SUCCESS);
}
And here is the output:
11111111,01010101,00001100
Since the string length is 24, for ( i = 1; ptr >= instring; i++ ) iterates 24 times. On the 24th iteration, optr points to the first character of outstring. Since (i % 8) == 0 is true, *optr-- = ','; is executed. That puts a comma before outstring, writing outside array bounds and corrupting your program’s memory.
I recommend that you do this
#include <assert.h>
//copy instring into outstring backwards inserting commas
assert (optr >= outstring);
*optr-- = *ptr--;
for ( i = 1; ptr >= instring; i++ )
{
assert (optr >= outstring);
*optr-- = *ptr--;
if ( ( i % 8 ) == 0 ) {
assert (optr >= outstring);
*optr-- = ',';
}
}
Then when the assertion goes off, debug it. You have almost certainly botched the space calculation, under-estimating how much space is needed to store the version of the datum with commas inserted.
Secondly, you're doing something that ISO C does not require to work: incrementing pointers below the start of an object. This is not the actual problem; even if you debug the malloc corruption, that issue is still there.
What I'm getting at is that this is not a correct idiom:
for (ptr = end_of_object; ptr >= start_of_object; ptr--)
{
// ... loop body in which ptr is dereferenced
}
Here is why. When the last iteration of the loop occurs, ptr == start_of_object holds. The body of the loop is executed, and then, unconditionally, the ptr-- decrement is executed. Even though we do not execute the loop body any more, and therefore do not dereference ptr, it is still incorrect to be decrementing it. It is undefined behavior according to ISO C.
The idiom works in machine languages.
One way to avoid it is to use integer indexing.
for (i = num_elements - 1; i >= 0; i--)
{
// work with array[i]
}
Here, i is assumed to be a signed integer type. At the top of the last iteration, i == 0 holds. Then, unconditionally, i is decremented to -1. Since array[i] is never accessed in this case, that is completely safe.
Lastly, a robust, production version of this type of code cannot just assume that you have all the space in the destination array. Your comma-inserting API needs to provide some means by which the caller can determine how much space is required. E.g.:
const char *str = "1110101101";
// determine how much space is needed for string with commas
size_t space = comma_insert_space_required(str);
// OK, allocate that much space
char *str_with_commas = malloc(space);
// now process the same string into that space
comma_insert(str_with_commas, str);
This will work whether you have a five character input or five thousand.
If you choose an approach involving artificial limits in there like 100 bytes (the idea being no valid inputs will ever occur that come close), you still need defenses against that, so that you don't access an object out of bounds. "Bad guys" trying to break your software will look for ways to sneak in the "never occur" inputs.

How to add this information to an array?

I've got this project in C and the code looks like this.
BOOL Commands(LPBYTE command, DWORD size)
{
wchar_t params[MAXCHAR];
MultiByteToWideChar(CP_ACP, MB_COMPOSITE, (LPCCH)command, size, params, size);
wchar_t *bufferoon;
bufferoon = (wchar_t *)malloc(sizeof(wchar_t) * size);
wcscpy(bufferoon, params);
wchar_t buf2[MAXCHAR], *ptr;
int i;
wchar_t a[MAXCHAR];
for (ptr = wcstok(bufferoon, L","); ptr != NULL; ptr = wcstok(NULL, L","))
{
CWA(lstrcpyW, kernel32, buf2, ptr);
for (i = 0; i < lstrlenW(buf2); i++)
{
if (buf2[i] == '=' )
{
wcscpy(a + i, buf2 + i + 1);
MessageBoxW(0, a + i, 0, 0);
}
}
}
free(bufferoon);
CWA(Sleep, kernel32, 100);
return 1;
}
It gets a string from a PHP page and then splits it, removes the "=" and some junk before the "=" and and displays the important datas in MessageBoxes one by one and it works well.
However, instead of showing it in messageboxes, I want to create an array with all the data.
For example, some of the data returned as "a + i" will include:
1. https
2. //test.com/test.doc
3. H3IG2IOUFG23IOFGU2H3
Etc.
I want to create an array, so I can use it to make if-statements.
For example, I want to be able to do something like:
if(strarray[1] == L"https")
{
MessageBoxW(0,L"Element 1 equals HTTPS",0,0);
}
However, after trying a million things for hours and hours, I have still no clue, so I am asking you guys on StackOverflow as a last resort.
Does anyone have an idea? My brain is fried by now, I would really appreciate it if someone could help me out.
Thanks in advance!
If you want to use an array, you need to know the size. You have two choices:
1) Allocate an array of N elements using malloc (just pick some number N), populate the array, and increment your size variable. If size exceeds N, you will need to realloc with a bigger N.
2) Perform two loops. The first loop counts the number of array elements. After the first loop ends, use malloc to allocate the array knowing the size. Then perform a second loop to populate the array.
int N=0;
wchar_t *saved = wcsdup(bufferoon);
for (ptr = wcstok(bufferoon, L","); ptr != NULL; ptr = wcstok(NULL, L","))
{
for (i = 0; i < lstrlenW(ptr); i++)
{
if (ptr[i] == '=' )
{
++N;
break;
}
}
}
int j=0;
wchar_t **a = malloc(N*sizeof(*a));
for (ptr = wcstok(saved, L","); ptr != NULL; ptr = wcstok(NULL, L","))
{
for (i = 0; i < lstrlenW(ptr); i++)
{
if (ptr[i] == '=' )
{
a[j++] = wcsdup(ptr+i+1);
break;
}
}
}
free(saved);

How to manipulate the value of a char pointer from a external function in C?

I'm intending to create a function that has a similar job of the scanf, but that I will not need to define the length of my char array, only defining the pointer ( and using malloc() ).
At this point, I want to make this header file to only have to include and use it when I need.
Here is my external function, inside of string.variavel.h:
# include <stdio.h>
# include <stdlib.h>
void pegastr( char *str ){
char x , *guardaStr ;
unsigned int i , j ;
str = malloc( 1 );
str[0] = '\0';
for( j = 0 ; x != '\n' ; ++j ){
x = getc( stdin );
fflush( stdin );
guardaStr = malloc( j );
for( i = 0 ; i < j ; ++i ){
guardaStr[i] = str[i];
}
str = malloc( 1 + j );
for ( i = 0 ; i < j + 1 ; ++i ){
if( guardaStr[i] == '\0' ){
str[i] = x ;
}else{
str[i] = guardaStr[i] ;
}
}
str[i] = '\0';
}
}
And here is my function that calls and include the externals:
# include "string.variavel.h"
int main(void){
char *palavrao , *torrada;
pegastr( palavrao );
pegastr( torrada );
printf( "%s\n%s" , palavrao , torrada );
return 0;
}
So, my problem is that if I copy all code of pegastr() to inside of main(), when I try to output the string it works, but, if I don't do this and let the code stays like it is right now, when I try to output the value of the strings inside the main(), I only gets (null) at each printf().
I think that my problem is with the address that I send/receive to/from the parameters of my function pegastr(), but I don't see what I need to change more.
My thanks for all of your help!
The code you pasted has a lots of problems with memory handling. You have memory leaks and what you do there is not very clear.
I'm going to address the main problem you have here, from what I understood after reading your question. This is generally about pointers and how they work.
If you want to allocate a pointer in a function and return it, you can A) pass a pointer to the pointer or B) return the pointer.
A)
// call: myallocator(&element, size)
void myallocator(char **element, size_t size)
{
*element = malloc(size);
// ...
}
B)
// call: element = myallocator(size)
char* myallocator(size_t size)
{
char *mem;
mem = malloc(size);
// ...
return mem;
}
If I copy all your code into main, it still just prints the null. In general your program has undefined behavior and won't work (regardless of where you put the code)
Your first problem is that the function does not change the value of palavrao and torrada. The function is just called with the value of the pointers and no matter how much you change the value inside the function, the variables outside still have the same value.
Instead you can do it like:
void pegastr( char **str ){ // Note double pointer
....
*str = malloc(....
}
// Called like
pegastr( &palavrao );
or like
char* pegastr(){ // Return the malloc'ed pointer
char * tmp = malloc(....
....
return tmp;
}
// Called like
palavrao = pegastr();
Besides that your code have quite a number of things you need to fix:
for( j = 0 ; x != '\n' ; ++j ){
^
x is uninitialized when the loop starts
and
guardaStr = malloc( j );
^
Do you want this when j is 0 ?
Or do you really want j + 1 here ?
Further you you have memory leak when you run this code the 2nd, 3rd, ... time. You need to free the memory before overwrint the old pointer with a new pointer.
The memory leak also applies to:
str = malloc( 1 + j );
And here:
if( guardaStr[i] == '\0' ){
^^^^^^^^^^^^
Access outside allocated memory (e.g. when j is 0)
I'll suggest that you read about realloc - it is a better choice for your code.
Using realloc the code could be something like:
# include <stdio.h>
# include <stdlib.h>
void pegastr( char **str ){
char *tmp;
char x;
unsigned int j ;
tmp = malloc( 1 );
if (tmp == NULL)
{
// Out of memory
exit(1);
}
str[0] = '\0';
j = 1; // Notice: j starts from 1
while(1){
x = getc( stdin );
if (x == '\n')
{
// Don't copy the \n - just break the loop
break;
}
fflush( stdin );
// Insert the new char and a termination
tmp = realloc(tmp, j+1);
if (tmp == NULL)
{
// Out of memory
exit(1);
}
tmp[j-1] = x;
tmp[j] = '\0';
// Increment j
++j;
}
// Update the input pointers value
*str = tmp;
}
int main(void){
char *palavrao , *torrada;
pegastr( &palavrao );
pegastr( &torrada );
printf( "%s\n%s\n" , palavrao , torrada );
free(palavrao);
free(torrada);
return 0;
}

Reallocation of Multi-dimensonal Pointer Array Causing Segmentation Fault

First, I'll explain why I'm doing this the way that I am. I'm taking a course in computer programming and my professor has given us an assignment where we have to make an array of records(each contains a first name, last name, & score), and then allow the user to manipulate the records using menu options. All of this MUST be done using only pointer arrays, and structures are not allowed. I know it is a headache. I know it probably one of the most difficult ways to accomplish this, but its what the professor wants.
With that out of the way, below is what I have for my main function so far. most of the long printf functions are just me printing debugging information. Please take note of the declaration of the char*** variable. It is meant to function as a 3D array where nameRecords[0] would be the first record, nameRecords[0][0] would be the first name of the first record, and nameRecords[0][1] is the last name of the first record. The third dimension is nameRecords[0][0][21], as the strings are only meant to be 20 characters long plus null character.
int main(void)
{
char ***nameRecords = NULL;
float *scores = NULL;
int size = 0; // total number of records
int usrInt = 0;
while(usrInt < 1)
{
printf("\nEnter the number of records to record(min 1): ");
scanf("%d", &usrInt);
inpurge();
if(usrInt < 1) printf("\nMust be integer greater than 1.\n");
}
nameRecords = (char***)calloc((size), sizeof(char**));
scores = (float*)calloc(size, sizeof(float));
int i;
for(i = 0; i < usrInt; i++)
{
addRecord(&nameRecords, &scores, &size);
printf("\nnameRecords#%p :: nameRecords[%d]#%p :: nameRecords[%d][0]=%s :: nameRecords[%d][1]=%s\n", nameRecords, size - 1, nameRecords[size - 1], size - 1, nameRecords[size - 1][0], size - 1, nameRecords[size - 1][1]);
}
printf("\nnameRecords[0]#%p\n", nameRecords[0]);
prntRecords(nameRecords, scores, size);
printf("\n\n\n");
return 0;
}
The trouble comes after I pass, for the SECOND TIME, &nameRecords into the addRecord function, defined below. To clarify, the segmentation fault is not received if the user chooses to enter only 1 entry at the beginning of the main function, and the program actually runs and terminates as expected.
void addRecord(char ****records, float **scores, int *size)
{
printf("\t(*records)[0]%p\n", (*records)[0]);
++*size; // increment total number of records by 1
int index = (*size) - 1;
char ***tempNames = (char***)realloc(*records, (*size) * sizeof(char**)); // reallocate larger space.
if(tempNames != *records)
*records = tempNames; // set original pointer to new value.
printf("\n\tsize - 1 = %d\n", index);
float *tempScores = (float*)realloc(*scores, (*size) * sizeof(float)); // reallocate larger space.
if(tempScores != *scores)
*scores = tempScores; // set original pointer to new value.
printf("\ttempNames[0]#%p\n", tempNames[0]);
tempNames[index] = (char**)calloc(tempNames[index], 2 * sizeof(char*));
enterRecord(tempNames[index], scores[index]);
printf("\n\ttempNames#%p :: tempNames[0]#%p :: tempNames[%d][0]=%s :: tempNames[%d][1]=%s\n", tempNames, tempNames[0], index, tempNames[index][0], index, tempNames[index][1]);
printf("\n\t*records#%p :: *records[0]#%p :: *records[%d][0]=%s :: *records[%d][1]=%s\n", *records, (*records)[0], index, (*records)[index][0], index, (*records)[index][1]);
return;
}
Below is an example output of the program. Without taking too long to explain whats happening, the tabbed lines are the lines of output from within the addRecord function. Specifically, the pointer to the first record, record[0], has been turned into a garbage value on the second pass through the addRecord function, just after the enterRecord function.
Enter the number of records to record(min 5): 2
(*records)[0](nil)
size - 1 = 0
tempNames[0]#(nil)
Enter first name: 1
Enter last name: 1
Enter score: 1
COMPLETE enterRecord
tempNames#0x6387010 :: tempNames[0]#0x6387050 :: tempNames[0][0]=1 :: tempNames[0][1]=1
*records#0x6387010 :: *records[0]#0x6387050 :: *records[0][0]=1 :: *records[0][1]=1
nameRecords#0x6387010 :: nameRecords[0]#0x6387050 :: nameRecords[0][0]=1 :: nameRecords[0][1]=1
(*records)[0]0x6387050
size - 1 = 1
tempNames[0]#0x6387050
Enter first name: 2
Enter last name: 2
Enter score: 2
COMPLETE enterRecord
tempNames#0x6387010 :: tempNames[0]#0x40000000 :: tempNames[1][0]=2 :: tempNames[1][1]=2
*records#0x6387010 :: *records[0]#0x40000000 :: *records[1][0]=2 :: *records[1][1]=2
nameRecords#0x6387010 :: nameRecords[1]#0x63870b0 :: nameRecords[1][0]=2 :: nameRecords[1][1]=2
nameRecords[0]#0x40000000
records#0x6387010 :: records[0]#0x40000000
Segmentation fault
All of the debug information points to the enterRecord function as being the culprit. So here it is, the evil enterRecord function...
void enterRecord(char **names, float *score)
{
names[0] = (char*)calloc(21, sizeof(char)); // allocate first name string
names[1] = (char*)calloc(21, sizeof(char)); // allocate last name string
printf("\nEnter first name: ");
fgets(names[0], 21, stdin);
if(strlen(names[0]) == 20) // IGNORE. just handles overflow from fgets.
inpurge();
remNewLine(names[0]); // removes '\n' character at end of string
printf("\nEnter last name: ");
fgets(names[1], 21, stdin);
if(strlen(names[1]) == 20) // IGNORE. just handles overflow from fgets.
inpurge();
remNewLine(names[1]); // removes '\n' character at end of string
printf("\nEnter score: ");
scanf("%f", score);
inpurge();
printf("\nCOMPLETE enterRecord\n");
return;
}
Only... no attempt at altering the affected pointer was made. The pointer value to the second element of the records array(records[1]) was passed into the function, and nothing I can see is altering the value of the pointer of the first element of the records array(records[0]), though the value of records[0] is what's causing the segfault.
I am very sorry for the length and all obfuscatory code. Again, this seems like a terrible approach to writing this program, but its what the situation calls for. I just feel bad for the poor teacher's aide who has to grade 30+ of these assignments.
Any help is welcomed.
this problem seems to be better implemented as
#define MAX_FIRST_NAME_LEN (21)
#define MAX_LAST_NAME_LEN (21)
#define MAX_SCORES (10)
// in file global memory...
static char **ppFirstNames = NULL;
static char **ppLastName = NULL;
static int **ppScores = NULL;
static int numOfEntries = 0;
// in the record input function, which needs NO parameters
scanf ( "%d", &numOfEntries );
if scanf fails, exit
ppFirstNames = malloc (numOfEntries*sizeof char*);
if malloc fails, exit
memset (ppFirstName, '\0', numOfEntries*sizeof char* );
ppLastName = malloc (numOfEntries*sizeof char*);
if malloc fails, free all, exit
memset (ppLastName, '\0', numOfEntries*sizeof char* );
ppScores = malloc (numOfEntries *sizeof int* );
if malloc fails, free all, exit
for(int i=0; i<numOfEntries; i++ )
ppFirstNames[i] = malloc( MAX_FIRST_NAME_LEN );
if malloc fails free all, exit
memset ( ppFirstNames[i], '\0', MAX_FIRST_NAME_LEN );
ppLastName[i] = malloc (MAX_LAST_NAME_LEN);
if malloc fails free all, exit
memset ( ppLastName[i], '\0', MAX_LAST_NAME_LEN );
ppScores[i] = malloc (MAX_SCORES *sizeof int);-1
if malloc fails, free all, exit
memset (ppScores[i], '\0', MAX_SCORES *sizeof int );
end for
for ( int i=0; i < numOfEntries; i++ )
now read each record
scanf( "%(MAX_FIRST_NAME_LEN-1)s", ppFirstNames[i] );
if scanf fails, free all, exit
scanf( "%(MAX_LAST_NAME_LEN-1)s", ppLastNames[i] );
if scanf fails, free all exit
for( int j=0; j< MAX_SCORES; j++ )
now read this students scores
int tempScore;
scanf( "%d", tempScore );
if scanf fails, free all, exit
if -1 == tempScore ) break;
ppScores[i][j] = tempScore;
end for
end for
The above is the pseudo code for inputting the records
and should be enough to get the input correct.
printing the info thereafter should be easy.
Example to use realloc for array multidimensional:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int size_initial = 10;
int **ptr;
int i, j;
ptr = (int**) malloc(sizeof (int*) * size_initial);
for (i = 0; i < size_initial; i++) {
ptr[i] = (int*) malloc(sizeof (int) * 10);
for (j = 0; j < 10; j++)
ptr[i][j] = i+j;
}
/* realloc +10 */
ptr = (int**) realloc(ptr, sizeof (int*) * (size_initial * 2));
for (i = size_initial; i < size_initial * 2; i++) {
ptr[i] = (int*) malloc(sizeof (int) * 10);
for (j = 0; j < 10; j++) {
ptr[i][j] = i+j;
}
}
/* print values */
for (i = 0; i < 20; i++) {
for (j = 0; j < 10; j++) {
printf("ptr[%d][%d] = %d\n", i, j, ptr[i][j]);
}
}
return 0;
}

Malloc affecting random integer value

I'm writing a virtual memory simulator in C, compiling on linux, and I'm getting something rather strange. It takes in a file IO, which I put into an int* plist.
I've printed this "plist" array, and it comes out to
0 100
1 200
2 400
3 300
etc
The problem is that it seems malloc or something is randomly changing plist[3] to 0. It doesn't seem like it should be that way, but I've put a print statement at every line of code to print plist[3], and
tables[i].valid = (char*) xmalloc(num_pages * sizeof(char));
is where it changes. plist[3] = 300 before the line, 0 after it. And it only does this when i = 2. The first 3 rounds of the loop run fine, and on round 3, it changes the values for round 4. I have no idea why, it makes little sense that malloc would change a value in an array that's completely unrelated - is it possible I've gone over some space limit, even though I'm using the heap for basically everything? Would it just change values in random arrays if I did?
for(i = 0; i < 4; i++){
num_pages = plist[i] / P1;
tables[i].page_num = (char**) xmalloc(num_pages * sizeof(char*));
tables[i].valid = (char*) xmalloc(num_pages * sizeof(char));
//initialize page numbers and valid bits
for(j = 0; j < 10; j++){
tables[i].page_num[j] = (char*) xmalloc(16*sizeof(char));
tmp = itoa(i, tmp);
strcat(tables[i].page_num[j], tmp);
strcat(tables[i].page_num[j], "p");
tmp = itoa(j, tmp);
strcat(tables[i].page_num[j], tmp);
tables[i].valid[j] = 0;
}
}
Here's the struct for tables:
typedef struct s_page_table
{
char** page_num;
char* valid;
} t_page_table;
And this is xmalloc (it's just a wrapper to make it easier):
void* xmalloc(int s)
{
void* p;
p = malloc(s);
if (p == NULL)
{
printf("Virtual Memory Exhausted");
exit(1);
}
return p;
}
EDIT: If I take out both lines referencing tables[i].valid, the problem does not exist. plist[3] stays the same. num_pages is always >= 10. I set j to be 0 to 10 just to have less output for debugging purposes.
EDIT 2: If I change valid from a char* to an int* it doesn't work. If I change it to an int, it does.
There are several possibilities, including (but not limited to):
tables[i] is out of bounds;
plist contains a dangling pointer (i.e. it's been deallocated);
plist hasn't been initialised;
plist isn't as large as you think, i.e. plist[3] is out of bounds.
If you can't figure out the problem by looking at the code, valgrind is your friend.
OK. So I believe the problem turned out to be playing with the strings before initializing everything. I'm not entirely certain the reason, maybe someone else can elaborate, but when I encapsulated JUST the initialization in its own function, like only doing mallocs, and then separately created the strings afterwards, the plist variable was unaffected.
For those interested, the encapsulated function looked like this:
t_page_table* table_builder(int* p, int x, int num_tables)
{
t_page_table* ret = xmalloc(num_tables * sizeof(*ret));
int i, tmp, j;
for(i = 0; i < num_tables; i++){
tmp = (p[i]/x);
ret[i].page_num = xmalloc(tmp * sizeof(char*));
ret[i].valid = xmalloc(tmp * sizeof(char));
for(j = 0; j < tmp; j++){
ret[i].page_num[j] = xmalloc(16 * sizeof(char));
ret[i].valid = 0;
}
}
return ret;
}

Resources