Am I freeing memory properly in this C program? - c

I'm writing a small program that reads multiple input lines from the user:
#include <stdio.h>
#include <stdlib.h>
#define MAXINPUT 256
#define MAXLINES 32
/* Reads at most maxLines inputs from stdin. Returns number of lines. */
int readlines(char** buffer, int maxLines, size_t maxInput);
/* Gets input from stdin with maxInput as the limit. Returns size of string. Terminates at newline. */
int getstdline(char* buffer, int maxInput);
int main(int argc, char** argv) {
char** buffer = malloc((sizeof buffer[0]) * MAXLINES);
int numlines = readlines(buffer, MAXLINES, MAXINPUT);
/* free memory that was allocated for each str */
for(int i = 0; i < numlines; ++i) {
free(*(buffer++));
}
/* free memory that was allocated to hold all the strings */
free(buffer);
}
int readlines(char** buffer, int maxLines, size_t maxInput) {
int linecount = 0;
while(maxLines--) {
char* tmp = malloc(maxInput);
/* if empty string, exit loop */
if(getstdline(tmp, maxInput) <= 0) {
free(tmp);
break;
}
*buffer = tmp;
++linecount;
++buffer;
}
return linecount;
}
My question is regarding the call to malloc() in readlines(char**,int,size_t). I obviously can't free() the memory within the function so to free it at the end of the program, I tried to loop through the array of char* and free them individually. I then also free char** buffer in main() because it was also allocated using malloc().
Looping through each of them gives me the error :
object was probably modified after being freed.
Freeing char** buffer at the end works fine.
So it seems there is a concept of dynamic memory I am not quite understanding. Why is this happening and what would be the correct way to handle memory in this specific program?

The problem is that you are modifying the buffer pointer by running buffer++ so when you call free(buffer) you are passing in the wrong pointer. You can rewrite your loop to not modify that pointer.

Related

Weird characters when allocating memory for char*

Hy I have a sample code bleow, which should write the "MSG" in a way an LCD display would (running text) and when it reached the end it strarts again, but when I allocate memory for the "LCD" (which schould be 10 character+terminating 0) fills it with bunch of random characters.
Sample picture
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
void delay(unsigned int mseconds)
{
clock_t goal = mseconds + clock();
while (goal > clock());
}
int main()
{
int LCDSize = 10;
int MSGSize;
char* LCD = (char *)malloc(LCDSize+1);
char* MSG = (char *)malloc(80);
MSG = "This is a long message, probabli will move.";
MSGSize = strlen(MSG);
if (MSGSize <= LCDSize)
{
printf(MSG);
}
else
{
char* tmpMSG;
int j = 0;
while (j < 2)
{
for (int i = 0; i < MSGSize - LCDSize + 1; i++)
{
tmpMSG = MSG+i;
strncpy(LCD, tmpMSG, LCDSize);
strcat(LCD,"\0");
printf(LCD);
delay(200);
system("cls");
}
printf("----------");
j++;
}
}
getchar();
return 0;
}
What could be the problem?
strncpy(LCD, tmpMSG, LCDSize);
strcat(LCD,"\0");
The strncpy function will not terminate if it doesn't fit. In this case, it doesn't fit. So there is no termination. Something that is not terminated with a zero byte is not a legal string, so you cannot pass a pointer to it as the first parameter to strcat, but you do.
The strcat function appends one string onto another. Both strings must be legal, well-formed strings or you must not call strcat.
This is one of the reasons it is generally suggested that you not use strncpy -- there is no guarantee the result is a valid string and it's easy to make the kind of mistake you made. Yes, you made sure you didn't overflow the buffer when you called strncpy by limiting the size, but you didn't ensure the buffer contained a valid string.
What you probably wanted was LCD[LCDSize]='\0'; instead of the call to strcat. This ensures the buffer is terminated.

Returning malloced pointer in C

I have the following program:
#include <stdio.h>
#include <stdlib.h>
char* getStr(int length) {
char* chars = malloc(length + 1);
int i;
for(i = 0; i < length; i++)
chars[i] = 'X';
chars[i] = '\0';
// no call to free()
return chars;
}
int main(int argc, char** argv) {
char* str;
str = getStr(10);
printf("%s\n", str);
free(str);
return EXIT_SUCCESS;
}
It prints 10 X's, as I expected.
Would it behave like this on any platform with any compiler?
Is the memory still malloced after getStr() returns?
(I don't want to pass the pointer as argument :D)
Yes, the code looks valid and the behavior should be reliable with any C compiler.
And, yes, the memory is still allocated after getStr() returns. So the call to free() is also correct.
Don't forget to check if malloc() returns NULL, in the event there is insufficient memory.
If you use malloc to allocate memory, it will remain allocated until you explicitly call free on it, regardless of how it's passed around between functions, returned, etc.

Segmentation fault in C. What is the reason?

I am getting segmentation fault in C and I have no idea what is the reason. As far as I know segmentation fault occurs when system run our of memory. I checked my loops and they seem to have clear termination conditions. Thus, I am confused what causes my code to crash. As I checked this fault should occurs in mygetline or readlines functions.
Is there any debugger that I can use to find our why program crashes?
#include <stdio.h>
#include <string.h>
#define MAXLINE 100
#define MAXLINENUM 10
int readlines(char *lines[]);
int mygetline(char line[]); /* getline: read a line into s, returns length */
void writelines(char *lines[], int nlines);
int main()
{
int i = 0;
char *lines[MAXLINE];
i = readlines(lines);
writelines(lines, i);
return 0;
}
int mygetline(char line[]){
int i, c;
for(i = 0; i < MAXLINE-1 && (c = getchar()) != '\n' && c != EOF; i++){
line[i] = c;
}
line[i] = '\0';
return i;
}
int readlines(char *lines[]){
int i, c;
i = 0;
while((c = mygetline(lines++)) > 0 && i < MAXLINENUM){ //line[i]
i++;
}
lines[--i] = '\0';
return i;
}
void writelines(char *lineptr[], int nlines) {
int i;
for (i = 0; i < nlines; i++)
printf("%s\n", lineptr[i]);
}
The reason for the segmentation fault is that you don't allocate any storage for the strings. You declare an array of char* here:
char *lines[MAXLINE];
But nowhere do you ever allocate memory to hold the actual strings.
To continue using an array of char*, allocated that way, you'd need to use malloc to allocate memory for the actual strings.
lines[i] = malloc(...);
Obviously you'll need to:
Decide how much memory to allocate for each string.
Call free to dispose of the memory when you are done with it.
Add some code to check that you don't write beyond the end of any of your buffers.
You created an array char *lines[MAXLINE] which is an array of pointers. However, you've not initialized those pointers, so they're pointing to garbage. You then pass the garbage pointer into mygetline which writes to the garbage pointer, and this is the problem.
Not only do you need to allocate memory for the line to be stores in, but you also need to get mygetline how many characters it can read. If you allocate space for 10 characters, but the user enters 20 you're going to have a similar problem.
The reason that you get a segfault is that your code reads the data into lines without allocating any memory for the characters that you read.
Your main allocates memory for the pointers to strings, but it does not initialize these pointers. You need to add code to set these pointers to valid blocks of memory, for example, by allocating some max number of characters with malloc:
while(i < MAXLINENUM) {
lines[i] = malloc(MAXLINE);
if (!mygetline(lines[i++])) {
break;
}
}
Also note that you confused MAXLINE with MAXLINENUM in the declaration of lines.
The reason for the segmentation fault is the memory allocation.
You can not allocate memory like char *lines[MAXLINE];.
Try the following code
If you are Using 1D array
char *lines;
lines=(char *)malloc(MAXLINE*sizeof(char));
If you are using 2D array go with this code
char **lines;
lines=(char **)malloc(MAXLINENUM*sizeof(char *));
for(i=0;i<MAXLINENUM;i++)
lines[i]=(char *)malloc(MAXLINE*sizeof(char));

Freeing a non-allocated pointer

The following code throws the error:
mem(44582) malloc: * error for object 0x7f9f8a4000e0: pointer being freed was not allocated
* set a breakpoint in malloc_error_break to debug
Abort trap: 6
I'm not sure what's going on. I'm freeing an area of memory that I explicitly malloc'd, does it have something to do with passing in a pointer to another method?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFFERSIZE 10
void readstringbuffered(char *buffer);
int main(int argc, char const *argv[])
{
char *buffer = (char *)malloc(BUFFERSIZE);
readstringbuffered(buffer);
printf("%s",buffer);
free(buffer);
return EXIT_SUCCESS;
}
void readstringbuffered(char *buffer)
{
FILE *source;
source = fopen("hello.txt","r");
int current_size = BUFFERSIZE;
int len = 0;
int c;
while((c = fgetc(source)) != EOF)
{
if(len == current_size-1)
{
current_size *= 2;
char *temp = (char *)realloc(buffer,current_size);
if(!temp)
{
fprintf(stderr,"out of memory");
exit(1);
}
buffer = temp;
}
buffer[len] = c;
len++;
}
buffer[len] = 0;
}
C is a pass by value language. The modifications you make to buffer inside your readstringbuffered() function have no effect on the value of buffer in main(). If the realloc() there is ever executed, you've already freed the buffer that main knows about, and when you return - BAM - double free.
A possible solution is to pass a pointer to buffer, rather than buffer itself. Change the signature of readstringbuffered() to be:
void readstringbuffered(char **buffer)
And then use *buffer inside it. At the call site, you'd use readstringbuffered(&buffer) to pass the necessary pointer.
realloc() can release the previously allocated memory and allocate it again somewhere else, which makes your buffer pointer in main totally invalid. You can pass buffer by reference and have readstringbuffered() modify it accordingly, or return a pointer to buffer instead of void.
The buffer pointer in main() will not be modified according to the reallocations you do in readstringbuffered(), you may write back the buffer pointer using a pointer to the buffer pointer (pBuffer), like this:
void readstringbuffered(char** pBuffer,size_t* pSize)
{
char* buffer = *pBuffer;
size_t size = MIN_SIZE;
char* newBufferPtr = (char*) realloc(buffer,size);
if(newBufferPtr)
{
buffer = newBufferPtr;
}
else
{
//out of memory
free(buffer);
buffer = NULL;
size = 0;
}
if(buffer)
{
//fill the buffer
}
//must always execute
*pBuffer = buffer;
*pSize = size;
}
int main(int argc, char const *argv[])
{
char* buffer = NULL;
size_t size = 0;
readstringbuffered(&buffer,&size);
if(buffer)
{
printf("%s",buffer);
free(buffer);
}
else
{
//error
}
return EXIT_SUCCESS;
}

getting string with dynamic memory management

I wanna get string like 34,34;34,21;45,12;45,12(length is not certain.)
I wanna dynamic memory allocation with realloc but i can't do it.
How i can get like this characters to string??
it will be string={34,34,34,21,45,12,45,12}
You will have to know the length beforehand, and when you know that your buffer is too small for data that is going to be newly entered, use:
realloc(ptr, newLength);
If you're looking to do this at compile time (which is the only way to perform initializers similar to what you have in your question), you can let the initializer define the size f your array:
char string[] = {34,34,34,21,45,12,45,12, 0}; // added a 0 to the end to
// make it '\0' terminated
// You might not need that
If you want your string to take it's data from a runtime source (a file or other input), you'll need to perform the allocation yourself, and exactly how to do it depends on how you're going to be getting the data.
The following example reads data from stdin into a dynamically allocated character array, growing the array as needed until EOF is reached. It grows the array by 20 bytes each time so you can easily check what's happening in a debugger, but a real life program would do better to grow by something larger like by doubling the size or just growing in increments of 100KB - the details of your expected data should guide you in this decision).
#include <stdlib.h>
#include <stdio.h>
void fatal_error(void);
int main( int argc, char** argv)
{
int buf_size = 0;
int buf_used = 0;
char* buf = NULL;
char* tmp = NULL;
char c;
int i = 0;
while ((c = getchar()) != EOF) {
if (buf_used == buf_size) {
//need more space in the array
buf_size += 20;
tmp = realloc(buf, buf_size); // get a new larger array
if (!tmp) fatal_error();
buf = tmp;
}
buf[buf_used] = c; // pointer can be indexed like an array
++buf_used;
}
puts("\n\n*** Dump of stdin ***\n");
for (i = 0; i < buf_used; ++i) {
putchar(buf[i]);
}
free(buf);
return 0;
}
void fatal_error(void)
{
fputs("fatal error - out of memory\n", stderr);
exit(1);
}
Maybe you are passing the pointer as an argument to a function b() which is in turn calling the realloc
In this case you need to also return the pointer.

Resources