i have this code in C:
char* func(char* str, int a) {
str = malloc(a * sizeof(char));
return str;
}
int main() {
char* s1 = NULL;
s1 = func(s1,4);
s1 = "123";
free(s1);
s1 = func(s1, 5);
s1 = "1234";
free(s1);
...
}
i keep getting run time error(as if it were an infinte loop)
is this using of s1 in main() legal?
would it produce memory leakage?
s1 = "123"; here you make s1 to point to a string literal and you should never call free for a string literal. My guess is that you meant to copy these characters to the memory allocated for s1. If that is the case, make use of strcpy. For instance:
char* func(char* str, int a) {
str = malloc(a * sizeof(char));
return str;
}
int main() {
char* s1 = NULL;
s1 = func(s1,4);
strcpy(s1, "123");
free(s1);
s1 = func(s1, 5);
strcpy(s1, "1234");
free(s1);
...
}
As for your second question - you have a memory leak in your code but precisely because of the reason I already mentioned - s1 = "123"; does not copy the bytes but points s1 at the literal. The code I suggest should be safe of memory leaks.
You are freeing a string literal, and you loose the address s1 points to when you do s1 = "123"; and now you can never free it.
is this using of s1 in main() legal? would it produce memory leakage? \
it will compile but it is not an issue of ilegal use but incorrect use, and yes it is an evident memory leak.
Related
I am trying to implement the strcat function by myself, using pointers.
My pseudo-code is:
receive 2 char pointers (which means 2 strings (= 2 char arrays)).
create a copy of the dest array
realloc() space of dest to be the sum of the sizes of source string + dest string, because I need the dest string to include in the end both of the strings.
create a pointer that points to the first index of the dest string, this pointer will be returned as the function's return value.
run 2 simple while loops on both source and copy of dest strings, and while doing this, copy all contents to the dest
free all allocated pointers
return the address that points to the first index of the dest string by return the created pointer that was created for this exact purpose.
So. I wrote this:
char *StrCat(char *dest, const char *src)
{
size_t size = strlen(dest) + strlen(src) + 1;
char *temp = (char *) malloc(strlen(dest) + 1);
char *start = dest;
dest = (char *) realloc(dest, size);
strcpy(temp,dest);
while (*src)
{
*dest = *src;
src++;
dest++;
}
while (*temp)
{
*dest = *temp;
temp++;
dest++;
}
*dest = '\0';
free(temp);
return start;
}
void strcatTest()
{
char source[] = "this is source of cat";
char dest4[100] = "this is dest of cat";
StrCat(dest4,source);
puts(dest4);
}
and I'm getting:
realloc(): invalid pointer.
I know there are a lot of working and better implementations of strcat around the internet and on stackoverflow, but my purpose here is to understand what did I do wrong and why I failed to create a working implementation.
What went wrong with my understanding of starcat()?
Beware, you can only use realloc on a pointer that has previously been alloc-ed, and not on a pointer to an automatic or static storage array.
So those lines are enough to cause the error:
char *StrCat(char *dest, const char *src)
{
...
dest = (char *) realloc(dest, size);
...
char dest4[100] = "this is dest of cat";
StrCat(dest4,source);
This is the reason why the standard library does not try to reallocate...
From the C Standard (7.23.3.1 The strcat function)
2 The strcat function appends a copy of the string pointed to by s2
(including the terminating null character) to the end of the string
pointed to by s1. The initial character of s2 overwrites the null
character at the end of s1. If copying takes place between objects
that overlap, the behavior is undefined.
So within the standard C string function strcat neither allocation or reallocation memory is present. The destination character array shall be initially large enough to accommodate within itself one more string.
Take into account that you need to rename your function. Otherwise there will be a conflict between your function and the standard function.
The function definition can look the following way (without using any standard string function)
char * new_strcat( char *s1, const char *s2 )
{
char *p = s1;
while ( *p ) ++p;
while ( ( *p++ = *s2++ ) );
return s1;
}
Here is a demonstrative program.
#include <stdio.h>
char * new_strcat( char *s1, const char *s2 )
{
char *p = s1;
while ( *p ) ++p;
while ( ( *p++ = *s2++ ) );
return s1;
}
int main(void)
{
char s1[14] = "Hello ";
const char *s2 = "World!";
puts ( new_strcat( s1, s2 ) );
return 0;
}
The program output is
Hello World!
If you want to write a new function that combines two strings creating a new character array (such a function is a different function compared with the standard string function strcat) then the function can be declared and defined the following way (in this implementation there is used the standard string function strlen though it can be written without using the function).
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char * combine( const char *s1, const char *s2 )
{
char *result = malloc( strlen( s1 ) + strlen( s2 ) + 1 );
if ( result )
{
char *p = result;
while ( *s1 ) *p++ = *s1++;
while ( ( *p++ = *s2++ ) );
}
return result;
}
int main(void)
{
const char *s1 = "Hello ";
const char *s2 = "World!";
char *p = combine( s1, s2 );
if ( p ) puts( p );
free( p );
return 0;
}
Again the program output is
Hello World!
As for your function then it is incorrect and does not make any sense. For example the user can pass to the function a character array with automatic storage duration. You may not reallocate it dynamically using realloc.
Or you at first assign the pointer start with the value of the pointer dest but then the memory pointed to by the pointer dest was reallocated. As a result the pointer start has an invalid value that is returned from the function.
char *start = dest;
dest = (char *) realloc(dest, size);
//...
return start;
Also you are trying to copy strings in the reverse order relative to each other, At first you are copying the string pointed to by the pointer src and then the string that initially was pointed to by the pointer dest. S0 you are not appending the second string to the tail of the first string.
Pay attention to your function declaration
char *StrCat(char *dest, const char *src);
The first parameter without the qualifier const means that the string pointed to by the pointer dest will be changed in place. So even the function declaration contradicts your function implementation because you are not changing the destination character array in place. You are trying to create a new character array.
So I have this code in which allocation is happening in one function and deallocation is being done in the calling function. Getting Segmentation fault or Abort message while trying to free the memory either by ptr or *ptr. Kindly have a look:
#include <stdio.h>
int main()
{
char *ptr;
fun(&ptr);
printf("ptr = %p\n",ptr);
printf("&ptr = %p\n",&ptr);
printf("String ptr = %s\n",ptr);
free (ptr);
return 0;
}
void fun(char **str)
{
*str = malloc(10);
*str = "HELLO";
printf("str = %p\n",str);
printf("&str = %p\n",&str);
printf("String str = %s\n",*str);
}
Following is the output:
str = 0x7ffe63247858
&str = 0x7ffe63247838
String str = HELLO
ptr = 0x400764
&ptr = 0x7ffe63247858
String ptr = HELLO
*** Error in `/home/a.out': munmap_chunk(): invalid pointer: 0x0000000000400764 ***
Aborted
Question :
Why can't we free ptr ? And if we can, what is the best way to do it ?
you're overwriting the pointer value in the line after, making *str point to a literal.
So you have a memory leak and undefined behaviour by trying to free a literal.
You probably mean
strcpy(*str,"hello");
Note that those 2 lines could be changed into a working single line like this:
*str = strdup("HELLO");
which has the advantage of allocating the exact number of bytes for the string instead of guessing.
When you do *str = "HELLO"; it does not have the effect you expect. Instead of assigning value to the allocated memory, you are re-assigning the pointer to point to the string literal and thus later you try to deallocate it (thus the error). Instead of this you should use strcpy like strcpy(*str, "HELLO").
To answer the question of how to do this without explicit string copying, instead of
char *p = "hello";
do
char p[] = "hello";
The first points p to a non-modifiable portion of memory. The second allocates an array large enough to hold the literal and copies the literal into it.
you are changing memory address pointed str pointer after malloc in fun. you should do strcpy instead of direct assignment :
#include <stdio.h>
int main()
{
char *ptr;
fun(&ptr);
printf("ptr = %p\n",ptr);
printf("&ptr = %p\n",&ptr);
printf("String ptr = %s\n",ptr);
free (ptr);
return 0;
}
void fun(char **str)
{
*str = malloc(10);
strcpy(*str,"HELLO");//*str = "HELLO";
printf("str = %p\n",str);
printf("&str = %p\n",&str);
printf("String str = %s\n",*str);
}
I'm fairly new to C and I'm a little confused as to the correct way to initialise struct variables which are pointers, within a function. Is this style sufficient, or do I need to allocate memory before I assign s->str?
Thank you kindly for your replies, apologies if the question is unclear as I am very new to this language.
typedef struct Mystruct{
const char* str1;
const char* str2;
}mystruct;
mystruct* mystruct_new(const char* str1, const char* str2){
mystruct *s = (mystruct*)(malloc(sizeof(mystruct)));
s->str1 = str1;
s->str2 = str2;
return s;
}
your function is legal and doesn't do anything bad. Nevertheless, you should document it to mention that the strings are not copied, only the pointers are.
So if the passed data has a shorter life than the structure itself, you may meet undefined behaviour. Example:
mystruct*func()
{
char a[]="foo";
char b[]="bar";
return mystruct_new(a,b);
}
mystruct*func2()
{
char *a="foo";
char *b="bar";
return mystruct_new(a,b);
}
int main()
{
mystruct *s = func();
printf(s->a); // wrong, memory could be trashed
mystruct *s2 = func2();
printf(s2->a); // correct
mystruct *s3 = mystruct_new("foo","bar");
printf(s3->a); // also correct, string literals have global scope
}
the above code is undefined behaviour for the first print because s->a points to some memory that is no longer allocated (local to func).
The second print is OK because s2->a points to a string literal which has infinite life span.
So maybe your function is more useful like this:
mystruct* mystruct_new(const char* str1, const char* str2){
mystruct *s = malloc(sizeof(mystruct));
s->str1 = strdup(str1);
s->str2 = strdup(str2);
return s;
}
now the memory is allocated for the strings. Don't forget to free it when discarding the structure, better done in another utility function.
If the strings being passed in to str and str2 will always be string constants than yes you can get away with doing it this way. My guess however is that this is not the case. So you would be better off making a copy of each string with strdup and assigning those to the struct members:
mystruct* mystruct_new(const char* str1, const char* str2){
mystruct *s = malloc(sizeof(mystruct));
s->str1 = strdup(str1);
s->str2 = strdup(str2);
return s;
}
Just make sure to free each of those fields before freeing the struct.
Think of it this way: when you allocate memory for the struct, you get the pointer member variables for free. So in essence, when you do this:
mystruct *s = malloc(sizeof(mystruct)); //don't cast result of malloc.
Then you can treat s->str1 in the exact same way as you would any regular char* variable, say
char *str1 = NULL;
If you want it to point to something, then you have to allocate memory for the pointers. Consider this:
mystruct* mystruct_new(const char* str1, const char* str2){
mystruct *s = malloc(sizeof(mystruct);
char* someString = getMyString(); //gets some arbitrary string
char* str1 = NULL;//just for demonstration
int length = strlen(someString) + 1;
//for struct members
s->str1 = malloc(sizeof(char) * length);
strcpy(s->str1, someString);
//For regular pointers
str1 = malloc(sizeof(char) * length);
strcpy(str1, someString);
return s;
}
Also note that if you just assign to a pointer by using the = operator instead of allocating memory, then it will only copy the address to the original value. This may or may not be what you want depending on the context. Generally, if you know the memory location will stay in scope and you don't need (or don't mind) to change the original string, then it is preferred to simply assign it. Otherwise, it is advisable to make a copy.
//Makes a copy of the string
s->str1 = malloc(sizeof(char) * length);
strcpy(s->str1, someString);
//copies the address of the original value only!
s->str1 = someString;
Use strncpy() instead of strcpy(). The latter is subject to buffer overruns.
For example in this code snippet given by another user, use the strncpy() in place of strcpy()
mystruct* mystruct_new(const char* str1, const char* str2){
mystruct *s = malloc(sizeof(mystruct);
char* someString = getMyString(); //gets some arbitrary string
char* str1 = NULL;//just for demonstration
int length = strlen(someString) + 1;
//for struct members
s->str1 = malloc(sizeof(char) * length);
strcpy(s->str1, someString);
//For regular pointers
str1 = malloc(sizeof(char) * length);
strcpy(str1, someString); // replace with strncpy(str1, someString, bufsize); where bufsize is the maximum number of characters in your string + 1 for the terminator '\0'.
return s;
}
I have the following program:
#include <stdio.h>
#define MAXLEN 100
char *my_strcat(char *strp1,char *strp2) {
char str[MAXLEN], *strp;
strp = str;
while (*strp1 != '\0') {
*strp++ = *strp1++;
}
while (*strp2 != '\0') {
*strp++ = *strp2++;
}
*strp = '\0';
strp = str;
return strp;
}
void test_strcat(void) {
char *strp1, *strp2, *strp3, str1[MAXLEN], str2[MAXLEN];
printf("Testing strcat! Give two strings:\n");
gets_s(str1, sizeof(str1));
gets_s(str2, sizeof(str2));
strp1 = str1;
strp2 = str2;
strp3 = my_strcat(strp1, strp2);
printf("Concatenated string: %s", strp3);
}
int main(void) {
test_strcat();
}
The function char *mystrcat is supposed to concatenate two strings, and I test it with
test_strcat. The program runs without errors but instead of printing the concatenated string a smiley symbol is printed. I have gone through the program with debugging and it
appears that the result sent back by my_strcat is the correct string. However, when
going into the last line where strp3 is supposed to be printed it appears red in the
debugging tool, implying that its value is about to change. After the printf call, strp3
no longer points to the concatenated string. Anyone knows what could be causing this error?
Here is the problem:
char str[MAXLEN], *strp;
strp = str; // str is a local variable
...
return strp; // <<== WRONG!!!
Since str is a local variable that disappears as soon as you return, the value pointed to by strp becomes invalid the instance the caller gets the control back.
Use malloc instead of allocating memory in the automatic storage area (i.e. on the stack) will fix this problem:
char *str = malloc(strlen(strp1)+strlen(strp2)+1);
char *strp = str;
I suggest you 2 ways as following.
first,
char *my_strcat(char *strp1,char *strp2) {
static char str[MAXLEN * 2]; /* from char str[MAXLEN] */
second,
char *my_strcat(char *strp1,char *strp2) {
char *str = malloc(strlen(strp1) + strlen(strp2) + 1);
because in my_strcat function, you allocated the str as auto variable.
When my_strcat function is finish, str will be freed.
I'm trying to self-study C using C Primer Plus from Stephen Prata and one of the end-of-chapter exercises is to "Write a function that replaces the contents of a string with the string reversed.". This is a chapter on character strings with a good dose of pointers. I'm trying to use pointers as much as possible so I can better understand, but I'm stuck.
My problem is that when I print the value of the return pointer in main, it is garbled.
When I use gdb(just learning how to use that too), I can see that the memory address returned from my function is the same address that was used in the function and it's getting assigned to my pointer in main okay as far as I can tell.
I've tried so many things, what am I missing? FWIW I have not learned about malloc yet in the book, though I see it referenced on various www pages I've frequented trying to better understand C.
$ cc -o exercise8 exercise8.c && ./exercise8
This is s1 before: abcd
This is s2 in function: dcba
This is s3 after: d`!
/* A function that replaces the contents of a string with the string reversed. */
#include <stdio.h>
#include <string.h>
char *str_rev(char * string);
int main(void)
{
char * s1 = "abcd";
char * s3;
printf("This is s1 before: %s\n", s1);
s3 = str_rev(s1);
printf("This is s3 after: %s\n", s3);
}
char *str_rev(char * string)
{
char ar3[5];
char * s2;
int len = 0;
s2 = ar3;
len = (strlen(string) - 1);
string = string + len;
while ( len >= 0 )
{
*s2 = *string;
len--;
string--;
s2++;
}
s2++;
*s2 = 0;
s2 = s2 - 5;
printf("This is s2 in function: %s\n", s2);
return s2;
}
$ gdb exercise8
GNU gdb (GDB) 7.1-ubuntu
Reading symbols from exercise8...done.
(gdb) break 12
Breakpoint 1 at 0x804844a: file exercise8.c, line 12.
(gdb) break 40
Breakpoint 2 at 0x80484d9: file exercise8.c, line 40.
(gdb) run
Starting program: exercise8
This is s1 before: abcd // My original string.
This is s2 in function: dcba // Good, my reversed string while in the function.
Breakpoint 2, str_rev (string=0xbffff043 "dcba") at exercise8.c:40
40 return s2;
(gdb) print s2
$1 = 0xbffff043 "dcba" // Location of pointer s2.
(gdb) continue
Continuing.
Breakpoint 1, main () at exercise8.c:12
12 printf("This is s3 after: %s\n", s3);
(gdb) print s3
$2 = 0xbffff043 "dcba" // Back in main same pointer as s2 from function.
(gdb) step
This is s3 after: d`Q // Line 12 executed. Output garbled.
14 }
(gdb)
You're returning a pointer to a local variable, (automatic variable to speak in ISO standard terms,) which is allocated on the stack, as soon as you return from your function that memory is released leaving you with a dangling pointer pointing to memory that may or may not still contain the string you put there, it depends entirely on circumstances. You should provide the output buffer as a function argument, or allocate it with malloc, or in C++ with new.
edit; added some example code
void reverse(const char* s1, char* s2) {
const int l = strlen(s1);
const char* p = s1 + l - 1;
do {
*s2++ = *p;
} while (p-- != s1);
*s2 = 0;
}
int main() {
// some code here
char s1[5] = "abcd";
char s2[5] = "";
reverse(s1, s2);
// some more code here
return 0;
}
or
char* reverse(const char* s) {
const int l = strlen(s);
char* rs = malloc(l+1);
const char* p = s + l - 1;
do {
*rs++ = *p;
} while (p-- != s);
*rs = 0;
return rs - l;
}
int main() {
// some code here
char s1[5] = "abcd";
char* s2 = reverse(s1);
// some more code here
free(s2);
return 0;
}
char ar3[5];
char * s2 = ar3;
The above code will make s2 points to a character string on the stack. This ar3 variable will be deleted once your function finishes.
You should output to some variable that you have pre-allocated. Modify it as follow
int main(void)
{
char * s1 = "abcd";
char s3[5];
printf("This is s1 before: %s\n", s1);
str_rev(s1, s3);
printf("This is s3 after: %s\n", s3);
}
void str_rev(char * string, char * s2)
{
........
// don't return
// Also assign the last character with the NULL terminator
ar2[strlen(string)] = '\0';
}
Of course, once you get to the chapter regarding malloc, you can allocate the necessary memory for s3 depending on the length of s1. Until then, read on and have fun.
The problem description sounds like you can just reverse the string in place. Keep it simple.
void reverse_range(char *first, char *last) // [first, last)
{
for (; first != last && first != --last; ++first)
{
char temp = *first; *first = *last; *last = temp;
}
}
void reverse(char *str)
{
reverse_range(str, str + strlen(str));
}
int main()
{
char text[] = "0123456789";
printf("before: %s\n", text);
reverse(text);
printf("after : %s\n", text);
}
s2 points to your local ar3 array. Therefore when str_rev returns, it is no longer valid to look at the memory where ar3 was via s2. Now s2 is called a dangling pointer, and this is one of the huge pains in learning to use C pointers correctly.
For a simple solution that doesn't use malloc and meets the exercise requirement of "replaces the contents of a string", try copying the result into the function argument pointer (the original string; but be careful since your current code has since changed the pointer string). You know this pointer points at memory with enough characters and isn't local to your function.
Part of the problem is that you can't actually "replace the contents of a string with the string reversed" when you are dealing with string literals, ie. strings delcared in the form char * s1 = "abcd";
Without using literals, I made a relatively easy to understand recursive example:
/* A function that replaces the contents of a string with the string reversed. */
#include <stdio.h>
#include <string.h>
void str_rev(char * string);
int main(void)
{
char s1[] = "abc";
char s2[] = "even";
char s3[] = "quodd";
printf("This is s1 before: %s\n", s1);
str_rev(s1);
printf("This is s1 after: %s\n", s1);
printf("This is s2 before: %s\n", s2);
str_rev(s2);
printf("This is s2 after: %s\n", s2);
printf("This is s3 before: %s\n", s3);
str_rev(s3);
printf("This is s3 after: %s\n", s3);
return 0;
}
void str_rev(char * string) {
//Store the first char of the string locally
char firstChar = string[0];
//Store the last char of the string locally
int lastCharPos = strlen(string)-1;
char lastChar = string[lastCharPos];
//Shorten the string (temporarily)
string[lastCharPos] = '\0';
if (string[1] != '\0') {
//Call on the now shortened string, eg.
//"abc" becomes "b"
//"even" becomes "ve"
//"quodd" becomes "uod"
str_rev(string+1);
}
//Swap the first and last characters
string[0] = lastChar;
string[lastCharPos] = firstChar;
}
On my system the output is as follows:
This is s1 before: abc
This is s1 after: cba
This is s2 before: even
This is s2 after: neve
This is s3 before: quodd
This is s3 after: ddouq
#include <stdio.h>
#include <string.h>
void my_strrev(char* begin){
char temp;
char* end;
end = begin + strlen(begin)-1;
while(end>begin){
temp = *end;
*end = *begin;
*begin = temp;
end--;
begin++;
}
}
main(){
char string[]= "foobar";
my_strrev(string);
printf("%s", string);
}