Reallocate a 2d char array - c

I have following code
int wordLenght = 256, arrayLength = 2, i = 0, counter = 0;
char **stringArray = NULL;
stringArray = calloc(arrayLength, sizeof(*stringArray));
for(counter; counter<wordLenght; counter++)
stringArray[counter] = calloc(wordLenght, sizeof(stringArray));
while(1)
{
printf("Input: ");
fgets(stringArray[i], wordLenght, stdin);
printf("stringArray[%d]: %s\n", i, stringArray[i]);
if(i == arrayLength)
{
printf("Reallocation !!!\n");
arrayLength *= 2;
stringArray = realloc(stringArray, arrayLength*sizeof(*stringArray));
}
i++;
}
I get this reallocation error:
*** glibc detected *** ./stringArray: realloc(): invalid next size: 0x0000000000b49010 ***
======= Backtrace: =========
/lib/libc.so.6(+0x775b6)[0x7f4dd12565b6]
/lib/libc.so.6(+0x7dd66)[0x7f4dd125cd66]
/lib/libc.so.6(realloc+0xf0)[0x7f4dd125d080]
./stringArray[0x4007f9]
/lib/libc.so.6(__libc_start_main+0xfd)[0x7f4dd11fdc4d]
./stringArray[0x400629]
What's my problem here ???
Thanks, greets

stringArray = calloc(arrayLength, sizeof(*stringArray));
Here you probably wanted to use sizeof(char*)
for(counter; counter<wordLenght; counter++) stringArray[counter] = calloc(wordLenght, sizeof(stringArray));
Here you are looping 256 times (wordLenght) but you should only 2 times (arrayLength). Additionally you probably wanted to use sizeof(char) instead of sizeof(stringArray).
if(i == arrayLength) {...}
This check should be done before you call fgets, because right now you are firstly using memory and later allocate them.
Additionally after you reallocate stringArray you need to allocate rest of strings using something like this
for(counter = i; counter<arrayLength; counter++) stringArray[counter] = (char*)calloc(wordLenght, sizeof(char));
And finally you need to free all allocated memory before you exit application.

You probably didn't mean sizeof(*stringArray)
In fact I believe you may want to relook at the calloc call too, I think you are allocating the size of the pointer there (word length times).

After the first time this line executes:
stringArray = realloc(stringArray, arrayLength*sizeof(*stringArray));
then stringArray[arrayLength/2] will be a garbage value - you haven't set it to point to storage for the word.
This part should use either use sizeof(**stringArray), or 1 as **stringArray is char, and the counter should only go up to arrayLength:
for(counter; counter<wordLenght; counter++)
stringArray[counter] = calloc(wordLenght, sizeof(stringArray));
Instead allocate in one block:
char* block = malloc(wordLength * arrayLength);
for ( counter; counter < arrayLength; ++counter )
stringArray[counter] = block + ( counter * wordLength );
At the moment, it's possible that there is some space after stringArray, into which you are storing the (wordLength-arrayLength) extra pointers when you calloc them, and realloc doesn't move stringArray.
It's quite probable that 0xb49010 is one of the pointers you calloc'd, and you're overwritten the memory where malloc keeps its block size..
But since you're writing off the end of stringArray, you're into undefined behaviour anyway.

Ok here is the whole solution:
int wordLength = 256, arrayLength = 2, i = 0, counter = 0;
char **stringArray = NULL;
char buffer[wordLength];
stringArray = calloc(arrayLength, sizeof(char*));
for(counter; counter<arrayLength; counter++) stringArray[counter] = (char*)calloc(wordLength, sizeof(char));
while(1)
{
if(i == arrayLength)
{
printf("Reallocation !!!\n");
arrayLength *= 2;
stringArray = realloc(stringArray, arrayLength*sizeof(char*));
for(counter = i; counter<arrayLength; counter++) stringArray[counter] = (char*)calloc(wordLength, sizeof(char));
}
printf("Input: ");
fgets(buffer, wordLength, stdin);
if(!strcmp(buffer,"q\n")) break; // also free here
else stringArray[i] = buffer;
printf("stringArray[%d]: %s\n", i, stringArray[i]);
i++;
}
How is the best way to free the space ?!

Related

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;
}

realloc() seems to affect already allocated memory

I am experiencing an issue where the invocation of realloc seems to modify the contents of another string, keyfile.
It's supposed to run through a null-terminated char* (keyfile), which contains just above 500 characters. The problem, however, is that the reallocation I perform in the while-loop seems to modify the contents of the keyfile.
I tried removing the dynamic reallocation with realloc and instead initialize the pointers in the for-loop with a size of 200*sizeof(int) instead. The problem remains, the keyfile string is modified during the (re)allocation of memory, and I have no idea why. I have confirmed this by printing the keyfile-string before and after both the malloc and realloc statements.
Note: The keyfile only contains the characters a-z, no digits, spaces, linebreaks or uppercase. Only a text of 26, lowercase letters.
int **getCharMap(const char *keyfile) {
char *alphabet = "abcdefghijklmnopqrstuvwxyz";
int **charmap = malloc(26*sizeof(int));
for (int i = 0; i < 26; i++) {
charmap[(int) alphabet[i]] = malloc(sizeof(int));
charmap[(int) alphabet[i]][0] = 0; // place a counter at index 0
}
int letter;
int count = 0;
unsigned char c = keyfile[count];
while (c != '\0') {
int arr_count = charmap[c][0];
arr_count++;
charmap[c] = realloc(charmap[c], (arr_count+1)*sizeof(int));
charmap[c][0] = arr_count;
charmap[c][arr_count] = count;
c = keyfile[++count];
}
// Just inspecting the results for debugging
printf("\nCHARMAP\n");
for (int i = 0; i < 26; i++) {
letter = (int) alphabet[i];
printf("%c: ", (char) letter);
int count = charmap[letter][0];
printf("%d", charmap[letter][0]);
if (count > 0) {
for (int j = 1; j < count+1; j++) {
printf(",%d", charmap[letter][j]);
}
}
printf("\n");
}
exit(0);
return charmap;
}
charmap[(int) alphabet[i]] = malloc(sizeof(int));
charmap[(int) alphabet[i]][0] = 0; // place a counter at index 0
You are writing beyond the end of your charmap array. So, you are invoking undefined behaviour and it's not surprising that you are seeing weird effects.
You are using the character codes as an index into the array, but they do not start at 0! They start at whatever the ASCII code for a is.
You should use alphabet[i] - 'a' as your array index.
The following piece of code is a source of troubles:
int **charmap = malloc(26*sizeof(int));
for (int i = 0; i < 26; i++)
charmap[...] = ...;
If sizeof(int) < sizeof(int*), then it will be performing illegal memory access operations.
For example, on 64-bit platforms, the case is usually sizeof(int) == 4 < 8 == sizeof(int*).
Under that scenario, by writing into charmap[13...25], you will be accessing unallocated memory.
Change this:
int **charmap = malloc(26*sizeof(int));
To this:
int **charmap = malloc(26*sizeof(int*));

Invalid read - Valgrind and C

New to C and Valgrind and manual memory management and I'm having trouble locating an error that I'm getting when I run Valgrind. I have this function which gets strings from the user:
char **get_fragments_from_user(){
// No more than 20k strings containing at most 1k characters
char **strings = malloc(20000 * sizeof(char *));
char tempstring[MAX_INPUT]; //MAX_INPUT = 1001
int count = 0;
while(true){
printf("\n> ");
fgets(tempstring, MAX_INPUT, stdin);
if((strlen(tempstring) > 0) && (tempstring[strlen(tempstring) - 1] == '\n')){
tempstring[strlen(tempstring) - 1] = '\0';
}
if(tempstring[0] == 'q') break;
strings[count] = malloc(sizeof(char) * (strlen(tempstring)+1));
strcpy(strings[count], tempstring);
count++;
}
int i = 0;
char **fstrings = malloc((count)*sizeof(char *)); // count+1 needed? Something I tried removing while debugging
for(i = 0; i < count; i++){
fstrings[i] = malloc(sizeof(char) * (strlen(strings[i])+1));
strcpy(fstrings[i], strings[i]);
free(strings[i]);
}
free(strings);
return fstrings;
}
The idea here is simply to get strings and put them in an array. I initially allocate an array that is large enough to fit the maximum number of strings that could ever be entered (20,000), but I then resize the array so that I don't allocate more memory than the each string needs. I am a little embarrassed with the above code, since its less clean than anything I would have written in another language, but that was my first pass through.
I then get "Invalid read of size 8" from Valgrind when I try to calculate the number of strings in the array using this function:
int lengthOf(char **arr){
int i = 0;
while(arr[i] != NULL){
i++;
}
return i;
}
I'm pretty sure this is due to a dereferenced pointer or something, but I can't find it for the life of me and I've been looking at this code for an hour or so.
So, I believe the problem was that I wasn't allocating enough memory to store the whole array.
Instead of doing:
malloc(count * sizeof(char *));
I should have been allocating count+1, so either:
malloc((count + 1) * sizeof(char *))
or
calloc((count + 1), sizeof(char *));

glibc detected, realloc(): invalid old size C

Admittedly what I was trying to do was at best educated guess work.
I have an array of strings, and I was trying to account for if someone entered a string that was too large, or the array received too much input (it needs to be dynamic for what I'm trying to do)
here's the section of code that's breaking:
if (strlen(token) > wordlength)
{
wordlength *= 2;
for(int j = 0; j < numwords; j++)
{
char* tmpw = realloc(wordarray[j], wordlength);
assert(tmpw != NULL);
wordarray[j] = tmpw;
printf("increased size of words to %zu \n", wordlength);
}
}
Explanations:
Token is the next word being taken in (I'm parsing a string) so I compare it to the current word length, if it's too big, i double word length and try to adjust the array accordingly.
If you need any more information let me know
initialization of wordarray:
wordarray = malloc(numwords);
for(int i = 0; i < numwords; i++)
wordarray[i] = malloc(wordlength);
Another place where realloc crashes:
if (arraycounter > numwords)
{
numwords *= 2;
char** tmp = realloc(wordarray, numwords);
assert(tmp != NULL);
wordarray = tmp;
for(int h = arraycounter; h < numwords; h++)
wordarray[h] = malloc(wordlength);
printf("increased size of wordarray to %zu \n", numwords);
}
In this situation, it would attempt to increase the size of the array if it was about to go over the initial set limit, so would not be affected due to token running out of memory (tested with 20 small words and it crashed on its attempt to resize)
You need
wordarray = malloc(numwords * sizeof *wordarray);
Also, what do you want to happen when your program is compiled without assert and run on a system with low memory? I mean, the use of assert() is probably wrong.

problem in char array?

char *funcNames[]= {"VString","VChar","VArray","VData"};
for(int i=0;i<4;i++)
{
char* temp = funcNames[i];
int len = strlen(funcNames[i]);
for(int j = 0;j<len ;j++)
{
if(j!=0)
{
char arr = temp[j];
}
}
}
here i want to separate "V" from all string in char array ...and create another char array without "V" in starting of the string.i want another char array {String,char,array,data}...i cant make a char array ....help me to solve my issue...
Do you really need a copy? You could just make a new array pointing into the original strings:
char *newArray[4];
for (i = 0; i < 4; i++) {
newArray[i] = funcNames[i] + 1;
}
If you do need to make copies then you'll have to use dynamical allocation to create the buffers to hold the copies. What you will do is declare an array of pointers and place an allocated string buffer in each of the array's entries:
char *newArray[4];
for (i = 0; i < 4; i++) {
newArray[i] = malloc(sizeof(char) * streln(funcNames[0]));
strcpy(newArray[i], funcNames[i] + 1);
}
You will have to call free() on each allocated buffer.
Or if you don't want to do allocation and are know the maximum length of the strings in funcNames:
#define MAX_FUNC_NAME_LEN 32
char newArray[4][MAX_FUNC_NAME_LEN];
for (i = 0; i < 4; i++) {
strcpy(newArray[i], funcNames[i] + 1);
}
There's only small differences between arrays and pointers so I'd opt for:
#include <stdio.h>
#include <string.h>
#include <assert.h>
int main (void) {
int i;
char *funcNames[]= {"VString","VChar","VArray","VData"};
// This is the code that dupicates your strings by allocating an array,
// then allocating each string within that array (and copying).
// Note we use strlen, not strlen+1 to mallocsince we're replacing the
// 'V' at the start with the zero byte at the end. Also we strcpy
// from char offset 1, not 0 (to skip the fist char).
char **newNames = malloc (sizeof(char*) * sizeof(funcNames) / sizeof(*funcNames));
assert (newNames != NULL);
for (i = 0; i < sizeof(funcNames) / sizeof(*funcNames); i++) {
newNames[i] = malloc (strlen (funcNames[i]));
assert (newNames[i] != NULL);
strcpy (newNames[i], funcNames[i] + 1);
}
/* Use your newNames here */
for (i = 0; i < sizeof(funcNames) / sizeof(*funcNames); i++) {
printf ("funcNames[%d] #%08x = '%s'\n", i, funcNames[i], funcNames[i]);
printf (" newNames[%d] #%08x = '%s'\n", i, newNames[i], newNames[i]);
putchar ('\n');
}
// Finished using them.
// Free the strings themselves, then free the array.
for (i = 0; i < sizeof(funcNames) / sizeof(*funcNames); i++)
free (newNames[i]);
free (newNames);
return 0;
}
You can see from the output that the locations of the variables in memory are different and that the content of the new strings is what you wanted:
funcNames[0] #00402000 = 'VString'
newNames[0] #006601c0 = 'String'
funcNames[1] #00402008 = 'VChar'
newNames[1] #006601d0 = 'Char'
funcNames[2] #0040200e = 'VArray'
newNames[2] #006601e0 = 'Array'
funcNames[3] #00402015 = 'VData'
newNames[3] #006601f0 = 'Data'

Resources