1

Assume I have a struct

struct 
foo{
char *p1;
char *p2;
char *p3;
}foo;

and I have assigned the struct malloc - allocated string line that

#include <stdlib.h>
#include <string.h>

char temp[] = "this is string"
char *allocated_temp = malloc(sizeof(temp));
strcpy(allocated_temp, temp);

struct foo bar; 
bar.p1 = strtok(allocated_temp, " ");
bar.p2 = strtok(NULL, " ");
bar.p3 = strtok(NULL, " ");

I want to free p1 without freeing the other memory that is pointed to by p2 and p3. using realloc will not work as p3 will be freed first, and I am searching for a more of a elegant solution than using coping the struct to a new one without the first part or reallocating the other two strings to a different address.

What good solutions does this problem have?

(to clarify, when I am saying I want to free p1 i mean the "this\0" part of the string.

avivgood2
  • 227
  • 3
  • 19
  • 1
    This looks like an XY-problem. Why do you want to free part of an array? – klutt Jul 04 '20 at 10:16
  • @klutt Yes, I want to free the first part of the memory block (the part before the first null terminator). What is a XY-problem? – avivgood2 Jul 04 '20 at 10:18
  • XY-problem: https://meta.stackexchange.com/q/66377/374458 – klutt Jul 04 '20 at 10:20
  • @klutt I am creating an assembler and in some cases the assembler needs to ignore the prefix of a line. (lables before ```.entry``` and ```.extern```) so when I find out this needs to be ignored I set the lable field in the struct to NULL. but then I need to free that part of the string (the lable part) – avivgood2 Jul 04 '20 at 10:23
  • just do not allocate memory for the first 'word' do something like `char *allocated_temp * strdup(strchr(temp, ' ') +1); ... bar.p2 = strtok(allocated_temp, " "; bar.p3 = strtok(allocated_temp, NULL);` and nothing about `p1` – bruno Jul 04 '20 at 10:24
  • 1
    So when you want to ignore it, why not just use `p2`? – klutt Jul 04 '20 at 10:24
  • @klutt I have read about what an XY problem is. If I will ask about X I will need to provide the full assembler architecture which is over 1200 lines of code and will require much explanation. I hope my last comment is enough to give you background. – avivgood2 Jul 04 '20 at 10:26
  • Yeah, it's just that I don't understand WHY you want to free the first word. You have a pointer to the second. Why not just use `p2` and when you're done with everything, free `p1` – klutt Jul 04 '20 at 10:27
  • @klutt ok I understand. I do it because when I later pass the struct to another function, it dosen't "knows" that the label should be ignored, unless it checks again, and if it checks again than all function will have to check again and it will be a waste – avivgood2 Jul 04 '20 at 10:33
  • Hmmm, my spontaneus thought is that you probably should rethink your code design. – klutt Jul 04 '20 at 10:36
  • @klutt do you have an alternative code design in mide for that problem? I thought that first pursing the string (user input) into structs will make it easier for me later on and it is more modular to do so as the machine code part of the program should not deal with user input directly – avivgood2 Jul 04 '20 at 10:41
  • Maybe `strtok(allocated_temp, " "); /* Skipping first word */ bar.p1 = strtok(allocated_temp, NULL);` – klutt Jul 04 '20 at 10:44
  • @klutt yes but the assembler ignores the labels is certain situations only, and I can know whether the label should or should not be ignored just after I will all the pointers in the struct, so I can't skip the first one, I can only delete it later on. – avivgood2 Jul 04 '20 at 10:50
  • 1
    Your use of `strtok()` is incorrect. `bar.p1 = strtok(allocated_temp, " ");` is fine for the first line, but your later lines `bar.p2 = strtok(allocated_temp, NULL);` are wrong. They should be `bar.p2 = strtok(NULL, " ");` The string being parsed is replaced by `NULL`, not the separator string. – Andrew Henle Jul 04 '20 at 10:50
  • @AndrewHenle changed it. – avivgood2 Jul 04 '20 at 10:51
  • Add `bool skip` to your struct? – klutt Jul 04 '20 at 10:52
  • @klutt can do, but setting NULL is more clear, becuse it means more clearly there is no lable . and saves redundant field from the struct. But this is a good solution – avivgood2 Jul 04 '20 at 10:55
  • If setting `p1` to NULL is an option, why not just do that? – klutt Jul 04 '20 at 11:09
  • @klutt it will cause a memory leak – avivgood2 Jul 04 '20 at 11:18
  • Not if you free `allocated_temp` afterwards. Honestly, I think you should take some time and clarify your question. It seems like no matter what is suggested, you will counter with something that cannot be seen in the question. – klutt Jul 04 '20 at 11:21

1 Answers1

1

There is no solution to your problem with standard tools (malloc, etc). You can only free the end of the memory that was allocated by realloc()-ing with a smaller size.

If you want to free p1 this way, you must first move your data to the beginning of the allocated block, update your pointers (p2 and p3) and then call realloc().

The best way is probably to change your program in order to malloc p1, p2 and p3 separately.

xhienne
  • 5,738
  • 1
  • 15
  • 34
  • 1
    *If you want to free p1 this way, you must first move your data to the beginning of the allocated block, update your pointers (p2 and p3) and then call realloc().* Even that's probably not worth the overhead given short input strings. The call to `realloc()` is likely to do nothing since most heap implementations allocate memory in blocks no smaller than 8, 16, or even 32 bytes because of alignment requirements. The bigger problem is having to keep track of the original pointer so it can be freed later – Andrew Henle Jul 04 '20 at 10:53
  • @AndrewHenle Agreed, hence my last paragraph. I'm just providing an algorithmically correct solution if the OP is in dire need to free p1. – xhienne Jul 04 '20 at 11:06