Allocating memory to a struct member pointer in C - c

I have a structure with a member that I need to pass to a function by reference. In that function, I'd like to allocate memory & assign a value. I'm having issues somewhere along the line - it seems that after the code returns from allocateMemory, the memory that I had allocated & the values that I assigned go out of scope (this may not be exactly what is happening, but it appears to be the case).
#include <stdio.h>
#include <stdlib.h>
typedef struct myStruct_t
{
char *myString;
} myStruct;
void allocateMemory(void *str);
int main(void) {
myStruct tmp = {
.myString = NULL
};
myStruct *p = &tmp;
allocateMemory(p->myString);
//allocateMemory(&(p->myString)); //also tried this
printf("%s", p->myString);
return 0;
}
void allocateMemory(void *str)
{
str = malloc(8);
((char *)str)[0] = 'a';
((char *)str)[1] = 0;
}
If I print the value of str inside of allocateMemory, the 'a' is successfully printed, but if I attempt to print p->myString in main, my string is empty.
Can anyone tell me what I'm doing wrong?

You need to pass address of the structure member and then you can change (aka allocate memory) to it. In your version of the function, you are not taking a pointer not reference of a pointer, so you can change the content of memory referenced by the pointer but not the pointer itself.
So change your function to
void allocateMemory(char **ret_str)
{
char *str = malloc(8);
str[0] = 'a';
str[1] = 0;
*ret_str = str;
}
And then call it as
allocateMemory(&p->myString)

An alternative way of writing the same function Rohan did, eliminating the need to define any new variables:
void allocateMemory(char **str, size_t size) {
*str = malloc(size);
(*str)[0] = 'a';
(*str)[1] = '\0';
}
Note that I pass a size parameter to justify using malloc() in the first place.

Related

How to return pointer to array in c

I call the function getdata() below inside main(). getdata() reads in characters from the uart and puts them in an array. At the end of the function it writes out the array over uart.
My question is, how can I get this function to return the data? I understand that you cannot return arrays in c and that you should declare a function returning a pointer.
How could I do that with the function below so that I can write out the data in main instead of having to do it inside getdata().
int main(void)
{
getdata();
}
void getdata(void)
{
static uint8_t ndx;
char recChars[6];
char retchar;
ndx = 0;
retchar = getch();
recChars[ndx] = retchar;
ndx++;
if (retchar == '\r'){
recChars[ndx] = '\n';
ndx = 0;
uart_write(UART_D, (uint8_t *)recChars, sizeof(recChars));
}
}
char getch(void) {
uint8_t ch = 0;
chuart_read(UART_D, &ch);
return ((char) ch);
}
You need to make recChars a pointer and allocate dynamic memory to it using malloc() or family. Then, you can return the pointer to the caller and make use of it in the caller.
Something like
char * getdata() //change return type
{
static uint8_t ndx;
char * recChars = NULL; // change to pointer
char retchar;
ndx = 0;
if ( (recChars = malloc(6)) == NULL ) return NULL;
retchar = getch();
recChars[ndx] = retchar;
ndx++;
if (retchar == '\r'){
recChars[ndx] = '\n';
ndx = 0;
//uart_write(UART_D, (uint8_t *)recChars, sizeof(recChars));
}
return recChars; //finally return
}
Remember, the returned pointer needs to be free()-d in the caller, after the usage is over to avoid memory leak.
You have to write a function that returns a pointer to char and use malloc to allocate memory. You must use malloc because arrays declared like this
char v[11];
belong to the automatic storage class which means that they have block scope,they get deleted as soon as your function returns and they are not initialized by default. Dynamic memory instead can be accessed anywhere in your program if you have a pointer to that memory block. You have also remember to free the memory using free() to avoid memory leak. If you returned a pointer to an automatic array,you'd probably get a SIGSEGV because your pointer is holding a memory location that doesn't exist anymore. So you could write something like this:
char *foo(void)
{
char *p = malloc(sizeof(type) * n);
return p;
}
In main
int main(void)
{
char *pointer = foo();
/*Do something*/
free(pointer);
return EXIT_SUCCESS;
}
PS: I apologize for my english
You can write a function that returns a char * and use malloc to create some storage for this table, as mentioned above, or you can simply declare your array as static and return it.
More explicitly:
char *getdata(void) {
static char retChar[6];
...
return retChar;
}
Works. The reason for this is that the array storage is reserved in a special segment.
A version with malloc reserves the storage for your array in the heap, which requires you to free it afterwards:
char *getdata(void) {
char *retChar = (char *) malloc(6);
...
return retChar;
}
main() {
char * ptr = getdata();
...
free(ptr);
}
Finally the only thing you can't do is to declare the array and return it as is, with no static declaration and no malloc... The reason for this is that your
array is allocated in the call-stack and so is potentially lost when you return
from getdata.
In other words, never ever do:
char *getdata(void) {
char retChar[6];
...
return retChar;
}
I would advice you to declare an array in the main() function itself pass the arrray as reference to getdata function, so whenever getdata() gets updated that will be reflected in the array in main().
Note: By the way why are you using sizeof(recChars), which will give 6, but you're only updating upto 2 location. I've incorporated this also in the code
int main(void)
{
char recChars[6];
int Rxd_Len = 0;
Rxd_Len = getdata(&recChars); //Pass the address of array
uart_write(UART_D, (uint8_t *)recChars, Rxd_Len );
}
int getdata(char *ptr_recChars)
{
uint8_t ndx; // removed static since its not a required/mandatory
char retchar;
ndx = 0;
retchar = getch();
*(ptr_recChars + ndx) = retchar; //Asign the value to the array address + offset
if (retchar == '\r'){
ndx++;
*(ptr_recChars + ndx) = '\n';
}
return ndx;
}
char getch(void) {
uint8_t ch = 0;
int ret;
ret = uart_read(UART_D, &ch);
return ((char) ch);
}
UPDATE:
Is it ok to call uart_write() in main() ?
Yes you can do that, but since the uart_write() will be using the length to transfer you need to keep track of it using another variable.
Also, why is this line necessary? What does it do*(ptr_recChars + ndx) = retchar;?
ptr_recChars is a pointer which points to the array recChars[6], so using this pointer we can update the array recChars[6] even though it is declared in main(), *(ptr_recChars + ndx) , here ndx is 0 so the first element of array is updated, then after that you increment ndx then, using the pointer variable we can point to the new updated location by *(ptr_recChars + ndx) (since ndx is new value now)
Also, I should the & operator in getdata(&recChars);
No, the array name itself is a pointer so for recChars[6] simplay giving recChars alone will give the base address of the array, also note recChars and &recChars[0] means same. So if you give &recChars it means recChars is a address then adding &recChars assumes the address of a address which will give you an invalid value in your expression.

If I use a while loop to iterate through the contents of a pointer to an array, how do I return back to the first element in the array?

Say for example I have a function called from main that returns a pointer:
EDIT
: I was a little unclear, sorry! Let's say I used a scanf in the main() and then I passed this into the function, and I wanted to copy the argument into a new pointer then return that one.
main(void)
{
char *word = malloc(50);
scanf("%s", word);
printf("%s", function(word));
}
char *function(char *array)
{
char *a = malloc(50);
while (*array)
{
*a = *array;
a++;
array++;
}
return a;
}
In this case, if I tried to return the pointer array to main, the pointer would be pointing to the memory location 1 space past where my values are held.
How would I make so I can return the pointer to the first value again?
Thanks!
The best way is to not increment your pointers at all:
char *function(char *array)
{
const size_t maxLength = 49;
char * a = malloc(maxLength + 1);
if ( !a ) {
perror("couldn't allocate memory");
exit(EXIT_FAILURE);
}
size_t i;
for ( i = 0; array[i] && i < maxLength; ++i ) {
a[i] = array[i];
}
a[i] = '\0';
return a;
}
Your original code does not null-terminate a, yet you pass it to printf() as if it's a string. Also, you're leaking memory, since you don't store the pointer you're returning, so you can never free() it.
The basic approach is to use a temporary variable to hold the pointer value you want to keep.
Assuming the only one you care about in your example is a.
char *function(char *array)
{
char *a, *t;
t = a = malloc(50);
while (*array)
{
*t = *array;
++t;
++array;
}
*t = '\0'; /* since the caller passes returned pointer to printf() */
return a; /* a unchanged, so return it */
}
Note that the above will have undefined behaviour if strlen(array) >= 50.
In your example, array is passed by value, so changes to it (repeated incrementing) do not propagate to the caller - there is no need to reset array back to its original value.
The best way would be to not use the parameter to the function, but a copy of it inside the function.
char* pTmp = array;
Also it's better to do ++pTmp rather than array++ because for non-POD types it can be quicker.

Assigning returned cstring to variable

I'm writing a function that reverses a cstring not in place but returns the reversed cstring. What exactly should the return type be?
#include <stdio.h>
#include <string.h>
const char* reverStr(const char *str)
{
char revStr[strlen(str)];
int i;
for(i = strlen(str)-1; i >= 0; i--)
revStr[strlen(str)-1-i] = str[i];
printf("returned value should be %s\n", revStr);
return revStr;
}
int main()
{
char aStr[] = "hello";
char aStr2[] = "goodbye";
printf("%s %s", aStr, aStr2);
char* tmp = reverStr(aStr);//tmp now has garbage
printf("\n%s", tmp);
printf(" %s", aStr);
return 0;
}
Gives
warning: function returns address of local variable [enabled by default]|
warning: initialization discards 'const' qualifier from pointer target type [enabled by default]|
I tried changing char* tmp to char tmp[] but it wouldn't compile. It confuses me when I should use an array and when I should use a pointer.
revStr is an array and ceases to exist after reverStr function exits. For more please read:
Where is the memory allocated when I create this array? (C)
const char* reverStr(const char *str)
{
char revStr[strlen(str)];
return revStr; /* Problem - revStr is a local variable trying to access this address from another function will be erroneous*/
}
const char* reverStr(const char *str)
{
const char * revStr = str;
return revStr; //ok
}
A modifiable l-value cannot have an array type. An l-value is an expression which can come on the left side of an assignment. You use an array when you want to declare lots of variables of the same type and you can index it easily since its layout will be in a sense contiguous.
You use pointers when you want to keep changing the values of the address where you variable points to.
You can do this:
char * p = "test";
p = "new";
But you cannot do this:
char p[] = "test";
char *p1 ="test1";
p = p1; //error
Because their (arrays and pointers) types are not the same and the array p is a non-modifiable l-value.
Here is your fixed code. I tried to make less modifications.
char revStr[strlen(str)]; allocates a local variable(an array) and when you are out of the scope of the reverStr function, its memory is released, which will lead any further usage of its pointer to be UB(segfault in most cases).
A correct way is to allocate the string on the heap and return its pointer like this
char* x = (char*)malloc(strlen(str));
...
return x;
This requires user to be responsible to free the memory. Or you could pass another parameter to your function for the result string.
I think you should use malloc to allocate a new string.
const char* reverStr(const char *str)
{
char *revStr;//using pointer
int i;
revStr = (char*)malloc(strlen(str));//dynamic allocation
for(i = strlen(str)-1; i >= 0; i--)
revStr[strlen(str)-1-i] = str[i];
printf("returned value should be %s\n", revStr);
return revStr;
}
An array is a pointer point to the head of continuous memory.
for example:
int a[] = {1,2,3};
The address in memory maybe:
--1000
|1|
--1004
|2|
--1008
|3|
--1012
1000, 1004, and 1012 are the value of address in memory.
Thus, the value of array a should be 1000.
printf("%d",a);// Yes, you can do it and you may get the value of 1000.
Also, you can use the following code.
int a[] = {1,2,3};
int *b;
b= a;
printf("%d",b[1]);// you will get "2".
You can consider that pointer is a set and array is in the set.
Therefore, you can NOT do this;
int a[] = {1,2,3};
int c = 0;
int *b = &c;
a = b;//error

initialize the struct pointer

typedef struct
{
char *s;
char d;
}EXE;
EXE *p;
For the above struct how do I initialize the structure with pointer? I know for a non-pointer we do EXE a[] = { {"abc",1}, {"def",2} }; . Similarly Is it possible with a pointer after allocating the memory? Say like p[] = { {"abc",1},.. so on} . Basically I want to initialize dynamically. Thanks.
We can initialise the structure with pointer as below
example:
int i;
char e[5]="abcd";
EXE *p=malloc(sizeof(*p));
for(i = 0;i < 5;i++)
*(p+i)=(EXE){e,i+48};
First you need to allocate some memory for that char * and after that use strcpy library function to copy data for structure element.
p->s = strcpy(s,str); //where str source, from where you need to copy the data
I hope this will help. Though I can give you full code for that, But I want you to try.
You can use this
Dynamically allocate C struct?
and it is a duplicate question.
You have to understand how do allocated pointer works:
Suppose you've allocated memory for three structs Ptr = malloc(3*sizeof(EXE)).
Then when you add 1 to Ptr, it comes to the next struct. You have a block of memory divided by 3 (3 smaller blocks of memory for each struct).
So, need to access to the elements of the 1st struct and then move the pointer to the next one.
Here you can understand how it works:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char *s;
char d;
} EXE;
int main()
{
int i;
EXE *Ptr;
Ptr = malloc(3*sizeof(EXE)); // dymnamically allocating the
// memory for three structures
Ptr->s = "ABC";
Ptr->d = 'a';
//2nd
Ptr++; // moving to the 2nd structure
Ptr->s = "DEF";
Ptr->d = 'd';
//3rd
Ptr++; // moving to the 3rd structure
Ptr->s = "XYZ";
Ptr->d = 'x';
//reset the pointer `Ptr`
Ptr -= 2; // going to the 1st structure
//printing the 1st, the 2nd and the 3rd structs
for (i = 0; i < 3; i++) {
printf("%s\n", Ptr->s);
printf("%c\n\n", Ptr->d);
Ptr++;
}
return 0;
}
Notice:
- If you have a variable of a struct use . opereator to access to the elements.
- If you have a pointer to a struct use -> operator to access to the elements.
#include <stdio.h>
#include <stdlib.h>
struct EXE {
int a;
};
int main(){
struct EXE variable;
struct EXE *pointer;
pointer = malloc(sizeof(struct EXE)); // allocating mamory dynamically
// and making pointer to point to this
// dynamically allocated block of memory
// like here
variable.a = 100;
pointer->a = 100;
printf("%d\n%d\n", variable.a, pointer->a);
return 0;
}

C segmentation fault-char pointers

I need help figuring out why I am getting a segmentation fault here. I have gone over it and I think I am doing something wrong with the pointers, but I can figure out what.
My Program:
#include <stdlib.h>
#include <stdio.h>
void encrypt(char* c);
//characters are shifted by 175
int main(){
char* a;
*a = 'a';
/*SEGMENTATION FAULT HERE!*/
encrypt(a);
printf("test:%c/n",*a);
return 0;
};
void encrypt(char* c){
char* result;
int i=(int)(*c);
i+=175;
if(i>255)
{
i-=256;
}
*c=(char)i;
};
The problem is here:
char *a;
*a = 'a'
Since the variable "a" is not initialized, *a = 'a' is assigning to a random memory location.
You could do something like this:
char a[1];
a[0] = 'a';
encrypt(&a[0]);
Or even just use a single character in your case:
int main(){
char a = 'a';
encrypt(&a);
printf("test:%c/n",a);
return 0;
};
char* a;
*a = 'a';
/*SEGMENTATION FAULT HERE!*/
There isn't any "there" there. You've declared a and left it uninitialized. Then you tried to use it as an address. You need to make a point to something.
One example:
char buffer[512];
char *a = buffer;
(Note buffer has a maximum size and when it falls out of scope you cannot reference any pointers to it.)
Or dynamic memory:
char *a = malloc(/* Some size... */);
if (!a) { /* TODO: handle memory allocation failure */ }
// todo - do something with a.
free(a);
That pointer a does not get the actual space where to store the data. You just declare the pointer, but pointing to where? You can assign memory this way:
char *a = malloc(1);
Then it won't segfault. You have to free the variable afterwards:
free(a);
But in this case, even better,
char a = 'a';
encript(&a);

Resources