Memory leak plain c - c

I wrote this code to sort names and the code works but there is always error int he end of the program the eror is: Heap corruption.Can someone please help me to uderstan why it is happening and how to fix it?
My code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define TEMP_SIZE 50
void swap(char *str1, char *str2);
int main(void)
{
int number = 0, i = 0, j = 0;
char** names = 0;
char temp[TEMP_SIZE] = { 0 };
printf("Enter number of friends: ");
scanf("%d", &number);
names = (char**)malloc(number * sizeof(char*));
for (i = 0; i < number; i++)
{
printf("Enter name of friend %d: \n", i + 1);
scanf("%s", temp);
names[i] = (char*)malloc(strlen(temp) * sizeof(char) + 1);
strcpy(names[i], temp, strlen(temp) + 1);
}
for (j = 0; j < number - 1; j++)
{
for (i = 0; i < number - 1; i++)
{
if (strcmp(names[i], names[i + 1]) > 0)
{
swap(names[i + 1], names[i]);
}
}
}
for (i = 0; i < number; i++)
{
printf("Friend %d: %s\n", i + 1, names[i]);
}
for (i = number - 1; i >= 0; i--)
{
free(names[i]);
}
free(names);
getchar();
getchar();
return 0;
}
void swap(char *str1, char *str2)
{
char *temp = 0;
temp = (char *)malloc((strlen(str1) + 1) * sizeof(char));
strcpy(temp, str1);
strcpy(str1, str2);
strcpy(str2, temp);
free(temp);
}
I would be pleased and thankful if you will help me!

When the strings are of different length, the swap function above will overwrite the bounds of the allocated strings, corrupting the heap. You probably just want to swap the pointers stored in the names array indices, rather than overwrite the contents of the allocated string buffers.
You could also just use stdlib qsort to sort the array.

The problem with your swap function is that it expects that both strings have
the same length or that both memory locations are large enough to hold the
strings. Consider this example:
char str1[] = "Hello";
char str2[] = "This is a so much longer string";
swap(str1, str2);
will crash, because str1 is not big enough to store the contents of str2, so
the strcpy calls will write beyond the memory limits, thus you are overflowing
the buffer. This is the problem your are facing.
You have to solutions:
allocate for example 1024 bytes for every name[i], regardless of the length
of the name. We can assume that no name is longer than 1024 characters. (Don't do it, ugly solution).
Instead of swapping the contents, swap the pointers. This is much easier to do
because names is char** and name[i] are char*s, so swapping the pointers
is easy as you don't have to worry about the length of the memory they are
pointing to.
The swap function could look like this
void swap_ptrs(char **x, char **y)
{
char *tmp = *x;
*x = *y;
*y = tmp;
}
and instead of calling
swap(names[i + 1], names[i]);
you call:
swap_ptrs(names + i + 1, names + i);
which will swap the pointers.
edit
I realize that you don't even need the swap_ptrs function for this, you can do it like this:
if (strcmp(names[i], names[i + 1]) > 0)
{
char *tmp = names[i];
names[i] = names[i + 1];
names[i + 1] = tmp;
}
And as jspcal points out, the most elegant and robust solution would be to use use qsort:
int comp(const void *x, const void *y)
{
const char *a = *((const char **) x);
const char *b = *((const char **) y);
return strcmp(a, b);
}
int main(void)
{
...
qsort(names, number, sizeof *names, comp);
...
}

Related

Segmentation fault and 'free' called on a pointer to an unallocated object

I am currently writing a program to simply reverse a string in C. However, when I try to copy the contents of the temp string I made into the original string, I get a segmentation fault. Also, when I try to free the memory I allocated for my test string I get a warning which says " 'free' called on a pointer to an unallocated object "
Here is my code:
void reverseString(char* str, size_t size) {
char *temp = (char*) malloc(sizeof(str) + 1);
int j = size;
for (int i = 0; i < size; i++) {
temp[i] = str[j];
j--;
}
for (int i = 0; i < size; i++) {
str[i] = temp[i];
}
free(temp);
return;
}
int main() {
char* result = (char*)(malloc(sizeof(char) * 10));
result = "Forty-two";
reverseString(result, strlen(result));
printf("%s", result);
free(result);
result = NULL;
return 0;
}
On the second line, you should be using strlen instead of sizeof, because otherwise you will be allocating space for a character pointer and you need more than that.
sizeof(str) returns size of pointer not length of the literal.
Array index starts from 0. That's why j should starts with (size - 1)
You are allocating memory from heap, use memset before do something.
#bereal already says, if you want to understand more, please check this out :
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
char* result = (char*)(malloc(sizeof(char) * 10));
memset(result, 0, 10);
printf("Addr of result var : %p \n", result);
result = "Re-assign";
printf("Addr of result var : %p \n", result);
return 0;
}
Maybe my solution gives an idea for you
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void reverseString(char** str, size_t size) {
char *temp = (char*) malloc(size + 1);
memset(temp, 0, size + 1);
int j = size - 1;
for (int i = 0; i < size; i++) {
temp[i] = str[0][j];
j--;
}
//Change addr of holding str
*str = temp;
return;
}
int main() {
char* result = "Forty-two";
reverseString(&result, strlen(result));
printf("%s", result);
//result holds same addr with temp
free(result);
return 0;
}
But there are ways to solve this question more accurately.

How can I write the concatenated string to the given string pointer in C?

I am having trouble with the very last line in my function, where I am stilly learning the basics of C. I have the signature of this function given and am tasked to write a function to concatenate two strings. The commented line outputs the correct result.
#include <stdio.h>
#include <stdlib.h>
// 1) len = dst-len + max_dst_len
int strlcat(char *dst, const char *src, int max_dst_len) {
int len = 0;
while (dst[len] != '\0') {
len++;
}
int total_len = len + max_dst_len;
char *new_str = malloc(sizeof(char) * total_len);
for (int i = 0; i < len; i++) {
new_str[i] = dst[i];
}
for (int i = len; i < total_len; i++) {
new_str[i] = src[i - len];
}
new_str[total_len] = '\0';
//printf("%s <--\n", new_str);
dst = *new_str;
return total_len;
}
int main() {
char test1[] = "dst";
char test1src[] = "src";
printf("%s\n", test1);
printf("%d\n", strlcat(test1, test1src, 10));
printf("%s\n", test1);
}
You should not be adding max_dst_len to the length of dst. max_dst_len is the amount of memory that's already allocated in dst, you need to ensure that the concatenated string doesn't exceed this length.
So you need to subtract len from max_dst_len, and also subtract 1 to allow room for the null byte. This will tell you the maximum number of bytes you can copy from src to the end of dst.
In your main() code, you need to declare test1 to be at least 10 bytes if you pass 10 as the max_dst_len argument. When you omit the size in the array declaration, it sizes the array just big enough to hold the string you use to initialize it. It's best to use sizeof test1 as this argument, to ensure that it's correct for the string you're concatenating to.
#include <stdio.h>
int strlcat(char *dst, const char *src, int max_dst_len) {
int len = 0;
while (dst[len] != '\0') {
len++;
}
int len_to_copy = max_dst_len - len - 1;
int i;
for (i = 0; i < len_to_copy && src[i] != '\0'; i++) {
dst[len+i] = src[i];
}
dst[i] = '\0';
//printf("%s <--\n", new_str);
return i + len;
}
int main() {
char test1[6] = "dst";
char test1src[] = "src";
printf("%s\n", test1);
printf("%d\n", strlcat(test1, test1src, sizeof test1));
printf("%s\n", test1);
}

How to go through a array of strings using pointers alone

I'm trying to create a function that will receive an array of strings and the size and will return a string made of the biggest ASCII value's letter of each word, and the size of the string has to be precised and I'm not allowed using operator [](which is my main issue).
so for:
char *strArr[SIZE] = { "hello", "and", "good", "morning" };
the function shall return a string with the word
"onor"
.
So i thought of creating a double for loop, first one will lead me into the location of each word in the array and the inside one will help me go through each word.
currently I'm having trouble finding the right format with my pointers to actually go through the letters of my first word.
I'm aware i haven't checked if my memory allocation is valid and also didn't free my memory yet as I'm trying to figure out whats wrong first.
char *bigLetters(char *str[], int size)
{
char *strNew = (char *)malloc((size + 1) * sizeof(char));
char max = 'a';
for (int i = 0; i < size; i++)
{
for (int j = 0; (*(str + i)+j) != NULL; j++)
{
if ((*(str + i) + j) >= max)
{
max = (*(str + i) + j);
}
}
*(strNew + i) = max;
}
*(strNew +(size+1)) = NULL;
return *(strNew);
}
void main()
{
char *strArr[SIZE] = { "hello", "and", "good", "morning" };
char *res = bigLetters(strArr, SIZE);
printf("The new string is --> %s\n", res);
system("pause");
}
It will be easier to use the pointers if you separate the string pointer from its character pointer. Also, the max needs to be reset for each string, and you were writing the final string terminator outside of the memory allocated. You also use NULL where you should be using the character '\0'.
Finally the function was returning the first character of the new string (which I later free).
#include <stdio.h>
#include <stdlib.h>
#define SIZE 4
char *bigLetters(char *str[], int size)
{
char *strNew = malloc(size + 1); // no cast or sizeof necessary
for (int i = 0; i < size; i++)
{
char ch;
char max = 'a'; // moved inside loop
char *ptr = *(str + i); // use a separate pointer
for (int j = 0; (ch = *(ptr + j)) != '\0'; j++) // pull out the character
{
if (ch > max) // >= is not necessary
{
max = ch;
}
}
*(strNew + i) = max;
}
*(strNew + size) = '\0'; // correct the bounds error
return strNew; // just the pointer not its target
}
int main(void) // correct signature
{
char *strArr[SIZE] = { "hello", "and", "good", "morning" };
char *res = bigLetters(strArr, SIZE);
printf("The new string is --> %s\n", res);
free(res); // clean up
system("pause");
}
Program output
The new string is --> onor
Press any key to continue . . .
If you didn't impose odd and unhelpful restrictions upon your coding, you'd be able to quickly see the problems with your code or even avoid making them in the first place. The problem is that the following statement makes no sense - you're comparing a char * with a char as you're only de-referencing str once.
if ((*(str + i) + j) >= max)
This is the same as writing
if ((str[i] + j) >= max)
which you can see the obvious mistake since what you're trying to write is the equivalent of
if ((str[i][j]) >= max)
which would be
if (*(*(str + i) + j) >= max)
Your compiler should be throwing up warnings because comparing between a pointer and an integer is rarely something you'd want to do.
You can use pointers as position indicators and advance them as needed.
#include <stdio.h>
#include <stdlib.h>
#define SIZE 4
char
biggest_ascii(char* str)
{
char c = 0;
int i;
for (i = 0; *str; str++)
if (*str > c)
c = *str;
return c;
}
int
main()
{
int i;
char* strArr[SIZE] = {"hello", "and", "good", "morning"};
char** ppch;// current string
char res_str[SIZE + 1] = {0};/* resulting string,
initilized to 0 to be 0-terminated */
char* pch;// current char position
for (i = 0, ppch = strArr, pch = res_str; i < SIZE; i++, ppch++, pch++)
*pch = biggest_ascii(*ppch);
printf("%s\n", res_str);
return 0;
}
First, (*(str + i)+j) isn't the good way.
You could replace all
(*(str + i) + j)
by :
str[i][j]
Then, you need to reset the max to "a", because it's 'o' when you leave the loop, so your condition become str[i][j] >= o which is not what you want. Do it before the second for.
And I would have used while instead of for for the first loop.
I edited your code and this version is working fine for me :
#include <stdlib.h>
char *bigLetters(char *str[], int size)
{
char *strNew = (char *)malloc((size + 1) * sizeof(char));
int i = 0;
while (i < size) {
char max = 'a';
for (int j = 0; str[i][j]; j++) {
if (str[i][j] >= max) {
max = str[i][j];
}
}
strNew[i] = max;
i++;
}
strNew[i] = '\0';
return strNew;
}
void main()
{
char *strArr[5] = { "hello", "and", "good", "morning"};
char *res = bigLetters(strArr, 4);
printf("The new string is --> %s\n", res);
return 0;
}
str[i] is equivalent to *(str + i) and str[i][j] is equivalent to *(*(str + i) + j).
In your code you are using (*(str + i) + j) which is incorrect.
When char *[] passed to function, it will decay to char **. So, in bigLetters(), you can give char **str as the parameter. Also, it is inline with you requirement - not allowed using operator [].
Instead of hardcoding the dimension SIZE in char *strArr[SIZE], you can give the empty [] and let the compiler assign the dimension based on the size of initializer. In your case, size of initializer is 4 as you have given 4 strings in the strArr initializer. You can compute the size of strArr like this:
sizeof(strArr)/sizeof(strArr[0]);
You can do:
#include <stdio.h>
#include <stdlib.h>
char *bigLetters(char **str, size_t size) {
char *strNew = calloc(size + 1, 1); // sizeof(char) is always 1
// calloc will initialize all bytes in the allocated storage to zero.
// You dont need to add the null terminating character at the end of strNew
if (strNew == NULL)
exit(EXIT_FAILURE);
for (size_t i = 0; i < size; i++) {
for (size_t j = 0; *(*(str + i)+j) != '\0'; j++) {
if (*(*(str + i) + j) > *(strNew + i)) {
// You can directly fill the allocated memory with biggest ASCII
*(strNew + i) = *(*(str + i) + j);
}
}
}
return strNew;
}
int main(void) {
char *strArr[] = { "hello", "and", "good", "morning" };
char *res = bigLetters(strArr, sizeof(strArr)/sizeof(strArr[0]));
if (res != NULL) {
printf("The new string is --> %s\n", res);
free (res);
}
else
printf("bigLetters returned NULL\n");
return 0;
}
Note that void return type main() is not as per standard. Instead, you should use int as return type of main().

need help in understanding passing char* [] to function

I am trying to pass a array of pointers to string to a function where I need to set the values. In the passing function I do not know the number of strings I will get, the called function is calling some other function which returns list of strings.
Sample code below:
int main() {
char** list;
create(list);
}
int create(char **array) {
char* str[] = { "hello", "dear" };
int len;
int i = 0;
for (i = 0; i < 2; i++) {
len = strlen(str[i]);
printf("%d\n", len);
*(array + i) = (char*) malloc(len * sizeof(char*));
strcpy(*(array + i), str[i]);
i++;
}
return 1;
}
This gives me segmentation fault.
What wrong am I doing here. Please help.
Thanks
EDIT
Updated code from below comments:
int main() {
char** list;
create(list);
int i = 0;
for (i = 0; i < 2; i++) {
printf("%s\n", list[i]); // segmentation fault
}
}
int create(char **array) {
char* str[] = { "hello", "dear" };
int len;
int i = 0;
array = malloc(2 * sizeof(char*));
for (i = 0; i < 2; i++) {
len = strlen(str[i]);
printf("%d\n", len);
*(array + i) = (char*) malloc(len * sizeof(char));
strcpy(*(array + i), str[i]);
printf("%s\n", array[i]); // this prints
}
return 1;
}
Now getting segmentation fault in main while printing the list.
Actual code where I am reading the strings
int i;
for ( i=0; i<reply->elements; i++ )
{
printf( "Result: %d---%s\n", i,reply->element[i]->str );
*array[i] = (char*)malloc(strlen(reply->element[i]->str));
printf("***");
strcpy(array[i],reply->element[i]->str);
printf( "Array[%d]: %s\n", i,array[i] );
}
You correctly alloc memory for the individual strings, but fail to alloc some for the array itself.
You should use:
int main() {
char* list[8] = {0}; /* initialize pointers to NULL */
create(list);
/* free allocated memory - free(NULL) is legal and is a noop */
for (i=0; i<sizeof(list)/sizeof(list[0]); i++) free(list[i]);
return 0; /* never return random value from main */
}
And you should remove the i++ at the end of the loop in function create because it leads to a double increment.
Alternatively you could alloc the array itself in the function create:
int create(char ***array) {
char* str[] = { "hello", "dear" };
int len;
int i = 0;
*array = malloc(1 + sizeof(str)/sizeof(str[0]));
for (i = 0; i < 2; i++) {
len = strlen(str[i]) + 1;
printf("%d\n", len);
(*array)[i] = malloc(len * sizeof(char*));
strcpy((*array)[i], str[i]);
}
(*array)[i] = NULL;
return i;
}
int main() {
char** list;
create(&list);
}
In above code, the length of the array is the return value from create, and the last element of list is a NULL (in the same logic as argc/argv).
You need to allocate some space for list or undefined behavior occurs:
char* list[2];
You increment i twice; therefore, remove the i++ from the bottom of the for loop.
Minor notes:
refer to string literals as const char*
use array[i] instead of *(array + i)
don't cast the result of malloc
malloc allocates too much space as you allocate len char*s, even though you need just chars. Also, as #CoolGuy noted, you need one extra byte for the null byte. Replace the allocation with
array[i] = malloc(len * sizeof(char) + sizeof(char));
or
array[i] = malloc(len + 1);
call free after malloc
you assign 0 twice to i; remove the initialization
You allocate two arrays (char*) to store the strings "hello" and "dear" but does not allocate the array (char**) containing those two string array.
I would suggest you to change declaration of function create to this -
int create(char ***array);
And call it like this -
create(&list);
In function create allocate memory like this -
*array = malloc(2 * sizeof(char*));
for (i = 0; i < 2; i++)
{
len = strlen(str[i]);
printf("%d\n", len);
(*array)[i] =malloc(len * sizeof(char*)+1);
strcpy((*array)[i], str[i]);
}
And do the printing as you do in main.
Note - free memory that you allocate.
And you should declare len as type size_t -> size_t len;
and print it with %zu specifier in printf .
See working code here -https://ideone.com/GX2k9T

Sorting a 2 dimensional array of strings by a specific field

Given a two dimensional array decalred below:
char * Arr[4] =
{
{"124 -346 DATA...."},
{"39479 -32 MOREDATA...."},
{"12 -1 DATA2...."},
{"100 -45 DATA4...."}
};
i'm trying to use qsort() to sort this function according to the SECOND field, meaning the strings would be ordered according to the lowest second value(-1,-32,-45,-346). I know how to make this function if each value were only one digit, but the digits in the program could be arbitrarily long. here is what i have but the program crashes, if there is a more efficient way to sort this data i would love to here it(i know my method can't be very efficient).
Sort function(which qsort() calls):
inline void GetStr(char *ix, char* Result) //call to get second number in function
{
char *spacing; //iterator to traverse
spacing = ix; //iterator = pos of ix
int LEN = 0; //length and offset
int Offset = 0;
while(*spacing != ' ') //while not at end of first num
{
Offset++; //offset is more
spacing++;
}
spacing++; //go one ahead of the space
Offset++;
while(*spacing != ' ') //while not end of second number
{
spacing++;
Offset++;
LEN++; //length of number
}
strncpy(Result, ix + (Offset - LEN),LEN);
}
int sort(const void* a, const void* b)
{
char *ia = *(char**)a;
char *ib = *(char**)b;
char * Str;
char * Str2;
GetStr(ia, Str); //getting some strange errors....... program just crashes
GetStr(ib, Str2);
printf("Str: %s Str2: %s", Str, Str2);
int n1 = atoi(Str);
int n2 = atoi(Str2);
return (n1 > n2);
}
I believe you have at least one problem here:
strncpy(Result, ix + (Offset - LEN),LEN);
If you look at the documentation for strncpy, you will see that it does not automatically null-terminate the copied string if you hit the character limit. Therefore your Result strings are not null-terminated.
Try changing to this:
strncpy(Result, ix + (Offset - LEN),LEN);
Result[LEN] = '\0';
Of course, you still need to provide memory for the Result string. Currently you are passing an uninitialized pointer into GetStr():
char * Str;
char * Str2;
Since these are fairly small integers you can use statically allocated storage like this:
#define MAX_RESULT_LEN 64
/* ... */
char Str[MAX_RESULT_LEN]
char Str2[MAX_RESULT_LEN]
/* ... */
if (LEN > MAX_RESULT_LEN - 1) {
LEN = MAX_RESULT_LEN - 1;
}
strncpy(Result, ix + (Offset - LEN),LEN);
Result[LEN] = '\0';
Finally, there are some issues with your sort() function. If you look at the qsort() documentaton, you can see that the return value should be "an integer less than, equal to, or greater than zero if the first argument is considered to be respectively less than, equal to, or greater than the second". The easiest way to achieve this is with the logic n1 - n2 instead of the n1 < n2.
I also thought you're sort arguments of type char ** were odd as well, but upon further reflection I realize they are correct. From the qsort docs: "two arguments that point to the objects being compared". So indeed they will be pointers to C strings or char **.
So here is the final version:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_RESULT_LEN 64
void GetStr(char *ix, char* Result) //call to get second number in function
{
char *spacing; //iterator to traverse
spacing = ix; //iterator = pos of ix
int LEN = 0; //length and offset
int Offset = 0;
while(*spacing != ' ') //while not at end of first num
{
Offset++; //offset is more
spacing++;
}
spacing++; //go one ahead of the space
Offset++;
while(*spacing != ' ') //while not end of second number
{
spacing++;
Offset++;
LEN++; //length of number
}
if (LEN > MAX_RESULT_LEN - 1) {
LEN = MAX_RESULT_LEN - 1;
}
strncpy(Result, ix + (Offset - LEN),LEN);
Result[LEN] = '\0';
}
int sort(const void* a, const void* b)
{
char *ia = *(char **)a;
char *ib = *(char **)b;
char Str[MAX_RESULT_LEN];
char Str2[MAX_RESULT_LEN];
GetStr(ia, Str);
GetStr(ib, Str2);
printf("Str: %s Str2: %s", Str, Str2);
int n1 = atoi(Str);
int n2 = atoi(Str2);
return (n1 - n2);
}
int main(void) {
char * Arr[4] =
{
{"124 -346 DATA...."},
{"39479 -32 MOREDATA...."},
{"12 -1 DATA2...."},
{"100 -45 DATA4...."}
};
qsort(Arr, 4, sizeof(char *), sort);
}
You can start with something like this, and you need to actually call sort somewhere. Also need to consider what happens when the file is large:
#include <stdio.h>
int
Sort(const void *a, const void *b)
{
int *aa = a, *bb = b;
return (aa[1] < bb[1]); //i need to sort by field, not a simple comparison. HOW?
}
int main(int argc, char **argv) {
FILE *f = fopen(argv[1]);
if (f) {
char buffer[1024];
int *v;
int data[1024][5];
int cnt = 0;
while (fgets(buffer, sizeof(buffer), f)) {
v = data[cnt++];
sscanf(buffer, "%d %d %d %d %d", v, v+1, v+2, v+3, v+4);
}
fclose(f);
}
return 0;
}

Resources