When I allocate an array using malloc, is there a way to only free the first element(s) of the array?
A small example:
#include <stdlib.h>
#include <string.h>
int main() {
char * a = malloc(sizeof(char) * 8);
strcpy(a, "foo bar");
// How I would have to do this.
char * b = malloc(sizeof(char) * 7);
strcpy(b, a+1);
free(a);
free(b);
}
Is there a way to free just the first char of a, so that I can use the rest of the string using a+1?
If you want to remove the first character of a, you could use memmove() to move the remainder of the characters in the string to the left by 1, and you could use realloc() to shrink the allocation if desired:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char * a = malloc(sizeof(char) * 8);
strcpy(a, "foo bar");
puts(a);
size_t rest = strlen(a);
memmove(a, a+1, rest);
/* If you must reallocate */
char *temp = realloc(a, rest);
if (temp == NULL) {
perror("Unable to reallocate");
exit(EXIT_FAILURE);
}
a = temp;
puts(a);
free(a);
return 0;
}
Update
#chux has made a couple of good points in the comments.
First, instead of exiting on a failure in realloc(), it may be better to simply continue without reassigning temp to a; after all, a does point to the expected string anyway, the allocated memory would just be a little larger than necessary.
Second, if the input string is empty, then rest will be 0. This leads to problems with realloc(a, rest). One solution would be to check for rest == 0 before modifying the string pointed to by a.
Here is a slightly more general version of the above code that incorporates these suggestions:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char *s = "foo bar";
char *a = malloc(sizeof *a * (strlen(s) + 1));
strcpy(a, s);
puts(a);
size_t rest = strlen(a);
/* Don't do anything if a is an empty string */
if (rest) {
memmove(a, a+1, rest);
/* If you must reallocate */
char *temp = realloc(a, rest);
if (temp) {
a = temp;
}
}
puts(a);
free(a);
return 0;
}
Is there a way to free just the first char of a
No. You can not free the first character of a because it is of char type. Only pointer returned by malloc family function can be freed.
You can do this though.
char * a = malloc(sizeof(char) * 8);
strcpy(a, "foo bar");
char * b = malloc(strlen(a));
strcpy(b, a+1);
free(a);
Related
As a homework I need to rewrite the string.h library, I have started with the strcat function but I am having trouble printing the **dest variable.
Here is the code:
#include <stdlib.h>
#include <stdio.h>
#ifndef MY_STRING_H
#define MY_STRING_H
int my_strlen(char *str){
int count;
for (count = 0; str[count] != '\0'; ++count);
return count;
}
void my_strcat(char **dest, const char *src){
size_t srcSize = my_strlen((char *)src);
size_t destSize = my_strlen((char *)dest);
dest = realloc(dest ,(destSize + srcSize) * sizeof(char));
int count;
printf("%s \n", (char *) dest); //prints null here
for (count = 0; dest[count] != '\0'; ++count); //throws segmentation error here
for (int count2=0; src[count2] != '\0'; ++count2){
*dest[count] = src[count2];
count += 1;
}
*dest[count] += '\0';
}
int main (){
char str[80] = "these strings";
my_strcat ((char **) str,"are ");
my_strcat ((char **) str,"concatenated.");
printf("%s", str);
return 0;
}
#endif // MY_STRING_H
I dont know how I can fix this please help me.
In my_strcat(), you used a char ** pointer while you transfer a char * pointer, maybe you can use (char *)dest.
(Also, since you have a my_strlen() function, you don't need a for loop to get the length of array.)
in this case, i tried to fix it like :
#include <stdlib.h>
#include <stdio.h>
#ifndef MY_STRING_H
#define MY_STRING_H
int my_strlen(char *str){
int count;
for (count = 0; str[count] != '\0'; ++count);
return count;
}
void my_strcat(char **dest, const char *src){
size_t srcSize = my_strlen((char *)src);
size_t destSize = my_strlen((char *)dest);
dest = realloc(dest ,(srcSize+destSize) * sizeof(char));
int count;
int count2=0;
printf("%s\n", (char *) dest); //prints null here
for (count=0 ;((char *)dest)[count]!='\0'; ++count); //throws segmentation error here
for (; src[count2] != '\0'; ++count2){
((char *)dest)[count] = src[count2];
count += 1;
}
((char *)dest)[count] += '\0';
}
int main (){
char str[80] = "these strings";
my_strcat ((char **) str,"are ");
my_strcat ((char **) str,"concatenated.");
printf("%s", str);
return 0;
}
#endif // MY_STRING_H
By chance, i noticed that if replace printf("%s\n", (char *) dest) to printf("%s \n", (char *) dest), something wrong will happen. Amazing! I tried to read assembly code to found the difference between two code, and i find that for the first printf, it will be compilered into puts while the second will be compilered into printf with "%s \n" compilered into a string. I haven't know what happened now.
Then, suddenly, i think that we transfer a pointer str which point to data in stack, while it seems we need a pointer point to data in heap.
i tried some simple code:
#include <stdlib.h>
#include <stdio.h>
int main (){
char str[80] = "these strings";
printf("%lld\n", str);
void * p = realloc(str ,100 * sizeof(char));
printf("%lld", &((char *)p)[4]);
return 0;
}
it works well.
however, in:
#include <stdlib.h>
#include <stdio.h>
int main (){
char str[80] = "these strings";
printf("%lld\n", str);
char str1[80] = "these strings";
printf("%lld\n", str1);
void * p = realloc(str ,100 * sizeof(char));
printf("%lld", &((char *)p)[4]);
return 0;
}
it can't work.
then:
#include <stdlib.h>
#include <stdio.h>
int main (){
char * str = (char *)malloc(80);
str[0] = 'h'; str[1] = 'i'; str[2] = '\0';
printf("%lld\n", str);
char str1[80] = "these strings";
printf("%lld\n", str1);
void * p = realloc(str ,100 * sizeof(char));
printf("%lld", &((char *)p)[4]);
return 0;
}
it works well.
so, it seems you can't get str by this way, for the pointer transfered into realloc() should be alloced by malloc(), calloc() or realloc(). In another word, this pointer should point to data in heap. You can see this in realloc - cppreference. When i change the way we get str by malloc, it works well. You can try this.
At last, from the args of my_strcat(), i think maybe you should change the way you implement this function.
I haven't written C code for a long time, hope this can help you.
I have two char pointers:
char *temp;
char *saveAlias;
I want to assign saveAlias with whatever is stored in temp; saveAlias is currently empty while temp has a string of an unknown size saved from user input.
Note that I don't want saveAlias to point to where temp points; I want the content of temp and assign (get pointed) it to saveAlias.
I have attempted using strcat and strcpy but to no avail.
Assuming that your temp variable points to a character string that is suitably nul-terminated (as strings in C should be), then you can just use the strdup() function to make a copy of it and store a pointer to that in saveAlias. This function will duplicate the given string into newly-allocated memory; that memory should be released, using the free function, when no longer needed:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char* temp = "source string";
char* saveAlias = strdup(temp);
printf("Temp is <%s> (at %p).\n", temp, (void*)temp);
printf("Alias is <%s> (at %p).\n", saveAlias, (void*)saveAlias);
free(saveAlias);
return 0;
}
The strdup function effectively combines malloc and strcpy into a single function call, with the call shown above being the equivalent of:
char* saveAlias = malloc(strlen(temp) + 1);
strcpy(saveAlias, temp);
If you want to allocate memory for a copy of the string currently pointed to by temp, use strdup():
#include <stdio.h>
#include <string.h>
int main() {
char buf[128];
char *temp;
char *saveAlias = NULL;
if ((temp = fgets(buf, sizeof buf, stdin)) != NULL) {
saveAlias = strdup(temp);
if (saveAlias == NULL) {
fprintf(stderr, "allocation failed\n");
} else {
printf("saveAlias: %s\n", saveAlias);
}
}
free(saveAlias);
return 0;
}
You can basically point the saveAlias to temp; Thus you would have:
saveAlias = temp;
As noted by Chris. This will make one pointer point to another.
Correcting my answer. I suggest you define de size of saveAlias with malloc, and then use the memcpy function. You will have:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(){
char *temp = "your_char";
//with malloc you make sure saveAlias will have the same size as temp
//and then we add one for the NULL terminator
char *saveAlias = (char*) malloc(strlen(temp) + 1);
//then just
strcpy(saveAlias, temp);
printf("%s\n", temp);
printf("%s", saveAlias);
return 0;
}
Thank you chqrlie for the explanation also. I was mistaken about the memcpy.
Jus started learning about pointers and im stuck with this program outputting a segmentation fault.
Its supposed to copy the first 10 Characters of a string to the location pointed by the double pointer
using gdb ive found that **pt=*s; produces the seg fault
#include <stdio.h>
#include <stdlib.h>
void str1(char *s, char **pt);
void str1(char *s, char **pt){
for(int i=0;i<10;i++){
**pt=*s;
pt++;
s++;
}
}
int main (void) {
char str[30] = "223This is test";
char *ptr;
str1(str, &ptr);
printf("%s", ptr);
return 0;
}
First of all ptr is not initialized, you can't really use it until you reserve space for it or store a valid memory address in it, i.e. make it point to some valid variable.
char *ptr = malloc(11);
Then you need to increment it properly in the function:
(*pt)++;
Once the copy is completed you need to null terminate the char array so it can be treatead as a string, aka a null terminated char array.
**pt = '\0';
Now as ptr was passed as a pointer to pointer, the increment is known by the caller, main in this case, so when you try to print it, it prints nothing because it's pointing to the end of the char array, we need to bring it back to the beggining.
*pt -= 10;
Corrected code with comments taking yours as base:
Live demo
#include <stdio.h>
#include <stdlib.h>
#define SIZE 10
void str1(char *s, char **pt) {
for (int i = 0; i < SIZE; i++) {
**pt = *s;
(*pt)++; //properly increment pt
s++;
}
**pt = '\0'; //null terminate copied string
//since ptr was passed as **, the increment is known by the caller
//now ptr will be pointing to the end of the string
//we have to bring it back to the beginning
*pt -= SIZE;
}
int main(void) {
char str[] = "223This is test";
char *ptr = malloc(SIZE + 1); //space for 10 character + null-terminator
//check for allocation errors
if(ptr == NULL){
perror("malloc");
return EXIT_FAILURE;
}
str1(str, &ptr);
printf("%s", ptr);
free(ptr);
return EXIT_SUCCESS;
}
You probably want this:
#include <stdio.h>
#include <stdlib.h>
void str1(char* s, char** pt) {
char *p = malloc(100); // allocate memory for destination
*pt = p; // store it for the caller
for (int i = 0; i < 10; i++) {
*p = *s;
p++;
s++;
}
*p = 0; // put string terminator, otherwise printf won't work correctly
}
int main(void) {
char str[30] = "223This is test";
char *ptr; // for now p points nowhere
str1(str, &ptr); // now p points to the memory allocated in str1
printf("%s", ptr);
free(ptr); // free memory for completeness
return 0;
}
There's a function. It is add_lexem and adds an element (char *) in the end of specified array and. If no memory left, it allocates some extra memory (100 * sizeof(char *)). That function causes segfault, which is the problem.
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
void add_lexem(char **lexems, int *lexemsc, int *lexem_n, const char *lexem)
{
if (*lexem_n >= *lexemsc) {
lexems = realloc(lexems, sizeof(char *) * (*lexemsc + 100));
*lexemsc += 100;
}
char *for_adding = malloc(sizeof(char) * strlen(lexem));
strcpy(for_adding, lexem);
lexems[*lexem_n] = for_adding;
(*lexem_n)++;
}
int main(void)
{
char **D = malloc(sizeof(char *) * 2);
int lexemsc = 2;
int lexem_n = 0;
add_lexem(D, &lexemsc, &lexem_n, "MEOW");
printf("%s\n", D[0]);
add_lexem(D, &lexemsc, &lexem_n, "BARK");
printf("%s\n", D[1]);
// in this place lexem_n becomes equal lexemsc
add_lexem(D, &lexemsc, &lexem_n, "KWARK");
printf("%s\n", D[2]);
return 0;
}
The output must be
MEOW
BARK
KWARK
but it is
MEOW
BARK
Segmentation fault (core dumped)
You're passing your lexeme parameter by value, when it should be by address:
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
// removed unused void ccat(char *str, char c)
void add_lexem(char ***lexems, int *lexemsc, int *lexem_n, const char *lexem)
{
if (*lexem_n >= *lexemsc) {
*lexems = realloc(*lexems, sizeof(char *) * (*lexemsc + 100));
*lexemsc += 100;
}
char *for_adding = malloc(sizeof(char) * strlen(lexem)+1);
strcpy(for_adding, lexem);
(*lexems)[*lexem_n] = for_adding;
(*lexem_n)++;
}
int main(void)
{
char **D = malloc(sizeof(char *) * 2);
int lexemsc = 2;
int lexem_n = 0;
add_lexem(&D, &lexemsc, &lexem_n, "MEOW");
printf("%s\n", D[0]);
add_lexem(&D, &lexemsc, &lexem_n, "BARK");
printf("%s\n", D[1]);
// in this place lexem_n becomes equal lexemsc
add_lexem(&D, &lexemsc, &lexem_n, "KWARK");
printf("%s\n", D[2]);
return 0;
}
Output
MEOW
BARK
KWARK
Note: Triple indirection (i.e. a 3-start-programming) is not something to enter into lightly, though it actually fits what you appear to be trying to do here. Read the above code carefully and make sure you understand how it works.
Edit: added terminator space for added string. (don't know why I missed it, since it was what everyone else seemed to be catching on first-review, duh).
Note: See #wildplasser's answer to this question. Honestly it is the best way to do this, as it tightens the relationship between the string pointer array and the magnitude of said-same. If it is possible to retool your code to use that model, you should do so, and in-so-doing select that answer as the the "correct" solution.
Alternative to avoid the three-star-programming: put everything you need inside a struct:
struct wordbag {
size_t size;
size_t used;
char **bag;
};
void add_lexem(struct wordbag *wb, const char *lexem)
{
if (wb->used >= wb->size) {
wb->bag = realloc(wb->bag, (wb->size+100) * sizeof *wb->bag );
wb->size += 100;
}
wb->bag[wb->used++] = strdup(lexem);
}
The main problem is that you are passing D to the function by value: the assignment
lexems = realloc(...);
has no effect on D. In cases when realloc performs reallocation, D becomes a dangling pointer, so dereferencing it becomes undefined behavior.
You need to pass D by pointer in the same way that you pass lexemsc and &lexem_n, so that the realloc's effect would be visible inside the main function as well.
In addition, your add_lexem does not allocate enough memory for the string being copied: strlen does not count the null terminator, so these two lines
char *for_adding = malloc(sizeof(char) * strlen(lexem));
strcpy(for_adding, lexem);
write '\0' one byte past the allocated space.
The problem may come from :
char *for_adding = malloc(sizeof(char) * strlen(lexem));
strcpy(for_adding, lexem);
try char *for_adding = malloc(sizeof(char) * (strlen(lexem)+1)); to leave some space for the '\0 character.
Edit : and #WhozCraig seems to be right !
Bye,
I am trying to solve StringMerge (PP0504B) problem from SPOJ (PL). Basically the problem is to write a function string_merge(char *a, char *b) that returns a pointer to an char array with string created from char arrays with subsequent chars chosen alternately (length of the array is the length of the shorter array provided as an argument).
The program I've created works well with test cases but it fails when I post it to SPOJ's judge. I'm posting my code here, as I believe it the problem is related to memory allocation (I'm still learning this part of C) - could you take a look at my code?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#define T_SIZE 1001
char* string_merge(char *a, char *b);
char* string_merge(char *a, char *b) {
int alen = strlen(a); int blen = strlen(b);
int len = (alen <= blen) ? alen : blen;
int i,j;
char *new_array = malloc (sizeof (char) * (len));
new_array[len] = '\0';
for(j=0,i=0;i<len;i++) {
new_array[j++] = a[i];
new_array[j++] = b[i];
}
return new_array;
}
int main() {
int n,c; scanf("%d", &n);
char word_a[T_SIZE];
char word_b[T_SIZE];
while(n--) {
scanf("%s %s", word_a, word_b);
char *x = string_merge(word_a, word_b);
printf("%s",x);
printf("\n");
memset(word_a, 0, T_SIZE);
memset(word_b, 0, T_SIZE);
memset(x,0,T_SIZE);
}
return 0;
}
Note: I'm compiling it with -std=c99 flag.
Off-by-one.
char *new_array = malloc (sizeof (char) * (len));
new_array[len] = '\0';
You're writing past the bounds of new_array. You must allocate space for len + 1 bytes:
char *new_array = malloc(len + 1);
Also, sizeof(char) is always 1, so spelling it out is superfluous, so are the parenthesis around len.
Woot, further errors!
So then you keep going and increment j twice within each iteration of the for loop. So essentially you end up writing (approximately) twice as many characters as you allocated space for.
Also, you're leaking memory by not free()ing the return value of string_merge() after use.
Furthermore, I don't see what the memsets are for, also I suggest you use fgets() and strtok_r() for getting the two words instead of scanf() (which doesn't do what you think it does).
char *new_array = malloc (sizeof (char) * (len*2 + 1));
new_array[len*2] = '\0';