pointers to structs in c - c

struct TokenizerT_ {
char* separators;
char* tks;
char* cur_pos;
char* next;
};
typedef struct TokenizerT_ TokenizerT;
TokenizerT *TKCreate(char *separators, char *ts)
{
TokenizerT *tokenizer;
tokenizer = (TokenizerT*)malloc(sizeof(TokenizerT));
//some manipulation here
tokenizer->tks = (char*) malloc (strlen(str)* sizeof(char));
tokenizer->tks=str;
printf("size of tokenizer->tks is %zu\n", strlen(tokenizer->tks)); //this prints out the correct number (e.g. 7)
return tokenizer;
}
int main(int argc, char **argv)
{
TokenizerT *tk = TKCreate(argv[1], argv[2]);
printf("tk->tks: %zu\n", strlen(tk->tks)); //HOWEVER, this prints out the wrong number (e.g. 1)
}
As seen from the above code, I'm working with pointers to structs. For some reason I am not receiving back the correct length for tk->tks. I cannot understand this because it should be the same size as tks in my TKCreate function. Can someone explain this please?

I suspect str, the definition of which is not shown in your code snippet, is a local variable defined in TKCreate(). If so, you're assigning tokenizer->tks to have the value of str, which points to a proper string inside the scope of TKCreate() but upon exiting TKCreate(), the stack contents (including parameters and local variables) are freed and wiped out so when you try to reference that pointer outside the scope of TKCreate() all bets are off.
One plausible fix is to allocate the storage for tokenizer->tks dynamically, so it persists after you exit TKCreate(). I see you do that with a call to malloc but then you overwrite that with an explicit assignment from str. Instead you should copy the contents of str (using strcpy) into the dynamically allocated memory via: strcpy(tokenizer->tks, str);

You should strcpy the contents of str to tokenizer->tks, because when you use the assign operator, you're losing the pointer malloc gave you, creating a memory leak and pointing tokenizer->tks to a local variable, which will be destroyed after the function's return.
So, the approach would be something like this:
tokenizer->tks = (char *)malloc ((strlen(str) + 1) * sizeof(char));
strcpy(tokenizer->tks, str);
Another thing:
Don't forget to free ->tks before you free tk itself.
So, after the printf, you should use:
free(tk->tks);
free(tk);
There's no problem in not freeing the structure and the string (which is in another memory location and not inside the structure's memory space, that's why you have to free they both), if your program is that small, because after it's executed, the program's memory will be wiped out anyways. But if you intend to implement this function on a fully-working and big program, freeing the memory is a good action.

It is not clear where str is defined, but if it is a local variable in the function, your problem is likely that it goes out of scope, so the data gets overwritten.
You're leaking memory because you've forgotten to use strcpy() or memcpy() or memmove() to copy the value in str over the allocated space, and you overwrite the only pointer to the newly allocated memory with the pointer str. If you copied, you would be writing out of bounds because you forgot to allocate enough space for the trailing null as well as the string. You should also check that the allocation succeeds.
Bogus code:
tokenizer->tks = (char*) malloc (strlen(str)* sizeof(char));
tokenizer->tks = str;
Fixed code:
size_t len = strlen(str) + 1;
tokenizer->tks = (char *)malloc(len);
if (tokenizer->tks == 0)
...error handling...
memmove(tokenizer->tks, str, len);
Using memmove() or memcpy() can outperform strcpy() handily (see Why is Python faster than C for some illustrations and timing). There are those who would excoriate you (and me) for using the cast on malloc(); I understand why they argue as they do, but I don't fully agree with them (and usually use the cast myself). Since sizeof(char) is 1 by definition, there's no particular need to multiply by it, though there's no harm done in doing so, either.

Related

in c why the dereference of the s point to string value not working?

why when i use the program it return s = null
the get_string function can have update to make the program work
it is : string s = malloc(sizeof(string));
but in the end of the function and after return s; i cant free(s);
or before return s; i will lose the data i stored
i tried to search more about dereference pointers but i got nothing.
#include <stdio.h>
typedef char* string;
string get_string(string q)
{
string s = NULL;
printf("%s",q);
scanf("%s",s);
return s;
}
int main(void)
{
string a = get_string("name : ");
printf("name is %s\n",a);
}
Here are two correct uses of scanf to read a string:
char s1[10];
scanf("%9s", s1);
char *s2 = malloc(100);
scanf("%99s", s2);
Notice that in both cases — s1 and s2 — I had to explicitly say how much memory I wanted for my string. Then, when I called scanf, I included that information — 1 less than the overall string size — in the %s format, so that I could tell scanf not to read a bigger string than my string variable could hold.
Notice, by contrast, that in your get_string function, you did not allocate any memory to hold your string at all. Your variable s was a null pointer, explicitly pointing to no memory at all.
This is something that's very easy to overlook at first: Most of the time, C does not allocate memory for strings for you. Most of the time, this is your responsibility.
Now, an additional concern is that even when you do allocate memory for a string, you have to think about how long that memory will stick around, and whether anyone has to explicitly deallocate it. And there are some additional mistakes that are easy to make. In particular, suppose you took my first example (s1) to heart, and tried to fix your get_string function like this:
char *get_string(char *q)
{
char s[100]; /* WRONG */
printf("%s",q);
scanf("%99s",s);
return s;
}
Here you have given scanf a proper array to read in to, but it's local to the get_string function, meaning that it will disappear after get_string returns, and it will be useless to the caller.
Another possibility is
#include <stdlib.h>
char *get_string(char *q)
{
char s = malloc(100); /* better */
if(s == NULL) {
fprintf(stderr, "out of memory!\n");
exit(1);
}
printf("%s",q);
scanf("%99s",s);
return s;
}
This will work just fine. Note that I have checked to see whether malloc succeeded. (If it fails, it returns a NULL pointer.) But now we have the issue that some memory has been allocated which might never be freed. That is, get_string returns a pointer to dynamically-allocated memory, and it's the caller's responsibility to free that memory when it's no longer needed. The caller doesn't have to, but if there end up being 1,000,000 calls to get_string, and if none of the allocated blocks ever gets freed, that's a lot of memory wasted.
First as other people have noted in the comments the Typedef in this case isn't very helpful as it hides the fact its a pointer. Also char* is vary commonly used and not a type complicated enough for a typedef IMO.
For your other issues the problem appears to be that you are thinking of the value as a C++ string instead of a char pointer. In C there aren't string objects but instead people use char* which can pointer blocks of chars and we determine the end of the string by putting a null character at the end of list of characters.
So the reason you can't print the NULL string is because it is undefined behavior to pass a NULL pointer to printf. When you change it to s = malloc(sizeof(string)); the pointer is no longer null but instead pointing to the start of a block of memory that is sizeof(string) bytes long. You should be doing malloc(sizeof(char)*strlen(q)); instead so you have a block of memory holding a string with the length of string q instead of just one character. More generally it would be malloc(sizeof(char)*NUM_CHARS);.
When it come to the free call. You can't call free(s) after return s; because no statements after return s; will occur because the function has returned and no longer executing. As for calling before, calling free(s) deallocates that block of memory that s is pointing too from the malloc(sizeof(string)) is pointing to. Here you have to remember that the function isn't returning the memory or the string but instead it returns the pointer to the string. So if you delete the memory the pointer is pointing to then you lose it once you return.

Typedef char pointer allocation of string

I am trying to understand a code that has the typedef char * I am supposed to allocate memory enough for the string "Pointer of" and "Redundancy".
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <stdio.h>
typedef char* DString;
DString dstring_initialize(const char* str);
int main(void)
{
DString str1, str2;
str1 = dstring_initialize("Pointer of ");
str2 = dstring_initialize("Redundancy ");
return 0;
}
DString dstring_initialize(const char* str)
{
str = malloc((strlen(str)+1)*sizeof(DString));//mycode
return str;//mycode
}
I am 100% sure that I am doing it completely wrong. The only thing I am supposed to do is change the part where it says mycode. It was sent to me like that, but as I said before, I don't know how it works, and if someone could explain it to me in detail, I would appreciate it
In the code below you allocate too much memory:
str = malloc((strlen(str)+1)*sizeof(DString));//mycode
^^^^^^^^^^^^^^
Not needed
Also you assign the return value from malloc to the input argument, i.e. you "destroy" the input.
Further, you never copy the value of the input string to the allocated memory.
Instead of the above, you need:
char* res = malloc(strlen(str) + 1);
if (res != NULL)
{
strcpy(res, str);
}
return res;
There are two areas of memory, the stack where local things exist, and the heap where other things exist. The stack is automatic in that your compiler manages it for you, and the heap is something that you have to manage through calls to malloc, realloc, and free, etc.
Things that are known at compile can exist in the stack, whereas things that you don't know at compile time can exist in the heap and be allocated, reallocated, freed, etc., with calls to malloc, realloc, and free.
And that basically all comes down to the size of the memory allocated. If you declare, for example, an int, that int can change in value as your program executes because it always exists in a space that is the sizeof an int.
But you might want to place your string in the heap if it changes length while the program runs and you don't want to allocate something big enough to always be able to hold it. For example, you don't need to allocate space on the heap for str if you always made it big enough with something like char str[64] or something like that because you allocate that space ahead of time.
In terms of malloc, you ask it to allocate memory of a certain size, and if it can it returns a pointer to it, if it can't it returns NULL. So the variable that holds the pointer returned by malloc exists in the stack, and the memory allocated by malloc exists in the heap and is not automatic. Ie: when your program terminates the pointer variable in the stack is released but not the actual memory stored in the heap, so you have to free it with free.
In the case of sizeof, well, that tells malloc how much you want to allocate, in this case a char, but it can be anything that can be resolved to a size, for example a structure that you define, etc. So what you're basically saying when you call malloc is "give me something this big and give me this many of them". In this case, "give me something as big as a char" and give me "strlen(str) + 1 of them".
And because the size of a character is always 1 byte and strlen returns a value of type size_t which malloc takes you can simply do it as char *ptr = malloc(strlen(str) + 1). But keep in mind that malloc returns a pointer of type void so you need to cast it to the type you are requesting. In this case you would cast it to a char* like this: ptr = (char*)malloc(strlen(str) + 1).
The other error is described in the other answer. But that is basically in a nutshell how malloc works. I'm not a teacher and I apologize if I'm not 100% clear.

How to use realloc in C [duplicate]

This question already has answers here:
Expanding an array with malloc
(4 answers)
In C, are arrays pointers or used as pointers?
(6 answers)
Closed 2 years ago.
I'm trying to reallocate memory using the realloc function, I saw that you need to use malloc before but I don't understand if you MUST use it because let's say I'm creating the following string:
char string[] = "fun";
would the realloc function work if I try to add more space?
that brings me to my question, I'm trying to simply add one letter at the end of the string, lets say 'p', but for some reason the program crushes on the realloc line every time I run it.
Here is my full code:
int main()
{
char string[] = "fun" ;
str_func(string);
printf("%s", string);
return 0;
}
void str_func(char* str)
{
str = (char*)realloc(str, strlen(str) + 2);
strcat(str, "p");
}
I also tried making a pointer to 'string' and sending the pointer, which results the same thing.
would the realloc function work if I try to add more space?
No, because that array is no allocated on the heap - in your case it is very likely allocated on the stack and can't get resized. Simply put: realloc doesn't recognize the pointer and doesn't know what to do with it, but tries to do something anyway, hence the crash.
You can only call realloc on a pointer that was previously passed to malloc, or on a null pointer. That's just how these functions work.
For details, see What gets allocated on the stack and the heap?.
I saw that you need to use malloc before but I don't understand if you MUST use it
If you need to use malloc before you can realloc something, then by definition you must only realloc things originally allocated with malloc.
You're trying to find some space between "need" and "must" that doesn't exist.
... for some reason the program crushes on the realloc
You already said you know you need to use malloc. Then you didn't use malloc, and you're asking why this is a problem. You could at least try doing the thing you "know" you need to do, to see if that solves the problem.
The program should probably look like
int main()
{
/* array is an automatic local variable. It wasn't dynamically allocated
in the first place, so can't be dynamically re-allocated either.
You cannot (and don't need to) free it either, it just goes out of scope
like any other automatic variable.
*/
char array[] = "fun";
/* you need to use malloc (or one of the other dynamic allocation functions)
before you can realloc, as you said yourself */
char *dynamic = malloc(1+strlen(array));
memcpy(dynamic, array, 1+strlen(array));
/* realloc can move your data, so you must use the returned address */
dynamic = str_func(dynamic);
printf("old:'%s', new:'%s'\n", array, dynamic);
/* not really essential since the program is about to exit anyway */
free(dynamic);
}
char* str_func(char* str)
{
char* newstr = realloc(str, strlen(str) + 2);
if (newstr) {
strcat(newstr, "p");
return newstr;
} else {
/* we failed to make str larger, but it is still there and should be freed */
return str;
}
}
Your original condition isn't quite correct: actually the pointer passed to realloc
... must be previously allocated by malloc(), calloc() or realloc() and not yet freed with a call to free or realloc
[OR] If ptr is NULL, the behavior is the same as calling malloc(new_size).
The realloc function only works with things that were originally created with a small group of allocation functions (such as malloc, calloc, or realloc itself), or the null pointer. Since string is none of those things, your code is not well-defined.

strdup and memory leaking

Does strdup allocate another memory zone and create another pointer every time?
For example: does the following code result in a memory leak?
void x(char** d, char* s){
*d = strdup(s);
}
int main(){
char* test = NULL;
x(&test, "abcd");
x(&test, "etc");
return 0;
}
Yes, the program leaks memory because it allocates objects and then loses references to them.
The first time this happens is in the line:
x(&test, "etc");
The variable test holds the one and only copy of a pointer that was allocated in a previous call to x. The new call to x overwrites that pointer. At that point, the pointer leaks.
This is what it means to leak memory: to lose all references to an existing dynamically allocated piece of storage.*
The second leak occurs when the main function returns. At that point, the test variable is destroyed, and that variable holds the one and only copy of a pointer to a duplicate of the "etc" string.
Sometimes in C programs, we sometimes not care about leaks of this second type: memory that is not freed when the program terminates, but that is not allocated over and over again in a loop (so it doesn't cause a runaway memory growth problem).
If the program is ever integrated into another program (for instance as a shared library) where the original main function becomes a startup function that could be invoked repeatedly in the same program environment, both the leaks will turn into problems.
The POSIX strdup function behaves similarly to this:
char *strdup(const char *orig)
{
size_t bytes = strlen(orig) + 1;
char *copy = malloc(bytes);
if (copy != 0)
memcpy(copy, orig, bytes);
return copy;
}
Yes; it allocates new storage each time.
If you have a garbage collector (such as Boehm) in your C image, then it's possible that the leaked storage is recycled, and so strdup is able to re-use the same memory for the second allocation. (However, a garbage collector is not going to kick in after just one allocation, unless it is operated in a stress-test mode for flushing out bugs.)
Now if you want to actually reuse the memory with realloc, then you can change your x function along these lines:
#include <stdlib.h>
#include <string.h>
void *strealloc(char *origptr, char *strdata)
{
size_t nbytes = strlen(strdata) + 1;
char *newptr = (char *) realloc(origptr, nbytes); /* cast needed for C++ */
if (newptr)
memcpy(newptr, strdata, nbytes);
return newptr;
}
(By the way, external names starting with str are in an ISO C reserved namespace, but strealloc is too nice a name to refuse.)
Note that the interface is different. We do not pass in a pointer-to-pointer, but instead present a realloc-like interface. The caller can check the return value for null to detect an allocation error, without having the pointer inconveniently overwritten with null in that case.
The main function now looks like:
int main(void)
{
char *test = strealloc(NULL, "abcd");
test = strealloc(test, "etc");
free(test);
return 0;
}
Like before, there is no error checking. If the first strealloc were to fail, test is then null. That doesn't since it gets overwritten anyway, and the first argument of strealloc may be null.
Only one free is needed to plug the memory leak.
* It's possible to have a semantic memory leak with objects that the program hasn't lost a reference to. For instance, suppose that a program keeps adding information to a list which is never used for any purpose and just keeps growing.
Yes, it allocates memory and leaks if you don't free it. From the man page:
The strdup() function returns a pointer to a new string which is a duplicate of the string s. Memory for the new string is obtained with malloc(3), and can be freed with free(3).
new_s = strdup(s) is essentially equivalent to:
new_s = malloc(strlen(s)+1);
strcpy(new_s, s);
Consider the following definition for strdup:
#include <string.h>
char *strdup(const char *string);
strdup reserves storage space for a copy of string by calling malloc. The string argument to this function is expected to contain a null character (\0) marking the end of the string. Remember to free the storage reserved with the call to strdup.
You must free the string yourself.

Is it risky to use freed memory

Suppose I have a char pointer which points to some string in memory.
and suppose I want to copy that string to some other place in memory.
void cpy(char **dst, char *src)
{
*dst = (char *) realloc(*dst, strlen(src) + 1);
memcpy(*dst, src, strlen(src) + 1);
}
(Assume memory allocation is successful, and src is not NULL)
What if I call this function like this:
char *str = malloc(14);
memcpy(str,"hello, world!", 14);
cpy(&str,str+7);
Now I would expect srt to point to the string "world!" (Which it does in my tests).
But what concerns me is that in this call to cpy, *dst and src actually point to different locations of the same string. And, when calling realloc on *dst, it's possible that this memory will be freed. But in the next line I'm trying to copy from that place with memcpy.
So the questions is: Is there something wrong with it?
Or to put it another way - is it okay to free memory, and use it immediately afterwards?
Thanks.
Note: The example was updated so that realloc is called on memory that was obtained with malloc.
Everything is wrong with this. It is outright undefined behaviour to call realloc on a pointer that was not obtained with malloc etc.
As #Daniel Fischer points out, it is also undefined behaviour to use memcpy on overlapping regions of memory (in which case you should use memmove), so you have to be careful.
Update: After your substantial edit, the question is quite different. It is now equivalent to this condensed version:
char * s = malloc(14);
strcpy(s, "hello, world!");
char * p = realloc(s, 14);
memcpy(p, s, 14);
This is also undefined behaviour, because you are not allowed to access the memory pointed to by s anymore after a successful realloc, and you're not allowed to access the memory pointed to by p after an unsuccessful realloc.
The implicit assumption in your example is that it is permitted for cpy to free memory it didn't allocate. It's kind of a dodgy assumption, but as long it's intentional, that's OK. Use malloc and free separately rather than realloc in that case:
void cpy(char **dst, char *src)
{
// obtain completely new memory (realloc might do this anyway)
char* new = malloc(strlen(src) + 1);
// duplicate the string
memcpy(new, src, strlen(src) + 1);
// release the original memory now that we know we are done with it
free(*dst);
// indicate where to find the new string
*dst = new;
}
This still isn't a great idea, because there's no way to know what other variables might be pointing at that memory that you're freeing, but if you have a way to make that guarantee, this is the kind of code you need.

Resources