I'm trying to do a program that get number of names from the user, then it get the names from the user and save them in array in strings. After it, it sort the names in the array by abc and then print the names ordered. The program work good, but the problem is when I try to free the dynamic memory I defined.
Here is the code:
#include <stdio.h>
#include <string.h>
#define STR_LEN 51
void myFgets(char str[], int n);
void sortString(char** arr, int numberOfStrings);
int main(void)
{
int i = 0, numberOfFriends = 0, sizeOfMemory = 0;
char name[STR_LEN] = { 0 };
char** arrOfNames = (char*)malloc(sizeof(int) * sizeOfMemory);
printf("Enter number of friends: ");
scanf("%d", &numberOfFriends);
getchar();
for (i = 0; i < numberOfFriends; i++) // In this loop we save the names into the array.
{
printf("Enter name of friend %d: ", i + 1);
myFgets(name, STR_LEN); // Get the name from the user.
sizeOfMemory += 1;
arrOfNames = (char*)realloc(arrOfNames, sizeof(int) * sizeOfMemory); // Change the size of the memory to more place to pointer from the last time.
arrOfNames[i] = (char*)malloc(sizeof(char) * strlen(name) + 1); // Set dynamic size to the name.
*(arrOfNames[i]) = '\0'; // We remove the string in the currnet name.
strncat(arrOfNames[i], name, strlen(name) + 1); // Then, we save the name of the user into the string.
}
sortString(arrOfNames, numberOfFriends); // We use this function to sort the array.
for (i = 0; i < numberOfFriends; i++)
{
printf("Friend %d: %s\n", i + 1, arrOfNames[i]);
}
for (i = 0; i < numberOfFriends; i++)
{
free(arrOfNames[i]);
}
free(arrOfNames);
getchar();
return 0;
}
/*
Function will perform the fgets command and also remove the newline
that might be at the end of the string - a known issue with fgets.
input: the buffer to read into, the number of chars to read
*/
void myFgets(char str[], int n)
{
fgets(str, n, stdin);
str[strcspn(str, "\n")] = 0;
}
/*In this function we get array of strings and sort the array by abc.
Input: The array and the long.
Output: None*/
void sortString(char** arr, int numberOfStrings)
{
int i = 0, x = 0;
char tmp[STR_LEN] = { 0 };
for (i = 0; i < numberOfStrings; i++) // In this loop we run on all the indexes of the array. From the first string to the last.
{
for (x = i + 1; x < numberOfStrings; x++) // In this loop we run on the next indexes and check if is there smaller string than the currnet.
{
if (strcmp(arr[i], arr[x]) > 0) // If the original string is bigger than the currnet string.
{
strncat(tmp, arr[i], strlen(arr[i])); // Save the original string to temp string.
// Switch between the orginal to the smaller string.
arr[i][0] = '\0';
strncat(arr[i], arr[x], strlen(arr[x]));
arr[x][0] = '\0';
strncat(arr[x], tmp, strlen(tmp));
tmp[0] = '\0';
}
}
}
}
After the print of the names, when I want to free the names and the array, in the first try to free, I get an error of: "HEAP CORRUPTION DETECTED: after normal block(#87)". By the way, I get this error only when I enter 4 or more players. If I enter 3 or less players, the program work properly.
Why does that happen and what I should do to fix it?
First of all remove the unnecessary (and partly wrong) casts of the return value of malloc and realloc. In other words: replace (char*)malloc(... with malloc(..., and the same for realloc.
Then there is a big problem here: realloc(arrOfNames, sizeof(int) * sizeOfMemory) : you want to allocate an array of pointers not an array of int and the size of a pointer may or may not be the same as the size of an int. You need sizeof(char**) or rather the less error prone sizeof(*arrOfNames) here.
Furthermore this in too convoluted (but not actually wrong):
*(arrOfNames[i]) = '\0';
strncat(arrOfNames[i], name, strlen(name) + 1);
instead you can simply use this:
strcpy(arrOfNames[i], name);
Same thing in the sort function.
Keep your code simple.
But actually there are more problems in your sort function. You naively swap the contents of the strings (which by the way is inefficient), but the real problem is that if you copy a longer string, say "Walter" into a shorter one, say "Joe", you'll write beyond the end of the allocated memory for "Joe".
Instead of swapping the content of the strings just swap the pointers.
I suggest you take a pencil and a piece of paper and draw the pointers and the memory they point to.
Related
How am I supposed to use dynamic memory allocations for arrays?
For example here is the following array in which i read individual words from a .txt file and save them word by word in the array:
Code:
char words[1000][15];
Here 1000 defines the number of words the array can save and each word may comprise of not more than 15 characters.
Now I want that that program should dynamically allocate the memory for the number of words it counts. For example, a .txt file may contain words greater that 1000. Now I want that the program should count the number of words and allocate the memory accordingly.
Since we cannot use a variable in place of [1000], I am completely blank at how to implement my logic. Please help me in this regard.
You use pointers.
Specifically, you use a pointer to an address, and using a standard c library function calls, you ask the operating system to expand the heap to allow you to store what you need to.
Now, it might refuse, which you will need to handle.
The next question becomes - how do you ask for a 2D array? Well, you ask for an array of pointers, and then expand each pointer.
As an example, consider this:
int i = 0;
char** words;
words = malloc((num_words)*sizeof(char*));
if ( words == NULL )
{
/* we have a problem */
printf("Error: out of memory.\n");
return;
}
for ( i=0; i<num_words; i++ )
{
words[i] = malloc((word_size+1)*sizeof(char));
if ( words[i] == NULL )
{
/* problem */
break;
}
}
if ( i != num_words )
{
/* it didn't allocate */
}
This gets you a two-dimensional array, where each element words[i] can have a different size, determinable at run time, just as the number of words is.
You will need to free() all of the resultant memory by looping over the array when you're done with it:
for ( i = 0; i < num_words; i++ )
{
free(words[i]);
}
free(words);
If you don't, you'll create a memory leak.
You could also use calloc. The difference is in calling convention and effect - calloc initialises all the memory to 0 whereas malloc does not.
If you need to resize at runtime, use realloc.
Malloc
Calloc
Realloc
Free
Also, important, watch out for the word_size+1 that I have used. Strings in C are zero-terminated and this takes an extra character which you need to account for. To ensure I remember this, I usually set the size of the variable word_size to whatever the size of the word should be (the length of the string as I expect) and explicitly leave the +1 in the malloc for the zero. Then I know that the allocated buffer can take a string of word_size characters. Not doing this is also fine - I just do it because I like to explicitly account for the zero in an obvious way.
There is also a downside to this approach - I've explicitly seen this as a shipped bug recently. Notice I wrote (word_size+1)*sizeof(type) - imagine however that I had written word_size*sizeof(type)+1. For sizeof(type)=1 these are the same thing but Windows uses wchar_t very frequently - and in this case you'll reserve one byte for your last zero rather than two - and they are zero-terminated elements of type type, not single zero bytes. This means you'll overrun on read and write.
Addendum: do it whichever way you like, just watch out for those zero terminators if you're going to pass the buffer to something that relies on them.
While Ninefingers provided an answer using an array of pointers , you can also use an array of arrays as long as the inner array's size is a constant expression. The code for this is simpler.
char (*words)[15]; // 'words' is pointer to char[15]
words = malloc (num_words * sizeof(char[15]);
// to access character i of word w
words[w][i];
free(words);
If you're working in C:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define WORD_LEN 15
int resizeArray(char (**wordList)[WORD_LEN], size_t *currentSize, size_t extent)
{
int result = 1;
char (*tmp)[WORD_LEN] = realloc(*wordList,
(*currentSize + extent) * sizeof **wordList);
if (tmp)
{
*currentSize += extent;
*wordList = tmp;
}
else
result = 0;
return result;
}
int main(void)
{
char *data[] = {"This", "is", "a", "test",
"of", "the", "Emergency",
"Broadcast", "System", NULL};
size_t i = 0, j;
char (*words)[WORD_LEN] = NULL;
size_t currentSize = 0;
for (i = 0; data[i] != NULL; i++)
{
if (currentSize <= i)
{
if (!resizeArray(&words, ¤tSize, 5))
{
fprintf(stderr, "Could not resize words\n");
break;
}
}
strcpy(words[i], data[i]);
}
printf("current array size: %lu\n", (unsigned long) currentSize);
printf("copied %lu words\n", (unsigned long) i);
for (j = 0; j < i; j++)
{
printf("wordlist[%lu] = \"%s\"\n", (unsigned long) j, words[j]);
}
free(words);
return 0;
}
If you intend to go for C++, STL is very useful for something dynamic allocation and is very easy. You can use std::vector ..
In modern C (C99) you have an additional choice, variable length arrays, VLA, such as that:
char myWord[N];
In principle you could also do such a thing in two dimensions, but if your sizes get too big, you may risk a stack overflow. In your case the easiest thing would be to use a pointer to such an array and to use malloc / realloc to resize them:
typedef char Word[wordlen];
size_t m = 100000;
Word* words = malloc(m * sizeof(Word));
/* initialize words[0]... words[m-1] here */
for (size_t i = 0; i < m; ++i) words[i][0] = '\0';
/* array is too small? */
m *= 2;
void *p = realloc(words, m*sizeof(Word));
if (p) words = p;
else {
/* error handling */
}
.
free(words);
This code should work (modulo typos) if wordlen is a constant or a variable, as long as you keep everything inside one function. If you want to place it in a function you should declare your function something like
void myWordFunc(size_t wordlen, size_t m, char words[m][wordlen]);
that is the length parameters must come first to be known for the declaration of words.
If the 15 in your example is variable, use one of the available answers (from Ninefingers or John Boker or Muggen).
If the 1000 is variable, use realloc:
words = malloc(1000 * sizeof(char*));
// ... read 1000 words
if (++num_words > 1000)
{
char** more_words = realloc(words, 2000 * sizeof(char*));
if (more_words) {printf("Too bad");}
else {words = more_words;}
}
In my code above, the constant 2000 is a simplification; you should add another variable capacity to support more than 2000 words:
if (++num_words > capacity)
{
// ... realloc
++capacity; // will reallocate 1000+ words each time; will be very slow
// capacity += 1000; // less reallocations, some memory wasted
// capacity *= 2; // less reallocations but more memory wasted
}
Here is a little information on dynamically allocating 2d arrays:
http://www.eskimo.com/~scs/cclass/int/sx9b.html
char ** words = malloc( 1000 * sizeof(char *));
int i;
for( i = 0 ; i < 1000 ; i++)
*(words+i) = malloc(sizeof(char) * 15);
//....
for( i = 0 ; i < 1000 ; i++)
free(*(words+i));
free(words);
I'm an infosec student, who has just begun learning C. I've been given an assignment to write a simple translation program using this prototype: char* dictionary[number_of_words][2];.
The output should look something like this:
Enter # of words to add: 3
dictionary[0][0]= plane
dictionary[0][1]= Flugzeug
dictionary[1][0]= house
dictionary[1][1]= Haus
dictionary[2][0]= cat
dictionary[2][1]= Katze
Enter english word to translate: house
---> Haus
My current (work in progress) code looks like this:
void clean_stdin(void);
int main(void)
{
unsigned int i = 0,j = 0,size;
printf("Enter # of words to add: ");
scanf("%u",&size);
clean_stdin(); //clears input buffer
char* dictionary[size][2];
while(i <= size)
{
printf("dictionary[%u][%u]= ",i,j);
fgets(dictionary[i][j],100,stdin);
if(j >= 1)
{
j = 0;
++i;
}
else
j = 1;
}
return 0;
}
The code throws no errors when compiled with gcc -Wall main.c, but this is the behaviour I get:
Enter # of words to add: 3
dictionary[0][0]= plane
dictionary[0][1]= Flugzeug
dictionary[1][0]= house
dictionary[1][1]= Haus
fish: “./a.out” terminated by signal SIGSEGV (Adressbereichsfehler)
*****
Enter # of words to add: 4
dictionary[0][0]= plane
fish: “./a.out” terminated by signal SIGSEGV (Adressbereichsfehler)
There's a fundamental flaw somewhere in my thought process. Any help/heads up is very appreciated. Cheers!
Let's look at this part of your code:
char* dictionary[size][2];
while(i <= size)
{
printf("dictionary[%u][%u]= ",i,j);
fgets(dictionary[i][j],100,stdin);
Each dictionary[i][j] is a pointer to char, but you haven't set them to point anywhere meaningful yet - each array element contains some random bit pattern that may or may not correspond to a writable address. Your first few entries get written somewhere, but eventually you try to write to a memory location you don't own or don't have access to.
You will need to set aside additional memory to store each individual string. You either need create a 3D array of char (not char *):
#define MAX_STR_LEN 100
...
char dictionary[size][2][MAX_STR_LEN+1];
or you will need to dynamically allocate memory for each array entry:
while ( i < size ) // <, not <=
{
dictionary[i][j] = malloc( sizeof *dictionary[i][j] * (MAX_STR_LEN + 1));
if ( !dictionary[i][j] )
{
// memory allocation failed, handle error
}
printf("dictionary[%u][%u]= ",i,j);
fgets(dictionary[i][j],MAX_STR_LEN,stdin);
If you allocate memory dynamically, you will need to explicitly free it when you're done:
for ( i = 0; i < size; i++ )
{
free( dictionary[i][0] );
free( dictionary[i][1] );
}
instead of messing around with arrays of multiple dimensions, I suggest you use structures:
#include <stdio.h>
#include <string.h>
int main()
{
unsigned int size;
printf("Enter # of words to add: ");
if (scanf("%u", &size) != 1)
return 1; // cannot convert input to integer
#define WORD_MAX_SIZE 100
struct {
char word[WORD_MAX_SIZE];
char translation[WORD_MAX_SIZE];
} dictionary[size];
memset(dictionary, 0, sizeof(dictionary));
for (int i = 0; i < size; i++) {
printf("dictionary[%u].word= ", i);
fgets(dictionary[i].word, WORD_MAX_SIZE, stdin);
printf("dictionary[%u].translation= ", i);
fgets(dictionary[i].translation, WORD_MAX_SIZE, stdin);
}
// do something with your stuff
}
fgets(dictionary[i][j],100,stdin); reads from an uninitialized variable (dictionary[i][j] was never given a value), which has undefined behavior.
Also, i is going out of bounds later.
Say I have the following code:
char* array[1000]; // An array containing 1000 char*
// So, array[2] could be 'cat', array[400] could be 'space', etc.
Now, how could I flatten this array into 1-D? Is it possible to do this such that new_1D_array[2] would still be 'cat', new_1D_array[400] would still be 'space', etc.?
You have a one-dimensional array of type pointer-to-char, with 1000 such elements. It's already 1D as far as arrays go, though it could be interpreted as a "jagged 2D array". If you want to convert this into one massive character array, you could do something like so, which requires calculating the size of the buffer you'll need to store it, and then flattening the array.
Note that if you opt to use malloc instead of calloc, you'll have to manually set the last character to '\0' or 0 so that the final result is a NULL-delimited C-style string, and not just a character array, as the latter of the two won't work with C string operations, and the former will.
Code Listing
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void) {
const char* array[] = { "one", "two", "three", "four" };
size_t length = sizeof(array) / sizeof(char*);
int i;
int sum = 0;
int count = 0;
for (i=0; i<length; i++) {
printf("Element #%d - %s\n", i, array[i]);
sum += strlen(array[i]) + 1;
}
sum++; // Make room for terminating null character
char* buf;
if ((buf = calloc(sum, sizeof(char))) != NULL) {
for (i=0; i<length; i++) {
memcpy(buf+count, array[i], strlen(array[i]));
count += strlen(array[i]) + 1;
buf[count-1] = '#';
}
printf("Output Buffer: %s\n", buf);
printf("Buffer size:%d - String Length:%d\n", sum, strlen(buf));
free(buf);
buf = NULL;
}
return 0;
}
Sample Output
Element #0 - one
Element #1 - two
Element #2 - three
Element #3 - four
Output Buffer: one#two#three#four#
Buffer size:20 - String Length:19
The above answer beat me to the puch and looks great, but I'll finish my thoughts here.
In this version every 11th byte of flatArray will contain the start of the strings from the original array, making it very easy to find the original strings from the ones before - i.e. string index 2 would start at 2*11 == index 22 and string 400 would start at 400 * 11 == index 4400. In this way, you would not need to iterate through the flat array counting terminators to find your old strings. The cost of this being that the flat array takes a bit more memory than the original.
char* array[1000];
// Malloc new buffer
char *flatArray = malloc(length * 1100);
for(i=0; i<1000; i++)
{
strncpy(&flatArray[i * 11], array[i], 10);
flatArray[i * 11 + 10] = '\0';
}
Basically, I'm trying to convert a bunch of char inputs to ints and assign them to a dynamic int array. The string input and tokenization seem to work fine. The issue (from what I can tell) seems to be with the reallocation of the int array; after the array is reallocated twice, the pointer to the int array returns NULL.
What I tried to do was double the size of the int array every time the number of tokens meets or surpasses (size divided by sizeof(int)). The realloc statement works each time this condition is met.
I thought using a pointer to a pointer was the end-all solution to this. I bet it's some really obvious issue, but I'm at my wit's end here. If you request any further elaboration, I'll try my best. Understand that I've only taken C for a semester and have struggled most of the way.
Also, truth be told, this was part of a class assignment which has since passed. I'd prefer an explanation about what's wrong more than a full-on code, if that's alright.
I have a lot of printf statements, so apologies for any clutter.
EDIT: Replaced all instances of newArray within the input() function with *resize. However, I've never tried assigning values through pointers to pointers, so feel free to correct me with a syntactic example if you know how I messed up. Segmentation fault occurs here:
for (k = (numElem - count); k < numElem; k++)
{
printf("\nk = %i\n", k);
printf("j = %i\n", j);
printf("numElem = %i\n", numElem);
printf("results[j]: %s\n\n\n", results[j]);
/* Segmentation fault regardless of what is assigned
to *resize[k]. */
*resize[k] = atoi(results[j]); // PROBLEM HERE
j++;
}
The source code has been updated to reflect upon this. To make this ridiculously long post a little more subdued, let's state that I did this in main():
int *newArray = malloc(MAXTOKEN * sizeof(int));
input(&newArray);
free(newArray);
Moving on.
/* String input takes in char values,
tokenizes them, converts the results
to int, assigns them to newresizeay. */
int input(int **resize)
{
int i, j, k, count;
int numElem = 0;
int currentSize = MAXTOKEN;
char str[MAXSTRING];
char *results[MAXTOKEN];
/* This entire loop takes place at least once,
provided the first input isn't NULL. */
do
{
i = 0, j = 0, k = 0;
/* Char input process. Takes place until the user
presses ENTER. */
printf("Input integer values separated by spaces, or "
"press ENTER to exit.\n");
while ( ((str[i] = getchar() ) != '\n') && (i < MAXSTRING) )
i++;
printf("\n\n");
str[i] = '\0';
/* Tokenization of the chars that were input */
count = 0;
if (results[0] = strtok(str, " \t"))
count++;
while (results[count] = strtok(NULL, " \t") )
count++;
/* numElem = 1 if the first input prompt established
str[0] as NULL */
if ( (count < 1) && (numElem < 1) )
count = 1;
numElem += count;
printf("numElem: %i\ncurrentSize: %i\n", numElem, currentSize);
/* If the number of elements to assign meet or surpass
the amount of [memory / sizeof(int)], exponentially
increase the size of the int resizeay. */
if ( numElem >= currentSize )
{
*resize = realloc(*resize, (currentSize) * sizeof(int));
if (*resize == NULL)
printf("\n\nYep, it threw up.\n\n");
currentSize *= 2;
}
printf("\nSize should be: %i\n", currentSize * 4);
printf("Actual size: %d\n", _msize(*resize));
/* The tokenized chars are converted to integers and
assigned to the int resizeay. */
for (k = (numElem - count); k < numElem; k++)
{
printf("\nk = %i\n", k);
printf("j = %i\n", j);
printf("numElem = %i\n", numElem);
printf("results[j]: %s\n\n\n", results[j]);
*resize[k] = atoi(results[j]); // PROBLEM HERE
j++;
}
for (i = 0; i < numElem; i++)
printf("resize[%i]: %i\n", i, *resize[i]);
printf("\n\n\n");
} while (str[0] != NULL);
}
The input function receives both resize and arr. main sends the same pointer to both. This is a bug.
When resize is resized, arr stays the same and may point to an invalid address (when realloc returns a different address).
How to fix:
Remove arr function argument and only use resize.
When you call the realloc function,if the new memory block is smaller than previous ,it will maintain the original state pointing to the memory block which previous used.If the new memory block is larger than previous,the system will re allocate memory on the heap and the previous memory is released.
Among other problems:
char *results[MAXTOKEN];
should be
char *results[MAXTOKEN + 1];
because here the maximum value of count will be MAXTOKEN in this loop :
while (results[count] = strtok(NULL, " \t") )
count++;
and
char str[MAXSTRING];
is pretty scary, because as soon as the user enters more than MAXSTRIN (=11) characters without pressing Enter, you will get a buffer overflow.
If I want to add chars to char array, I must do it like this:
#include <stdio.h>
int main() {
int i;
char characters[7] = "0000000";
for (i = 0; i < 7; i++) {
characters[i] = (char)('a' + i);
if (i > 2) {
break;
}
}
for (i = 0; i < 7; i++) {
printf("%c\n", characters[i]);
}
return 0;
}
To prevent from printing any weird characters, I must initialize the array, but it isn't flexible. How can I add characters to a char array dynamically? Just like you would in Python:
characters = []
characters.append(1)
...
There is no non-ugly solution for pure C.
#include <stdio.h>
int main() {
int i;
size_t space = 1; // initial room for string
char* characters = malloc(space); // allocate
for (i = 0; i < 7; i++) {
characters[i] = (char)('a' + i);
space++; // increment needed space by 1
characters = realloc(characters, space); // allocate new space
if (i > 2) {
break;
}
}
for (i = 0; i < 7; i++) {
printf("%c\n", characters[i]);
}
return 0;
}
In practice you want to avoid the use of realloc and of course allocate the memory in bigger chunks than just one byte, maybe even at an exponetial rate. But in essence thats what happening under the hood of std::string and the like: You need a counter, which counts the current size, a variable of the current maximum size (Here it is always current size+1, for simplicity) and some reallocation if the need for space surpasses the maximum current size.
Yes, of course you can add characters dynamically:
quote char[100] = "The course of true love";
strcat( quote, " never did run smooth.";
but only if there is enough room in quote[ ] to hold the appended characters. Or maybe you are asking why, in C, you have to pre-arrange enough character storage whereas, in Python, storage is allocated dynamically. That's how the language was designed in 197x.
C99 does allow dynamically-allocated storage: storage allocated by the system at run time. And a very bad mistake it is, imo.
You cannot unless you use Linked Lists or some other custom data structure.