I am working with a bunch of strings for logging. I want to refactor my code and make a new struct that combines the char, its length and allocated size. The idea is to make my internal string operations smoother and the code nicer to read, whilst assigning each string its own max allocated memory to keep the usage to a minimum but prevent stack overflow. I made this simple example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
char *str;
int size;
int max;
} Text;
void defText(Text *text, int max)
{
text->str=(char*) malloc(max * sizeof(char));
text->str="";
text->max=max;
}
int main() {
Text *a;
defText(a,50);
a->str="Test all you want";
printf("OUT: %s %zu %lu",a->str,strlen(a->str),sizeof(a->str));
return 0;
}
The function defText initializes and allocates memory. However, when I check the sizeof the char in my struct, I always get 8, no matter what I set in defText. Is this kind of struct handling strings and their properties together even possible? If so, what is wrong here?
There are several problems in your code, this is an example that cleans up these problems:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
char *str;
// you could use size to keep track of the strlen. That's particularly
// desirable if you find yourself calling strlen "a lot", since that
// function recalculates the length every time it's called
int size;
int max;
} Text;
void defText(Text *text, int max)
{
// no need to cast the return of malloc. In fact, sizeof(char) is defined by
// the standard to be 1 so you could take that out also.
text->str=malloc(max * sizeof(char));
// `=` is not the proper way to write strings in C, you must use strcpy
// or something similar. It looks like here you're simply trying to
// create an empty string.
//text->str="";
// per #JohnBollinger's comment, the best thing to do here to create
// an empty string is simply set to the first byte to the NUL
// terminator.
text->str[0] = '\0';
text->max=max;
}
int main() {
Text a; // store this in automatic memory, now the object exists without having to malloc
defText(&a,50); // Use & to pass the address of a to defText
// as mentioned, this is not the proper way to write data to a string in
// C. What you've done here is create a memory leak and point a.str to
// the string literal "Test all you want". Use strcpy (or similar) to
// write that string into the data you actually malloc'ed (using the dot
// operator now since `a` is no longer a pointer)
//a->str="Test all you want";
strcpy(a.str, "Test all you want");
// a.str is a pointer, and will always be 8 bytes on your system no matter
// the size of the memory it points to
printf("OUT: %s %zu %zu",a.str,strlen(a.str),sizeof(a.str));
// clean up allocated memory. Since we're about to exit, there's
// really no need to do this here (the OS will reclaim all allocated
// memory when the process ends), but if you're writing a more
// involved, long-running program, you need to be sure to handle
// memory allocations and deallocations appropriately as needed
free(a.str);
return 0;
}
Demo
The
a->str
is pointer .
the correct answer is
sizeof(*(a->str))
I can tell that there will be a memory leak on this and am looking for improvements / the standard way of doing things as far as these kind of problems go.
(e.g. how an experienced / pro use on C would implement this)
This is a simple case switch programme. Its purpose is to give it PizZa and give you back pIZza.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char changeCase(char ch){
if ( (int)ch < 65 || (int)ch > 122){
return ch;
}else if ((int)ch < 91){
return (char)(ch + 32);
}
else{
return (char)(ch - 32);
}
}
char* toUpper(char* string){
size_t size=strlen(string);
char* temp = (char*) malloc(size);
while (*string != '\0'){
*temp = changeCase(*string);
temp++;
string++;
}
return (temp - size);
}
int main() {
char* string = toUpper("PIZa");
printf("%s",string);
return 0;
}
This results in a memory leak since the memory from malloc is not freed. What would be better? Allocating memory outside the function and giving the pointer to that memory to the toUpper function? Other idea?
The de facto standard rule is that the part of the code that did the dynamic allocation is also responsible for freeing it. So if your function was in some file "toupper.c", then there should have been some manner of clean-up function available in that same C file.
However, the best solutions separates memory allocation and algorithms. This means that a better way to write this function is this:
void toUpper (char* dst, const char* src)
{
while (*src!= '\0')
{
*dst= ...
...
dst++;
src++;
}
}
Here, the caller can allocate space for dst as it pleases, it's no business of the algorithm. For example:
char str1[] = "hello world";
char* str2 = malloc(strlen(str1) + 1);
toUpper(str2, str1);
...
free(str2);
Just make sure to document the function so that the caller knows that they have to allocate space for dst - to be at least as large as src.
As a side-note, char* temp = (char*) malloc(size); is wrong, you didn't allocate room for the null terminator. Also your algorithm must make sure to copy the null terminator into the destination buffer.
This results in a memory leak since the memory from malloc is not freed.
Actually there is no memory leak in your code. All allocated memory will be freed when the program terminates.
A memory leak occurs in a running program when the program no longer holds a pointer to the allocated memory.
Example:
int main() {
char* string = toUpper("PIZa");
printf("%s",string);
string = toUpper("BRead"); // This causes a memory leak because after this
// line there is no longer any pointer to the
// memory allocated in the first call of toUpper
string = NULL; // Again this causes a memory leak because after this
// line there is no longer any pointer to the
// memory allocated in the second call of toUpper
return 0;
}
Note: Even leaked memory will be freed when the program terminates. Memory leaks are (mainly) a problem in "long" running programs.
What would be better? Allocating memory outside the function ...
Well, it's a matter of taste.
As an example: The widely used (but non-standard) strdup function handles allocation inside the function and requires the caller to free the memory later on.
For a function that reads an unknown amount of characters as user input it can also be nice to do malloc (and realloc as needed) inside the function.
There is really no right or wrong here. You are the designer so you decide. It's all about the "function contract", i.e. the documentation of the function - how to call it and what it will do.
Sorry. I really tried to solve this myself. But i don't understand. The statements ran okay when i place them in main. But when i call them in a function from main, segmentation fault happens. Does it mean memory overflowed?
void displayTime(char state[]) {
time_t totalSec = time(NULL);//total no of secs since EPOCH
struct tm *currTime = localtime(&totalSec); //store local time in struct declared in time.h
char *result;
strftime(result, 20, "%Y:%m:%d %H:%M:%S", currTime); //E.g. 2017:11:12 12:30:48 Max is 20 characters including \0
printf("Program at %s\n", result );
}
int main() {
displayTime("started");
return 0;
}
Allocate memory in result that is what is causing problem.
In your case it will be
result = malloc(sizeof(char)*BUFFSIZE);
if( result == NULL ){
fprintf(stderr,"Error");
exit(1);
}
There must be a corresponding free call to the allocated memory, here it will be
free(result);
Also accessing uninitialized variable is undefined behavior.
Also without malloc you can simply do this
char result[20];
strftime(result,20, "%Y:%m:%d %H:%M:%S", currTime);
Also my earlier edit with state is not possible. (Didn't notice that it's literal string) Since string literals belong to the read only section of memory. Now here we were trying to edit or modify it. That is wrong.
Secondly, even if it was not read only it will still not have memory to hold the characters that you would write. Because the size would not be big enough for that.
Further Explanation
To clarify the problem, look at the result variable. It is type char*. It is supposed to contain address of a char variable. Now when you declare it. Then it contains an indeterminate value.
Does it point to anything meaningful? No.
Now when you pass the variable to the function it tries to write something to a location whose address is contained in result variable. But it is not something useful and you will try to access some memory which is not even meant for you.(not permitted).
Segfaults are caused by a program trying read or write an illegal memory location.
That's what happened in your case.
Does it mean memory overflowed?
No. It has nothing to do with overflow.
Also what is the purpose of the state in your code? You are not using it anywhere in the code. You can avoid it.
//char * result; // this is just a pointer with no memory to point to
char result[256] = {0,}; // now this will work
strftime(result, 20, "%Y:%m:%d %H:%M:%S", currTime);//E.g. 2017:11:12 12:30:48 Max is 20 characters including \0
alternatively
//char * result; // this is just a pointer with no memory to point to
char *result = malloc( 256 * sizeof(char));
if( result )
{
strftime(result, 20, "%Y:%m:%d %H:%M:%S", currTime);//E.g. 2017:11:12 12:30:48 Max is 20 characters including \0
}
I am trying to copy a string into another char pointer variable using strcpy function.But I always get segmentation fault.Here is my code.
/* strcat example */
#include <stdio.h>
#include <string.h>
int main()
{
char str[100]="";
char *pch3;
strcpy(pch3,"Ravi");
//strcat(str,pch3); //Segmnetation fault.
puts(pch3);
return 0;
}
If I do the same thing in this one I still get segmentation fault.
else
{
misc_rec_cnt++;
fp1=fopen("breast-cancer-wisconsin-miscellaneous.data","a");
fprintf(fp1,"%s",line2);
fclose(fp1);
fp2=fopen("missingSCNs.data","a");
pch2=strtok(line2,",");
fprintf(fp2,"%s\n",pch2);
fclose(fp2);
//pch3=(char *)malloc(sizeof(char)*strlen(line3));
pch3 = strtok(line3,",");
while(pch3!=NULL)
{
if(strcmp(pch3,"?") == 0)
{
strcat(str1,"0");
strcat(str1,",");
}
else
{
//strcat(str1,pch3);
strcat(str1,",");
}
pch3 = strtok(NULL,",");
}
strlen1=strlen(str1);
memcpy(str2,str1,strlen1-1);
fp3=fopen("breast-cancer-wisconsin-miscellaneous-cleansed.data","a");
fprintf(fp3,"%s\n",str2);
fclose(fp3);
}
You need to allocate the space for pch3 before you copy to it. Use malloc to create a char array large enough to accomodate the elements of your source string before you copy it. What you are currently doing is declaring a char pointer and not initialising it. Therefore the memory location that it points to could be anywhere - and that means that you should probably not be attempting to write to it - which is why you are getting the segfault. Using malloc will allow you to allocate a region of memory that you are safe to write to and this will solve your problem (assuming the call to malloc succeeds). You cannot just go writing data to random memory locations without getting segfaults and access violations.
pch3 is a char pointer, but it doesn't have any storage associated with it which is the cause of the problem. Call malloc() to allocate some memory that the pch3 pointer can point to and you should be ok.
At this point you have a char pointer that is uninitialized and just pointing somewhere unknown. So try this:
pch3 = (char *)malloc(sizeof(char) * 100); /* 100 just as an example */
This tutorial might be helpful or this SO question: Allocating char array using malloc
pch3 is an unallocated pointer, so you're writing data to a location that doesn't exist. Did you mean to assign it to str?
char str[100]="";
char *pch3;
pch3 = str;
strcpy(pch3,"Ravi");
I'd recommend that you first allocate memory before copying data to a random place.
strcpy(pch3=(char*)malloc(sizeof("Ravi")),"Ravi");
but better check if it didn't return null pointer.
I've tried to write a string replace function in C, which works on a char *, which has been allocated using malloc(). It's a little different in that it will find and replace strings, rather than characters in the starting string.
It's trivial to do if the search and replace strings are the same length (or the replace string is shorter than the search string), since I have enough space allocated. If I try to use realloc(), I get an error that tells me I am doing a double free - which I don't see how I am, since I am only using realloc().
Perhaps a little code will help:
void strrep(char *input, char *search, char *replace) {
int searchLen = strlen(search);
int replaceLen = strlen(replace);
int delta = replaceLen - searchLen;
char *find = input;
while (find = strstr(find, search)) {
if (delta > 0) {
realloc(input, strlen(input) + delta);
find = strstr(input, search);
}
memmove(find + replaceLen, find + searchLen, strlen(input) - (find - input));
memmove(find, replace, replaceLen);
}
}
The program works, until I try to realloc() in an instance where the replaced string will be longer than the initial string. (It still kind of works, it just spits out errors as well as the result).
If it helps, the calling code looks like:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void strrep(char *input, char *search, char *replace);
int main(void) {
char *input = malloc(81);
while ((fgets(input, 81, stdin)) != NULL) {
strrep(input, "Noel", "Christmas");
}
}
As a general rule, you should never do a free or realloc on a user provided buffer. You don't know where the user allocated the space (in your module, in another DLL) so you cannot use any of the allocation functions on a user buffer.
Provided that you now cannot do any reallocation within your function, you should change its behavior a little, like doing only one replacement, so the user will be able to compute the resulting string max length and provide you with a buffer long enough for this one replacement to occur.
Then you could create another function to do the multiple replacements, but you will have to allocate the whole space for the resulting string and copy the user input string. Then you must provide a way to delete the string you allocated.
Resulting in:
void strrep(char *input, char *search, char *replace);
char* strrepm(char *input, char *search, char *replace);
void strrepmfree(char *input);
First off, sorry I'm late to the party. This is my first stackoverflow answer. :)
As has been pointed out, when realloc() is called, you can potentially change the pointer to the memory being reallocated. When this happens, the argument "string" becomes invalid. Even if you reassign it, the change goes out of scope once the function ends.
To answer the OP, realloc() returns a pointer to the newly-reallocated memory. The return value needs to be stored somewhere. Generally, you would do this:
data *foo = malloc(SIZE * sizeof(data));
data *bar = realloc(foo, NEWSIZE * sizeof(data));
/* Test bar for safety before blowing away foo */
if (bar != NULL)
{
foo = bar;
bar = NULL;
}
else
{
fprintf(stderr, "Crap. Memory error.\n");
free(foo);
exit(-1);
}
As TyBoer points out, you guys can't change the value of the pointer being passed in as the input to this function. You can assign whatever you want, but the change will go out of scope at the end of the function. In the following block, "input" may or may not be an invalid pointer once the function completes:
void foobar(char *input, int newlength)
{
/* Here, I ignore my own advice to save space. Check your return values! */
input = realloc(input, newlength * sizeof(char));
}
Mark tries to work around this by returning the new pointer as the output of the function. If you do that, the onus is on the caller to never again use the pointer he used for input. If it matches the return value, then you have two pointers to the same spot and only need to call free() on one of them. If they don't match, the input pointer now points to memory that may or may not be owned by the process. Dereferencing it could cause a segmentation fault.
You could use a double pointer for the input, like this:
void foobar(char **input, int newlength)
{
*input = realloc(*input, newlength * sizeof(char));
}
If the caller has a duplicate of the input pointer somewhere, that duplicate still might be invalid now.
I think the cleanest solution here is to avoid using realloc() when trying to modify the function caller's input. Just malloc() a new buffer, return that, and let the caller decide whether or not to free the old text. This has the added benefit of letting the caller keep the original string!
Just a shot in the dark because I haven't tried it yet but when you realloc it returns the pointer much like malloc. Because realloc can move the pointer if needed you are most likely operating on an invalid pointer if you don't do the following:
input = realloc(input, strlen(input) + delta);
Someone else apologized for being late to the party - two and a half months ago. Oh well, I spend quite a lot of time doing software archaeology.
I'm interested that no-one has commented explicitly on the memory leak in the original design, or the off-by-one error. And it was observing the memory leak that tells me exactly why you are getting the double-free error (because, to be precise, you are freeing the same memory multiple times - and you are doing so after trampling over the already freed memory).
Before conducting the analysis, I'll agree with those who say your interface is less than stellar; however, if you dealt with the memory leak/trampling issues and documented the 'must be allocated memory' requirement, it could be 'OK'.
What are the problems? Well, you pass a buffer to realloc(), and realloc() returns you a new pointer to the area you should use - and you ignore that return value. Consequently, realloc() has probably freed the original memory, and then you pass it the same pointer again, and it complains that you're freeing the same memory twice because you pass the original value to it again. This not only leaks memory, but means that you are continuing to use the original space -- and John Downey's shot in the dark points out that you are misusing realloc(), but doesn't emphasize how severely you are doing so. There's also an off-by-one error because you do not allocate enough space for the NUL '\0' that terminates the string.
The memory leak occurs because you do not provide a mechanism to tell the caller about the last value of the string. Because you kept trampling over the original string plus the space after it, it looks like the code worked, but if your calling code freed the space, it too would get a double-free error, or it might get a core dump or equivalent because the memory control information is completely scrambled.
Your code also doesn't protect against indefinite growth -- consider replacing 'Noel' with 'Joyeux Noel'. Every time, you would add 7 characters, but you'd find another Noel in the replaced text, and expand it, and so on and so forth. My fixup (below) does not address this issue - the simple solution is probably to check whether the search string appears in the replace string; an alternative is to skip over the replace string and continue the search after it. The second has some non-trivial coding issues to address.
So, my suggested revision of your called function is:
char *strrep(char *input, char *search, char *replace) {
int searchLen = strlen(search);
int replaceLen = strlen(replace);
int delta = replaceLen - searchLen;
char *find = input;
while ((find = strstr(find, search)) != 0) {
if (delta > 0) {
input = realloc(input, strlen(input) + delta + 1);
find = strstr(input, search);
}
memmove(find + replaceLen, find + searchLen, strlen(input) + 1 - (find - input));
memmove(find, replace, replaceLen);
}
return(input);
}
This code does not detect memory allocation errors - and probably crashes (but if not, leaks memory) if realloc() fails. See Steve Maguire's 'Writing Solid Code' book for an extensive discussion of memory management issues.
Note, try to edit your code to get rid of the html escape codes.
Well, though it has been a while since I used C/C++, realloc that grows only reuses the memory pointer value if there is room in memory after your original block.
For instance, consider this:
(xxxxxxxxxx..........)
If your pointer points to the first x, and . means free memory location, and you grow the memory size pointed to by your variable by 5 bytes, it'll succeed. This is of course a simplified example as blocks are rounded up to a certain size for alignment, but anyway.
However, if you subsequently try to grow it by another 10 bytes, and there is only 5 available, it will need to move the block in memory and update your pointer.
However, in your example you are passing the function a pointer to the character, not a pointer to your variable, and thus while the strrep function internally might be able to adjust the variable in use, it is a local variable to the strrep function and your calling code will be left with the original pointer variable value.
This pointer value, however, has been freed.
In your case, input is the culprit.
However, I would make another suggestion. In your case it looks like the input variable is indeed input, and if it is, it shouldn't be modified, at all.
I would thus try to find another way to do what you want to do, without changing input, as side-effects like this can be hard to track down.
This seems to work;
char *strrep(char *string, const char *search, const char *replace) {
char *p = strstr(string, search);
if (p) {
int occurrence = p - string;
int stringlength = strlen(string);
int searchlength = strlen(search);
int replacelength = strlen(replace);
if (replacelength > searchlength) {
string = (char *) realloc(string, strlen(string)
+ replacelength - searchlength + 1);
}
if (replacelength != searchlength) {
memmove(string + occurrence + replacelength,
string + occurrence + searchlength,
stringlength - occurrence - searchlength + 1);
}
strncpy(string + occurrence, replace, replacelength);
}
return string;
}
Sigh, is there anyway to post code without it sucking?
realloc is strange, complicated and should only be used when dealing with lots of memory lots of times per second. i.e. - where it actually makes your code faster.
I have seen code where
realloc(bytes, smallerSize);
was used and worked to resize the buffer, making it smaller. Worked about a million times, then for some reason realloc decided that even if you were shortening the buffer, it would give you a nice new copy. So you crash in a random place 1/2 a second after the bad stuff happened.
Always use the return value of realloc.
My quick hints.
Instead of:
void strrep(char *input, char *search, char *replace)
try:
void strrep(char *&input, char *search, char *replace)
and than in the body:
input = realloc(input, strlen(input) + delta);
Generally read about passing function arguments as values/reference and realloc() description :).