How can I free a string up to a certain point? For example if I have:
char *s = (char *)malloc(sizeof(char) * 21);
s[20] = '\0';
int i = 0;
while (i < 21)
{
s[i] = i + 'a';
i++;
}
And then I cut off the string at some point and store that half:
*(s + 10) = '\0';
char *m = s + 11;
Is there a way to free s up to s + 10 or the first \0?
Since s has been allocated by the system, you can perform a realloc on it to shorten the size:
s = realloc(s, 11);
But you cannot free the start of an allocated zone without freeing the rest, that you cannot. Use memmove & realloc to shift the data and reduce size afterwards.
Attempting to free a pointer which hasn't been allocated, or an allocated pointer plus an offset results in undefined behaviour.
You could do (as you suggested yourself, but with problems fixed :)):
char *c = strdup(s + 10);
free(s);
s = c;
so now s points to the end of the string.
alternative without strdup but using standard functions only (with the risk of forgetting the null-termination char):
char *c = malloc(strlen(s) - 10 + 1);
strcpy(c,s + 10);
free(s);
s = c;
and the memmove solution I was hinting about at first (avoids to allocate/free but offset/size is trickier to compute):
int offset = 10;
int size = strlen(s) - offset;
memmove(s,s+offset,size);
s[size]='\0'; // null-terminate
s = realloc(s,size+1); // adjust size after null-termination
Is there a way to free s up to s + 10 or the first \0?
No. Not in the standard library at least.
There's realloc but it isn't guaranteed to "free s up to s + 10 or the first \0".
Related
This question already has answers here:
How should character arrays be used as strings?
(4 answers)
Closed 2 months ago.
int main() {
char A[200], B[200];
printf("Enter 2 words or sentences.\n");
gets(A);
gets(B);
char* C = (char*)malloc((strlen(A) + strlen(B)) * sizeof(char));
for (int i = 0; i < strlen(A); i++)
C[i] = A[i];
for (int i = 0; i < strlen(B); i++)
C[i + strlen(A)] = B[i];
printf("%s", C);
}
The initial value of C is ÍÍÍÍÍÍÍÍÍÍýýýý, which is 4 symbols longer than requested and the 4 symbols also show up as output when printing C. I have no idea why there are 4 symbols, which is why I'm here seeking an explanation.
Problems:
Not null character terminated
Code attempts printf("%s", C); which is undefined behavior as C[] is not a string as needed by "%s".
// Append a \0
C[strlen(A) + strlen(B)] = '\0';
Insufficient memory allocated
Make room for the null character.
// (strlen(A) + strlen(B)) * sizeof(char)
strlen(A) + strlen(B) + 1
gets() is no longer part of the standard C library since C11
Use fgets() and lop off a potential trailing '\n' for similar behavior.
int vs. size_t
int is insufficient for very long strings. size_t works for all strings.
Avoid potentially recalculating the string length
int main(void) {
char A[200], B[200];
printf("Enter 2 words or sentences.\n");
// Code should check the return value of fgets()
// Omitted for brevity.
fgets(A, sizeof A, stdin);
A[strcspn(A, "\n")] = '\0'; // Lop off potential \n
fgets(B, sizeof B, stdin);
B[strcspn(B, "\n")] = '\0';
size_t A_len = strlen(A);
size_t B_len = strlen(B);
char* C = malloc(A_len + B_len + 1);
if (C) {
for (size_t i = 0; A[i]; i++) {
C[i] = A[i];
}
for (size_t i = 0; B[i]; i++) {
C[A_len + i] = B[i];
}
C[A_len + B_len + i] = '\0';
printf("%s\n", C);
free(C); // Good housekeeping to free allocations.
}
}
malloc just returns a pointer to some memory it allocated for you. It doesn't initialize that memory, zero it out, or anything like that. So what you're seeing when you print it out, is whatever junk was in there before.
Frankly, you're lucky you didn't open up a wormhole or something. C strings are nul-teminated, so when you pass that pointer around, you're technically not passing a string yet. When you pass it to a function that expects a string, all kinds of wackiness can ensue.
You should initialize the memory when you get it. The simplest initialization would be something like *C = '\0'; or C[0] = '\0';, which turns the memory into a zero-length string. But you probably already have something to put there, or why would you be allocating memory in the first place? :P
Now that there's code, we can tweak it a bit to fix the issue...
int main() {
char A[200], B[200];
printf("Enter 2 words or sentences.\n");
// BTW: you should never, ever be using `gets`.
// use `fgets` and pass the size of your buffer to avoid overruns.
// note: it returns a null pointer if it fails...at which point you
// can't trust that A and B are strings, and should probably bail
if (!fgets(A, sizeof A, stdin)) return 1;
if (!fgets(B, sizeof B, stdin)) return 1;
// you don't want to call `strlen` over and over. save these lengths
size_t Alen = strlen(A);
size_t Blen = strlen(B);
// lop off the newlines
if (Alen && A[Alen - 1] == '\n') A[--Alen] = '\0';
if (Blen && B[Blen - 1] == '\n') B[--Blen] = '\0';
// You need enough space for both strings, plus a nul at the end.
// side note: you don't need to cast the pointer to a `char *`.
// also, sizeof(char) is 1 by definition, so no need to multiply by it.
char* C = malloc(Alen + Blen + 1);
if (!C) return 1;
// compare to the length variable instead
for (int i = 0; i < Alen; i++)
C[i] = A[i];
for (int i = 0; i < Blen; i++)
C[i + Alen] = B[i];
// important: nul-terminate the string
C[Alen + Blen] = '\0';
printf("%s", C);
// not strictly necessary at the end of main on a modern OS, but
// you should free what you malloc
free(C);
}
C[strlen(A) + strlen(B)] = '\0'; after the malloc gets rid of the junk, thanks everyone for the ideas.
This question already has answers here:
Using realloc to shrink the allocated memory
(5 answers)
Can I assume that calling realloc with a smaller size will free the remainder? [duplicate]
(5 answers)
what will realloc do to the old pointer [duplicate]
(6 answers)
Closed 2 years ago.
I have a few questions about understanding
realloc behavior.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *str;
/* Initial memory allocation */
str = malloc(5 * sizeof(int));
*str = 1;
*(str + 1) = 2;
*(str + 2) = 3;
*(str + 3) = 4;
*(str + 4) = 5;
/* Reallocating memory */
int i, j;
for (i = 5; i > 0; i--) {
str = realloc(str, i * sizeof(int));
for (j = 0; j < i; j++) {
printf("%d", *(str + j));
}
printf("\n");
}
free(str);
return(0);
}
In this code example, can I be sure that a smaller realloc will drop the highest number?
Is the realloc is only freeing the last memory and keeping the same address in str? Or may the address change even though it's getting smaller and for sure have space in the current place?
Yes. If you have a memory block p of size N and you do realloc(p, M), then (assuming realloc succeeds), the result will contain the first min(N, M) bytes from p.
The address can change, even if the new size is smaller than the old one. realloc simply makes no guarantees about this case (it can even fail).
I've got a array of strings (char**) and I need to do some redimensioning on it when it has reached its capacity. So, in this function I create a new array, allocate a size two time bigger than before, and for each string in the old array I allocate space for the new array and copy the content. Code is as follows:
void matrix_double (char ***arrayptr, int *size) {
char **array = *arrayptr, **newarr;
int i, wordsize;
newarr = malloc (*size * 2);
for (i = 0; i < *size; i++) {
wordsize = strlen (array[i]);
newarr[i] = malloc (wordsize + 1);
strcpy (newarr[i], array[i]);
free (array[i]);
}
*size *= 2;
free (array);
*arrayptr = newarr;
}
However, I'm getting a lot of segfaults when allocating space for the new strings in the 7th line. According to Valgrind, those malloc commands are allocating space from within the space allocated for the array, which is small - I'm using arrays of 10 or 20 strings at most - and so it overflows to other allocated areas, causing segfaults. If I bump the array memory allocation up (such as malloc (*size * 200) everything runs smoothly.
Any ideas on what's happening? Haven't seen this behavior anywhere else.
malloc argument is size in bytes. So you should call it like
malloc(sizeof(char *) * (*size) * 2);
By calling
malloc(*size * 2);
you are allocating 2*size bytes of memory which is not enough for size of pointers.
Here's my function.
char * substring(int begin, int end, char * string)
{
int size = end - begin + 1;
char * s = (char *)malloc (sizeof(size));
int i;
for (i = 0; i < size; i++)
{
s[i] = string[begin++];
}
return s;
}
So let's say my string was only supposed to be "I". But when I try to print out the string later, I get I + 3 extra characters that were unintended. How do I fix this?
First, change the line
char * s = (char *)malloc (sizeof(size));
to
char * s = malloc( size + 1 ); // + 1 for null terminator
sizeof (size) gives you the number of bytes in an integer (2 to 4 to 8 depending on your platform), which is not necessarily what you want.
Next, use the strncpy function to copy the first size characters of string:
strncpy( s, string, size );
Make sure the string is null-terminated:
s[size] = '\0';
You have extra characters printed since you haven't null-terminated the s string:
s[i] = 0;
return s;
Fix the allocation to size, and also note that the following may depend on your interpretation of begin and end, but if you interpret the end as pointing to the last character you intend to copy (this would be a-typical), then you will need to adjust the size by 1.
This is undefined behavior waiting to happen. Your biggest problem is that your allocation should be
char * s = (char *)malloc (size);
I am getting segmentation fault in the following code
static char * result;
char s[31];
int i;
random_string(s, 10);
// for (i = 0; i < 15; i++){
// result[i] = s[i];
// }
strcpy(result, s);
printf("el result es %s\n", result);
where the function random_string is:
void random_string(char * string, int length)
{
/* Seed number for rand() */
int i;
for (i = 0; i < length -1; ++i){
string[i] = rand() % 90 + 65;
}
string[length] = '\0';
}
For some reason I am getting segmentation fault when using strcpy. Also copying byte by byte is not working. What is the problem? I am out of ideas.
The problem is that result has not been initialized. It results in undefined behavior. Before it can be used like that, you need to make sure it points to a valid buffer. For example:
result = malloc( strlen( s ) + 1 );
static char * result; is just an address without any allocated memory!
Try this:
[EDITED]
char * result = (char*)malloc(strlen(s) + 1);
You forgot to allocate memory to "result" pointer. Try next:
result = malloc( strlen( s ) + 1 );
strcpy(result, s);
result is just a uninitialised pointer.
You must assign result to a character buffer before using strcpy.
You need to assign a valid memory region to your result pointer using malloc or using static memory, as you are doing with your s string. Otherwise your pointer has just a random location assigned and your program receives a segfault by accessing it as it lies out of the boundaries of your program.
Declare result as a char array like
static char result[10];
or assign some memory to result pointer.