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.
Related
How can I implement a function that will concatenate something to a char* (not char array)?
Example of what I want:
#include <stdio.h>
#include <string.h>
int main() {
char* current_line;
char temp[1];
sprintf(temp, "%c", 'A');
// This causes a seg fault. I of course don't want that, so how do I get this to work properly?
strcat(current_line, temp);
return 0;
}
How can I fix this to work properly (and please, tell me if I need to add anything to my question or point me in the right direction because I couldn't find anything)?
Edit: I made this but it seg faults
char* charpointercat(char* mystr, char* toconcat) {
char ret[strlen(mystr) + 1];
for(int i = 0; mystr[i] != '\0'; i++) {
ret[i] = mystr[i];
}
return ret;
}
You have 3 problems:
You do not allocate memory for current_line at all!
You do not allocate enough memory for temp.
You return a pointer to a local variable from charpointercat.
The first one should be obvious, and was explained in comments:
char *current_line only holds a pointer to some bytes, but you need to allocate actual bytes if you want to store something with a function like stracat.
For the secoond one, note that sprintf(temp, "%c", 'A'); needs at least char temp[2] as it will use one byte for the "A", and one byte for terminating null character.
Since sprintf does not know how big temp is, it writes beyond it and that is how you get the segfault.
As for your charpointercat once the function exits, ret no longer exists.
To be more precise:
An array in C is represented by a pointer (a memory address) of its first item (cell).
So, the line return ret; does not return a copy of all the bytes in ret but only a pointer to the first byte.
But that memory address is only valid inside charpointercat function.
Once you try to use it outside, it is "undefined behavior", so anything can happen, including segfault.
There are two ways to fix this:
Learn how to use malloc and allocate memory on the heap.
Pass in a third array to the function so it can store the result there (same way you do with sprintf).
From the first code you posted it seems like you want to concatenate a char to the end of a string... This code will return a new string that consists of the first one followed by the second, it wont change the parameter.
char* charpointercat(char* mystr, char toconcat) {
char *ret = (char*) malloc(sizeof(char)*(strlen(mystr) + 2));
int i;
for(i = 0; mystr[i] != '\0'; i++) {
ret[i] = mystr[i];
}
ret[i] = toconcat;
ret[i + 1] = '\0';
return ret;
}
This should work:
char* charpointercat(char* mystr, char* toconcat) {
size_t l1,l2;
//Get lengths of strings
l1=strlen(mystr);
l2=strlen(toconcat);
//Allocate enough memory for both
char * ret=malloc(l1+l2+1);
strcpy(ret,mystr);
strcat(ret,toconcat);
//Add null terminator
ret[l1+l2]='\0';
return ret;
}
int main(){
char * p=charpointercat("Hello","World");
printf("%s",p);
//Free the memory
free(p);
}
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.
I have the following code that prints as intended in ubuntu linux but prints nothing in cygwin in windows. However, if I get rid of free(t) in is_rotation function then it works ok. I want to know if I am doing bad memory management or it is a cygwin issue. Why it is happening. And any other suggestion to improve the memory management.
Here is the code:
/**
* sub is a substring of str or not
**/
int is_substring(const char* str,const char* sub){
const char* s1=str;
const char* s2=sub;
int count=0;
while(1){
if(*s2=='\0') return 1;
else if(*s1=='\0') return 0;
else if(*s1==*s2){
count++;
s2++;
}
else{
if(count!=0){
s1-=count;
count=0;
s2=sub;
}
}
s1++;
}
return 0;
}
/**
* s1 and s2 are rotations of eachother or not, given only the is_substring function.
**/
int is_rotation(const char* s1,const char* s2){
int l1=strlen(s1);
if(l1!=strlen(s2)) return 0;
char* t=malloc(2*l1*sizeof(char));
strcat(t,s1);
strcat(t,s1);
int r=is_substring(t,s2);
free(t);
return r;
}
/**
* USAGE: ./a.out string1 string2
**/
int main(int argc, char *argv[]){
if(argc<3) return 1;
printf("is_substring=%d",is_substring(argv[1],argv[2]));
printf("\nis_rotation=%d",is_rotation(argv[1],argv[2]));
return 0;
}
Thanks for the help :)
The issue is in the first strcat() call. You should replace it with a strcpy() instead.
int is_rotation(const char* s1,const char* s2){
int l1=strlen(s1);
if(l1!=strlen(s2)) return 0;
char* t=malloc(2*l1*sizeof(char) + 1);
strcpy(t,s1); // initialize with strcpy() so we have a null in the string
strcat(t,s1);
int r=is_substring(t,s2);
free(t);
return r;
}
Note that malloc() does not initialize the buffer it allocates normally. Perhaps the one on ubuntu does, but it is not guaranteed. In cygwin, the buffer is not initialized, so the strcat() is walking memory looking for a null before it copies the string... which very likely is past the end of your allocated buffer.
Also, you have to add an extra character to the buffer to hold the null terminator for the final string... it's 2x the length of l1 + 1 for the null terminator
Here is a bug that kills your stack:
char* t=malloc(2*l1*sizeof(char));
strcat(t,s1);
strcat(t,s1);
The first strcat adds characters to somewhere... As you are using malloc the contents of the t buffer is unknown. Also you need one more byte for zero.
char* t=malloc(2*l1+1); // (2*l1+1)*sizeof(char)
strcpy(t,s1);
strcat(t,s1);
Hi I am getting the the following error from valgrind.
Conditional move based on uninitialized values, Uninitalized values was created by heap allocation.
The compiler does not complain.
I looked at most of the similar errors at stackoverflow, but I can't seem to pinpoint what's wrong with mine.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
int
main(void)
{
char *string1 = malloc(45);
char string2[25] = "HELLO WORLD";
strcpy(string1,string2);
printf("String one is %s\n",string1);
char string3[25];
for (int i = 0; i < 25; i++)
{
string3[i] = tolower(string1[i]);
}
printf("The output is %s\n",string3);
free(string1);
return 0;
}
Your tolower call accesses the first 25 bytes of the memory pointed to by string1, but only the first twelve bytes of that memory are in a valid state (thanks to the strcpy).
You could use calloc instead of malloc to allocate memory with a deterministic state. Alternatively, only copy as many bytes as you need:
{
const unsigned int M = max(24, strlen(string1));
for (unsigned int i = 0; i != M; ++i)
string3[i] = tolower(string1[i]);
string3[M] = 0;
}
You're looping from 0 to 24 along string1, which has only been initialized strlen("HELLO WORLD") + 1 bytes. Bytes indexed from 12 to 24 there have not been initialized, and you shouldn't be trying to read them. You should either use calloc() to allocate string1 or use memset() to initialize it, like so:
char *string1 = calloc(1, 45);
or
char *string1 = malloc(45);
memset(string1, 0, 45);
Or you could initialize string3 to zeroes with the above methods and then only copy strlen(string1) bytes.
I have a small piece of code. I compiled it with -lmcheck as I am trying to debug a code where I have the same similar error.
I get this error when I run this code:
memory clobbered before allocated block
Can someone explain the reason why free(ptr) will throw me this error?
How else can I free the pointer?
Thanks.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#define LEN 5
int main(int argc, char *argv[]){
char *ptr = NULL;
ptr = (char *) malloc(LEN+1);// +1 for string
strcpy(ptr, "hello");
int i = 0;
for(i = 0; i<LEN; i++)
{
printf("ptr[%d] = %c\n", i, ptr[i]);
ptr++;
}
free(ptr);
return 0;
}
You are incrementing ptr, therefore changing the address that it points to. You can't do that.
In your case, have a separate pointer, let's say char * p = ptr and do your operations with p leaving ptr intact so you can free(ptr) later.
EDIT Taking a second look at your code, I found that you are doing ptr++ when you shouldn't. You are accessing the characters in the array like ptr[i], if you mess with the ptr pointer, you are changing the base address and accessing the characters with ptr[i] can lead (and will lead) to unexpected results.
If you simply remove that line (ptr++) your code will magically work.
If you want to explore the pointer concept and try another solution, your code could look something like this:
int main(int argc, char *argv[]){
char *ptr = NULL;
char * p;
ptr = (char *) malloc(LEN+1);// +1 for string (please check for NULL)
p = ptr;
strcpy(ptr, "hello");
int i = 0;
while (*p) // note how I changed it to a while loop, C strings are NULL terminated, so this will break once we get to the end of the string. What we gain is that this will work for ANY string size.
{
printf("ptr[%d] = %c\n", i++, *p); // here i dereference the pointer, accessing its individual char
p++;
}
free(ptr);
return 0;
}
Because ptr no longer points to the base of the memory you allocated.
Also, after you increment ptr, the expression ptr[i] does not return what you might expect; and that is why the output starts with "hlo".
Find the answer in comments.
When you allocate some memory, typically, the memory management framework keep tracks of it by adding some more info (you can say Header and Footer) to the allocated memory area. When you free this memory, the same info is matched so as to detect any unwanted/invalid memory access.
int main(int argc, char *argv[]){
char *ptr = NULL;
char* temp = NULL; // Have a temp pointer.
ptr = (char *) malloc(LEN+1);// +1 for string
strcpy(ptr, "hello");
temp = ptr; // manipulate temp pointer instead of ptr itself
int i = 0;
for(i = 0; i<LEN; i++)
{
printf("ptr[%d] = %c\n", i, temp[i]);
temp++; // Why you are incrementing this? Just to print, there is no need of this.
}
free(ptr);
return 0;
}