strcpy when having char pointers in C - c

I have a simple doubt in char arrays. I have a structure:
struct abc {
char *charptr;
int a;
}
void func1()
{
func2("hello");
}
void func (char *name)
{
strcpy(abc.charptr, name); // This is wrong.
}
This strcpy will result in a crash since I do not have any memory allocated to the charptr.
The question is : For mallocing this memory, can we do
abc.charptr = (char *) malloc(strlen(name)); //?
strcpy(abc.charptr, name); // Is this (or strncpy) right ?
Is this right ?

If you were to use malloc() you need to remember to make room for the null-terminator. So use malloc(strlen(name)+1) before calling strcpy().
But in this case you should just use strdup() which does the allocation and copying in one go:
abc.charptr = strdup(name);
The memory returned by strdup() has been allocated with malloc() and hence must be disposed of with a call to free().

It needs to be:
abc.charptr = malloc(strlen(name)+1); ?
strcpy(abc.charptr, name);
The return value of strlen doesn't include space for the null zero '\0' at the end of the string.
You will also have to free your allocated memory at some point.

abc.charptr = (char *) malloc(strlen(name) + 1);
Note the +1, since you need space for the null terminator. Then strcpy() will be fine.

Related

how to free the dynamically allocated memory for a local variable?

Sample program:
#include <stdio.h>
#include <malloc.h>
void f(int n) {
char *val = (char *) malloc(12*sizeof(char));
val = "feels....";
printf("%s", val);
// free val; // if enable, compile time error: expected ';' before 'val' free val;
}
int main()
{
f(1);
return 0;
}
Is it required to free the memory which is dynamically allocated ? if yes, how to.
Yes, you need to free the memory. But when you allocate memory for a string, the way to populate the string is not to assign a string to it as that replaces the memory you've allocated. Instead you're meant to use the function strcpy like this...
char *val = malloc(12*sizeof(char));
strcpy(val,"feels....");
printf("%s", val);
free(val);
Instead of this:
char *val = (char *) malloc(12*sizeof(char));
val = "feels...."; // val points now to the string literal ""feels...."
// discarding the value returned by malloc
...
free(val); // attempt to free the string literal which will
// result in undefined behaviour (most likely a crash)
you probably want this:
char *val = malloc(12*sizeof(char)); // in C you don't cast the return value of malloc
strcpy(val, "feels...."); // the string "feels...." will be copied into
// the allocated buffer
...
free(val); // free memory returned previously by malloc
The compilation problem is because free is a function, you need to put its argument in parentheses.
free(val);
The other problem is a memory leak.
Strings in C are really just pointers to (hopefully) blocks of memory containing char data. The end of the string is denoted by a char with value 0. The thing to remember is that your variable is simply a pointer like any other pointer. So...
char *val = (char *) malloc(12*sizeof(char));
The above line dynamically allocates a block of memory and assigns a pointer to it to val.
val = "feels....";
The above line assigns a pointer to a string literal to val overwriting the previous pointer that was in val. It has not touched, in any way, the block of memory that was malloced in the first line. Furthermore, you have lost any reference you had to the malloced block so it has leaked. There's no way to free it.
String literals are usually created at compile time and the memory they occupy will be part of the program. This means they haven't come from the heap (where malloc gets its memory from. This means, in turn, when you try to free a string literal, bad things happen. On modern architectures, the program text is protected from writes at the OS level so trying to free part of it will almost certainly crash your program.
As long as you do not want to change the content of the string, you do not need to malloc space to it. You can omit the malloc line (and the corresponding free) and your program will still work.
f you do want to change the string, the easiest way to get a mutable copy of a string literal is to use strdup:
char *val = strdup("feels....");
// Do stuff with the string
free(val); // strdup strings need to be freed
strdup is a Posix function but not a C standard function so your platform might not have it. It's pretty simple to implement your own, though.
char* myStrDup(const char* thingToDup)
{
char* ret = malloc(strlen(thingToDup) + 1); // strlen returns the length without the terminating nul. Hence add 1 to it to allocate
strcpy(ret, thingToDup); // Copies the entire string including the terminating nul.
return ret;
}

C - create a string "from" struct parameter

Have a
typedef struct person {
char name[20]
char surname[20]
} person_t;
I need to create a string like XXXXXX:YYYYYY with the function like
char* personToString(person_t *p). I tried to make it:
char* personToString(person_t* p) {
int n1,n2;
n1=strlen(p->name);
n2=strlen(p->surname);
char *p = (char*) malloc((n1+n2+2)*sizeof(char));
strcat(p,puser->name);
strcat(p,":");
strcat(p,puser->surname);
return p;
}
This give me a reasonable output but I have some errors testing with valgrind! I also think that there is a way more classy to write the function!
When you malloc memory for p the memory will hold garbage values. Strcat will append a string after the null character, but in an uninitialized string will hold random values.
Replace the first strcat with strcpy.
You need to
strcpy(p,puser->name);
not
strcat(p,puser->name);
malloc does not initialize the buffer to zero, so strcat is searching for a null byte in p first and probably not finding one, reading past the end of the buffer and thus crashing.
Instead of one strcpy plus two strcat you can also write one call to sprintf:
sprintf(p, "%s:%s", puser->name, puser->surname);
First you should call string copy, then strcat:
strcat(p,puser->name);
should be:
strcpy(p,puser->name);
because memory allocated with malloc function keeps values garbage, by doing strcat for first you are concatenating after garbage -- it also brings Undefined behaviour in your code.
You can use void* calloc (size_t num, size_t size); instead of malloc(), calloc function initialized allocated memory with 0 (then strcat() no problem).
Also dynamically allocated memory you should deallocate memory block using void free (void* ptr);) explicitly.
This looks good to me,
char* personToString( struct person_t *p )
{
int len = strlen(p->name) + strlen(p->surname) + 2; // holds ':' + NULL
char *str = malloc( len ); // Never cast malloc's return value in C
// Check str for NULL
if( str == NULL )
{
// we are out of memory
// handle errors
return NULL;
}
snprintf( str, len, "%s:%s", p->name, p->surname);
return str;
}
NOTE:
Never cast malloc's return value in C.
Use snprintf when multiple strcat is needed, its elegant.
free the return value str here in caller.
Fixed struct and char variables.

C Allocating memory for array of structures containing multiple char*

I have problem allocating memory for array of structure containing char*.
I have one stracture "Person"
typedef struct
{
char *name;
char *surname;
char *phonenumber;
} Person;
What I want to do is to read some data from file and fill the array (Person *array) of people where I have to dynamically allocate memory.
At the moment, I have something like that:
array = malloc(sizeof(Person) * arraysize);
Person *buff;
char text[100];
char *result;
for(i=0; i<arraysize; i++)
{
buff = &array[i];
fgets(text, 100, f );
//Read first name
result = strtok(text,":");
buff->name= malloc(strlen(result));
buff->name= result;
//Read surname
result = strtok(0,":");
buff->surname = malloc(strlen(result));
buff->surname = result;
//Read phone number
result = strtok(0, ":");
buff->phonenumber = malloc(strlen(result));
buff->phonenumber = result;
}
When I print out the whole array I don't get any valid data. I'm wondering what am I doing wrong. I appreicate for your answers in advance!
The problem is:
result = strtok(text,":");
buff->name= malloc(strlen(result));
buff->name= result;
You need to use strcpy for copying and also the length of the malloced string should be one more than the string length to accommodate the NUL char.
buff->name= malloc(strlen(result) + 1);
This:
buff->name= malloc(strlen(result));
buff->name= result;
is broken. You can't assign "strings" like that in C, you need to copy characters. The pointer returned by malloc() is overwritten by result, leaking memory. Also, you need to include space for the terminator.
So, this should be:
buff->name= malloc(strlen(result) + 1);
strcpy(buff->name, result);
buff->name= result
resets the pointer buff->name to point to the same location in memory as result. If you want to copy in the string contents of result, use strcpy:
strcpy(buff->name, result);
But note that you have to reserve space for the trailing NUL character as well in the call to malloc:
buff->name = malloc(strlen(result) + 1);
If you're on a POSIX system (Linux, Mac OS X, any Unix) you can replace malloc, strlen and strcpy with the much more convenient strdup:
buff->name = strdup(result);
strtok overwrite the pointer everytime. So you lose the pointer to data as the iteration goes.
You can do something like this, if you wish to directly assign the pointer:
result = strtok(text,":");
buff->name= strdup(result);
strdup is POSIX function. So if it's not available you can easily implement it.
you need to copy the text in result in the newly allocated memory block.
now you just allocate memory (assign the pointer to the pointer), then you discard that pointer and assign a new pointer result to it.
you need to strncpy the result to the new memory allocation.
Also strlen does not include the terminating zero byte, so you do not have enough space in the new memory block.
There is a function strdup which does what you want.

char * as a reference in C

How to pass the param like char * as a reference?
My function uses malloc()
void set(char *buf)
{
buf = malloc(4*sizeof(char));
buf = "test";
}
char *str;
set(str);
puts(str);
You pass the address of the pointer:
void set(char **buf)
{
*buf = malloc(5*sizeof(char));
// 1. don't assign the other string, copy it to the pointer, to avoid memory leaks, using string literal etc.
// 2. you need to allocate a byte for the null terminator as well
strcpy(*buf, "test");
}
char *str;
set(&str);
puts(str);
You have to pass it as a pointer to the pointer:
void set(char **buf)
{
*buf = malloc(5 * sizeof(char));
strcpy(*buf, "test");
}
Call it like this:
char *str;
set(&str);
puts(str);
free(str);
Note that I have changed the malloc call to allocate five characters, that's because you only allocate for the actual characters, but a string also contains a special terminator character and you need space for that as well.
I also use strcpy to copy the string to the allocated memory. That is because you are overwriting the pointer otherwise, meaning you loose the pointer you allocate and will have a memory leak.
You should also remember to free the pointer when you are done with it, or the memory will stay allocated until the program ends.
C does not support pass by reference. But you can pass a pointer to your pointer, and set that:
void set(char **buf)
{
*buf = malloc(5*sizeof(char)); //5, to make room for the 0 terminator
strcpy(*buf,"test"); //copy the string into the allocated buffer.
}
char *str;
set(&str);
puts(str);
You to pass a pointer to a pointer, char**: there are no references in C.
void set(char** buf)
{
*buf = malloc(5); /* 5, not 4: one for null terminator. */
strcpy(buf, "test");
}
Note that:
buf = "test";
does not copy "test" into buf, but points buf to the address of the string literal "test". To copy use strcpy().
Remember to free() returned buffer when no longer required:
char* str;
set(&str);
puts(str);
free(str);
C is pass-by-value. There is no pass-by-reference.
In the example given above by hmjd, it should be:
strcpy(*buf, "test");
C cannot not pass function arguments by reference, C always passes them by value.
From Kernighan & Ritchie:
(K&R 2nd, 1.8 Call by value) "In C all function arguments are passed by "value""
To modify a pointer to T, you can have a pointer to pointer to T as the function argument type.

Passing strings by value in C

I have two functions, one that creates a pointer to a string and another that manipulates it. I somehow am missing something critical, however:
int foo() {
char * mystring; // Create pointer
bar(&mystring); // Pass in address
printf("%s\n", mystring);
return 0; // There's a reason for this
}
int bar(char ** mystring) {
mystring[0] = malloc(strlen(mystring) + 1); // Since malloc will persist even after exiting bar
*mystring = "hahaha"; // Dereference
return 0;
}
Any enlightenment for my addled brain would be greatly appreciated!
C doesn't have strings as first class values; you need to use strcpy() to assign strings.
strcpy(mystring[0], "hahaha");
In addition to the other answers given, note that:
mystring[0]
is the same as
*(mystring + 0)
which is the same as
*mystring
Your malloc allocates the memory and the pointer is written to mystring but it is overwritten by the next line.
The use of malloc is necessary, but this way:
mystring[0] = malloc(strlen(mystring) + 1);
is wrong, since you can't perform strlen on mystring(because it doesn't contain any string yet and because the pointer itself is not initialized). Allocate buffer with the size of your string. for example:
int bar(char ** mystring) {
char* hello = "hahaha";
*mystring = malloc(strlen(hello) + 1);
strcpy(*mystring, hello);
return 0;
}
BTW, you could use the assignment *mystring = "hahaha"; without the malloc since this is a string stored in the data section, and the data will not be lost after returning from the function, but this way it is read-only data and you cannot modify it. The strcpy is there to copy the string to the allocated buffer.

Resources