Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

question: why pass by reference in sc_str_substring((char** str, uint32_t start, uint32_t end)? #124

Closed
midnqp opened this issue Jul 31, 2023 · 6 comments

Comments

@midnqp
Copy link

midnqp commented Jul 31, 2023

I'd say I am still new to learning to code in C. This library has been really helpful for me to see how C code is written in the real world. So, thank you!

I was wondering why pass the str by reference in some cases sc_str_destroy() and sc_str_trim(), because I think it's possible to work with pointers without it. For example:

void alter(char* str) {
  str[0] = 'f';
  free(str);
}

int main() {
  char* str = malloc(6);
  strcpy(str, "hello");
  alter(str);
}
@tezc
Copy link
Owner

tezc commented Jul 31, 2023

Hi @midnqp, glad this repo is being helpful to you.

Just to be clear, you wonder why it passes double pointer e.g. char** instead of char* right? Reason is that some functions might need to change the value of the pointer.

For example, here: see the link
This function makes another allocation and updates the value of the pointer. To do that, you need to get char**.

So, you need to get "pointer to pointer" if you need allocate new memory in your function. In other cases, as in your example above, if you just want to change its content (its characters) it is not necessary.

One exceptional case is sc_str_destroy(). You may use char* as it just calls free() for the pointer. But just to make it safe to call twice, this function sets pointer to NULL. See: link

So, user does not have to remember if it called sc_str_destroy() before, it will be safe to call it multiple times.

e.g:

char *c = sc_str_create("hello");
sc_str_destroy(&c); // This call will set c = NULL 
...
sc_str_destroy(&c); // Safe to call it twice.

// Otherwise you would need to write 
if (c != NULL)  {
    sc_str_destroy(c);
    c = NULL;
}
// So, it saves you adding these NULL if checks in your application.

Let me know if this is clear? Cheers!

@midnqp
Copy link
Author

midnqp commented Jul 31, 2023

Wow, this is really simple and clear as a crystal ✨ Thanks for your time in explaining this to me! I actually did notice you mention that everytime we use set, create, append a new pointer is created. Perfect!

However, we could extend the previous pointer's memory. But.. oh, realloc() still malloc()s under the hood. So we don't have a choice other than to create a pointer everytime.

Wow, this library is well-built.

@tezc
Copy link
Owner

tezc commented Jul 31, 2023

Be careful with realloc, it is not guaranteed to return the same value even when you call it to shrink the memory. I've seen that is happening, I had to debug a painful issue :)

So, you don't have any other way, you have to get char** if you want to (potentially) update the pointer.

@midnqp
Copy link
Author

midnqp commented Aug 6, 2023

One last thing: kindly elaborate a tiny bit on this please? "it is not guaranteed to return the same value" - I understand realloc() returns a new pointer, but not the same value?

@tezc
Copy link
Owner

tezc commented Aug 6, 2023

I understand realloc() returns a new pointer, but not the same value?

My point is realloc() may return same value on some calls and it may return another value on other calls. Because allocator (malloc(), realloc() implementation) is free to return whatever it wants.

void *x = malloc(10);

// y points to same memory with x
void *y = x;

// Extend memory allocation. After realloc(), will y be equal to x? 
y =  realloc(y, 20);

 
// Assume that x points to a memory which has already 20 bytes empty space, 
// then allocator can mark your allocation as 20 bytes and it can return the same pointer. (y == x);
//
// If there is not enough space (assume x points to 10 bytes empty space and there are used bytes 
// by someone else just after that) , allocator has to return another pointer to you (y != x)

So, my point is we cannot say realloc() will return same or different value. It totally depends on allocator implementation.
Your interpretation is correct, if we assume realloc() will return new pointer all the time, we won't make mistakes but as you can see above, in reality, that might not be true :)

Let me know if it is clear.

@tezc
Copy link
Owner

tezc commented Aug 24, 2023

@midnqp please feel free to open issue if you have other questions! Cheers!

@tezc tezc closed this as completed Aug 24, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants