c char pointers memory and global variables - c

The pointer to my global variable is turning to crud after freeing the local resource that I use to set the value in c.
this is the .c class
char* resource_directory;
void getResourcePath()
{
char *basePath = SDL_GetBasePath();
char* resource_dir = (char*)malloc(37 * sizeof(char));
for(int i = 0; i < 25; i++)
{
resource_dir[i] = basePath[i];
}
strcat(resource_dir, "resources/");
resource_dir[36] = '\0';
*resource_directory = *resource_dir;
free(basePath);
// free(resource_dir); <--- If I free here the value goes to crud
}
(this line below should say the value at resresource_directorydir equals the value at resource_dir) right?
*resource_directory = *resource_dir;
so the value at the address of the first pointer should get the value of the address at the 2nd but after trying to free the resource towards the end of the function.
even doing a print statement of the addresses show that they have different addresses.
SDL_Log("%d, %d", &resource_directory, &resource_dir);
example output : 245387384, 1361037488
I get the feeling that I am making a silly mistake here but I don't know what it is.

This line,
*resource_directory = *resource_dir;
is assigning the first value resource_dir points to, to the uninitialized pointer resource_directory, it's equivalent to
resource_directory[0] = resource_dir[0];
which is clearly not what you want.
You need to assign the pointer
resource_directory = resource_dir;
but you shouldn't use a global variable for that, and specially
Don't malloc() it, you have to free() everything you malloc() and global variables make it hard.
Don't use malloc() for fixed size objects, instead declare it as an array with the appropriate size, like this
char resource_directory[37];
Copy strings with strcpy() instead of writing a loop your self
for(int i = 0; i < 25; i++)
{
resource_dir[i] = basePath[i];
}
woule be
strcpy(resource_dir, basePath);
One thing you should notice when using a global variable like this is that if you call getResourcesPath() more than once, you are going to leak resources, if you must use global variables to carry values that need to live as long as the whole program lives, try to make their initialization static, and you can completely avoid using global variables for that, because everything that you declare and initialized in the stack frame of main() will hafe the same lifetime as the program, so you can pass it as parameters to any function that requires them from within main(), if you have many of these variables, create a struct to hold them, and pass the struct across the functions that need these resources, this is a very common technique in fact.

This statements
SDL_Log("%d, %d", &resource_directory, &resource_dir);
outputs as integer values the addresses of global variables resource_directory and local variable resource_dir. Of course their addresses are different.
As for this statement
*resource_directory = *resource_dir;
then it stores the first character of the string pointed to by resource_dir at the address that is stored in pointer resource_directory. However initially resource_directory was initialized by zero as an object with the static storage duration. So the program has undefined behaviour.
I think you mean the following
resource_directory = resource_dir;
That is you wanted that resource_directory would point to the string built in the function.
And there is no sense to use statement
free(resource_dir); <--- If I free here the value goes to crud
necause in this case statement
resource_directory = resource_dir;
also does not have sense.
If resource_directory need to point to the built in the function string then you shall not destroy it.
Take into account that using magic numbers 37 and 25 makes the program unclear and error-prone.

A pointer is a variable that contains a numeric value which happens to be the address of a memory location. For example, a NULL pointer is a variable containing the value 0. Assigning the notion of "isa pointer" to is a way of notifying the compiler of your intended use: that is, you cannot use pointer syntax on non-pointer variables. But until you do use pointer syntax, they more or less behave like normal variables.
int i = 0;
int* p = &i;
int j;
int* q;
j = i; // j has the same value as i
q = p; // q has the same value as p
At the end of the above code, p and q point to the same address. We only use the * syntax when we want to dereference a pointer:
q = p;
*q = *p; // copies the `int` pointed to by `p` to
// the `int` memory location pointed to by `q`,
// which is the same location.
Note that it is possible to nest pointers:
int** pp = &p;
p is int*, so &p is int**.
pp is a numeric value, it is the address of a memory location that contains an int*. *pp means fetch the value at the memory location contained in pp which will retrieve a second numeric value - the value that is in p, which is itself an int* and thus a second address. **pp will retrieve us the integer to which p points.
Your assignment
*resource_directory = *resource_dir;
copies the pointed-to-values, not the addresses.
Since you have tagged your question as C++ I'm going to conclude by offering this alternative implementation:
std::string resource_dir;
void getResourcePath()
{
char *basePath = SDL_GetBasePath();
resource_dir = base_path;
resource_dir += "resources/";
free(basePath);
}
If you need the c-string value of resource_dir subsequently, use resource_dir.c_str().
Alternatively, if you require a C implementation:
char* resource_dir;
void getResourcePath()
{
const char subPath[] = "resources/";
size_t length;
char *basePath = SDL_GetBasePath();
if (resource_dir)
free(resource_dir);
length = strlen(basePath) + sizeof(subPath);
resource_dir = (char*)malloc(length);
snprintf(resource_dir, length, "%s%s", basePath, subPath);
free(basePath);
}

Related

What is the difference between 'ptr = &array[index]' and '*ptr = array[index]'?

I'm new to C programming and having a hard time differentiating this syntax
ptr = &array[index]
against this one
*ptr = array[index]
In a sample function I worth
void getDevice(Device* device)
the line works just like I expect it to
*device = devices[index];
(de-referenced device pointer now has value devices[index])
but this line causes segfault
device = &devices[index];
(device pointer has devices[index]'s address)
I think both ultimately should have same effect (ptr pointing to devices[index]). What am I missing here?
Actual code:
void populatePhysicalDevice(VkInstance* gInstance, VkPhysicalDevice* gPhysicalDevice)
{
uint32_t physicalDeviceCount = 0;
vkEnumeratePhysicalDevices(*gInstance, &physicalDeviceCount, VK_NULL_HANDLE);
VkPhysicalDevice physicalDevices[physicalDeviceCount];
vkEnumeratePhysicalDevices(*gInstance, &physicalDeviceCount, physicalDevices);
int bestSuitedPhysicalDeviceLocation = 0;
gPhysicalDevice = &physicalDevices[bestSuitedPhysicalDeviceLocation]; // Causes segfault
*gPhysicalDevice = physicalDevices[bestSuitedPhysicalDeviceLocation]; // Works
}
VkInstance
VkPhysicalDevice
vkEnumeratePhysicalDevices
Assuming you call your function like so:
vkInstance instance;
vkPhysicalDevice physicalDevice;
vkCreateInstance(..., &instance);
populatePhysicalDevice(&instance, &physicalDevice);
So the two values of the two arguments passed are the pointers to instance and physicalDevice in the caller's scope. The pointers (not the values they point to) get copied into the corresponding variables in populatePhysicalDevice:
void populatePhysicalDevice(VkInstance* gInstance, VkPhysicalDevice* gPhysicalDevice)
{
So at this point, inside populatePhysicalDevice(), you have two pointers that you can change at will, but will not change anything in the caller's scope. Let's go on:
uint32_t physicalDeviceCount = 0;
vkEnumeratePhysicalDevices(*gInstance, &physicalDeviceCount, VK_NULL_HANDLE);
VkPhysicalDevice physicalDevices[physicalDeviceCount];
vkEnumeratePhysicalDevices(*gInstance, &physicalDeviceCount, physicalDevices);
Now you have a local array of VKPhysicalDevices, that has been filled in by vkEnumeratePhysicalDevices(). Now you want to ensure that the caller gets a copy of the best suited physical device:
int bestSuitedPhysicalDeviceLocation = 0;
gPhysicalDevice = &physicalDevices[bestSuitedPhysicalDeviceLocation]; // Causes segfault
That line doesn't do anything that the caller will see. It will just change the local variabel gPhysicalDevice to point to the start of the local array physicalDevices. When you return, all those things go away. The end result is that [hysicalDevice in the caller's scope has not been initialized. That is the likely cause of the segmentation fault.
When you do this instead:
*gPhysicalDevice = physicalDevices[bestSuitedPhysicalDeviceLocation]; // Works
You are actually copying the value of the first element of physicalDevices[] into the variable physicalDevice in the caller's scope.
Note that if you are just always going for the first physical device, you do not need to create a local array, you could instead just do:
void populatePhysicalDevice(VkInstance* gInstance, VkPhysicalDevice* gPhysicalDevice)
{
vkEnumeratePhysicalDevices(*gInstance, 1, gPhysicalDevices);
}
But don't forget that the instance might not actually have any physical devices available, so check the return values of the functions you call and make sure they are as expected!
ptr = &array[index] sets ptr to point to array[index]. That is, it puts the address of array[index] into ptr.
*ptr = array[index] sets *ptr to the value array[index]. That is, it gets the value stored in array[index] and put that value in the place pointed to by ptr. It does not change ptr.
The cause of the segment fault you report cannot be ascertained because you have not provided sufficient code or information. The line device = &devices[index]; by itself is likely not the cause.

Memory allocation using for loop

My Doubt is regarding only memory allocation so don't think about program output
#include<stdio.h>
int main(){
for(int i=0;i<20;i++){
char *str=malloc(sizeof(char)*6); //assuming length of each string is 6
scanf("%s",str);
insertinlinkedlist(str);
}
}
whenever i allocate memory here as shown above only the base address of char array will pass to linked list,and that is the memory block allocated for char array is inside main only and i am storing the base address of that array in str which is local to main and is passed to insetinlinkedlist
I want to ask whenever memory is allocated inside loop than why the number of
memory blocks(no of char arrays declared ) are created equal to n (number of time loop runs) since variable name is same we should be directed to same memory location
Note I have checked in compiler by running the loop all the times when loop runs memory the value of str is different
is The above method is correct of allocating memory through loop and through same variable "Is the method ensures that every time we allocate memory in above manner their will be no conflicts while memory allocation and every time we will get the address of unique memory block"
Now above doubt also creates a doubt in my mind
That if we do something like that
int main(){
for(int i=0;i<n;i++){
array[50];
}
}
then it will also create 50 array inside stack frame
malloc returns a pointer to the first allocated byte. Internally it keeps track of how much memory was allocated so it knows how much to free (you do need to insert calls to free() or you'll leak memory, by the way). Usually, it does this by allocating a little bit of memory before the pointer it gives you and storing the length there, however it isn't required to do it that way.
The memory allocated by malloc is not tied to main in any way. Currently main is the only function whose local variables have a pointer to that memory, but you could pass the pointer to another function, and that function would also be able to access the memory. Additionally, when the function that called malloc returns, that memory will remain allocated unless manually freed.
The variable name doesn't matter. A pointer is (to first approximation) just a number. Much like how running int a = 42; a = 20; is permitted and replaces the previous value of a with a new one, int *p = malloc(n); p = malloc(n); will first assign the pointer returned by the first malloc call to p, then will replace it with the return value of the second call. You can also have multiple pointers that point to the same address:
int *a = malloc(42);
int *b = malloc(42);
int *c = a;
a = malloc(42);
At the end of that code, c will be set to the value returned by the first malloc call, and a will have the value returned by the last malloc call. Just like if you'd done:
//assume here that f() returns a different value each time
//it's called, like malloc does
int a = f();
int b = f();
int c = a;
a = f();
As for the second part of your question:
for(int i=0;i<n;i++){
int array[50];
}
The above code will create an array with enough space for 50 ints inside the current stack frame. It will be local to the block within the for loop, and won't persist between iterations, so it won't create n separate copies of the array. Since arrays declared this way are part of the local stack frame, you don't need to manually free them; they will cease to exist when you exit that block. But you could pass a pointer to that array to another function, and it would be valid as long as you haven't exited the block. So the following code...
int sum(int *arr, size_t n) {
int count = 0;
for (size_t i = 0; i < n; i++) {
count += arr[i];
}
return count;
}
for(int i=0;i<n;i++){
int array[50];
printf("%d\n", sum(array, 50));
}
...would be legal (from a memory-management perspective, anyway; you never initialize the array, so the result of the sum call is not defined).
As a minor side note, sizeof(char) is defined to be 1. You can just say malloc(6) in this case. sizeof is necessary when allocating an array of a larger type.

Pass by reference for pointers in C

I was trying to understand the concept of passing by reference. When I do this,
#include<stdio.h>
int recent (int *a)
{
*a = 20;
return 0;
}
int main()
{
int bee;
bee=5;
int *val = &bee;
printf("Value is %d\n", *val);
recent(val);
printf("Now Value is %d\n", *val);
return 0;
}
Basically I am making the pointer val point to the memory location of bee, and then when I pass it to recent function, and change the value, that change gets reflected in the calling function, so the value changes to 20. But when I do this,
#include<stdio.h>
int check = 20;
int recent (int *a)
{
a = &check;
return 0;
}
int main()
{
int bee;
bee=5;
int *val = NULL;
recent(val);
printf("Now Value is %d\n", *val);
return 0;
}
I get segmentation fault.
Is it because I didn't initialize the pointer to point to any location, and then I passed the value to recent function, and even though I made it point to a memory location (check variable), the calling function didnt catch that because I was passing by value?
Is this completely true or I misinterpreted something and got lucky with the answer?
Your problem is that you are printing the output of dereferencing the pointer val in the main function. The value of the pointer val in the main function is NULL. Thus the program is trying to print the thing at memory location 0, which is inaccessible to your program and results in a segmentation fault.
First you create the val pointer and assign it the value NULL.
int *val = NULL;
Then you call recent, passing it the pointer val, which still holds NULL.
recent(val);
Finally you print *val. val still holds NULL, and the * operator tells the compiler to "dereference" val, meaning to use the value of the thing that val is pointing to.
printf("Now Value is %d\n", *val);
In response to the question of whether your description is correct, the answer is sort of, but your description is imprecise. You made the function's copy of the pointer point to something. When you implement a pass-by-reference function in C using pointers, you are still passing the pointers themselves by value: a copy of the pointer is made, pushed onto the stack, and sent to the function. If you update the value of the pointer in the called function, the value of the pointer in the calling function will not be changed.
The reason has to do with your function recent(). When you pass in "a" you are passing in an int* (i.e. int pointer) which is an address to a location in memory. However, "a" as you have it, is local to this function (the pointer is pass by value).
Thus when you set "a = &check", you are only changing the local pointer value. As soon as recent() returns, "a" goes out of scope. In this context, you are never changing what "a" actually points to.
Thus, you segfault because val is still null, and you are trying to dereference a NULL pointer.
val is still a null pointer after leaving the function. The pointer itself is (as you correctly guessed) only passed by value, not by reference. Inside the function you are only modifying the pointer (which only lives insides the function), not the pointer target.
Besides that, please be careful with passing around memory locations to automatic stack variables. At least coming from a C++ background, it's considered bad style. Since you don't explicitly control the life cycle of a stack variable yourself (as you would do with malloc/free), you can easily shoot yourself in the foot by accidentally dereferencing pointers which have already been cleaned from the stack.
Is it because I didn't initialize the pointer to point to any location,
Code well initialized with int *val = NULL;, yet NULL is not a valid location. It isn't the NULL is a location or not. It is the NULL is the null pointer constant. As a null pointer, it "is guaranteed to compare unequal to a pointer to any object or function."
... and even though I made it point to a memory location (check variable), the calling function didn't catch that because I was passing by value?
Yes. With a = &check;, only the local a was affected, not the val in which a was copied from as the actual augment val was passed by value (copied) to the formal parameter a.
Is this completely true ...
IMO: Yes
... I misinterpreted something and got lucky with the answer?
It appears no misinterpretation. Lucky - hard to rate.
Here is what is going on in your code:
#include<stdio.h>
int check = 20;
int recent (int *a)
{
a = &check;
return 0;
}
int main()
{
// memory is allocated to hold an integer
int bee;
// the number 5 is written into that memory space
bee = 5;
// memory is allocated to hold a memory address
// the value of null (which is a invalid address) is written into it
int *val = NULL;
// more memory is allocated to hold a memory address (int* a)
// the address in val (which is null) is written into it
// the new memory address (a) now points to the address of check
recent(val);
// val is still NULL
// BOOOM!
printf("Now Value is %d\n", *val);
return 0;
}
Long story short, you are correct! :)
It's basically what all have answered. It's because you are passing the address pointed by pointer a using Pass By Value method. That is your sending in a copy of the address. If you want the second code to work you need to change the code to the following,
#include<stdio.h>
int check = 20;
int recent(int **a)
{
*a = &check;
return 0;
}
int main()
{
int bee;
bee = 5;
int *val = NULL;
recent(&val);
printf("Now Value is %d\n", *val);
return 0;
}
That is you have to Pass the address pointed by a by using C version of "Pass By Reference".

Returned array in C doesn't contain same values

I'm in the process of teaching myself C and I'm mistified as to what's causing the following issue: when I create an array in a method and return it as a pointer to the calling function, none of the content is correct. I've boiled down this problem to the following example:
char * makeArr(void){
char stuff[4];
stuff[0]='a';
stuff[1]='b';
stuff[2]='c';
stuff[3]='d';
printf("location of stuff:%p\n",stuff);
int i;
for(i = 0; i < 4; i++){
printf("%c\n",stuff[i]);
}
return stuff;
}
int main(void){
char* myarr;
myarr = makeArr();
int i;
printf("\n");
printf("location of myarr:%p\n", myarr);
for(i = 0; i < 4; i++){
printf("%c\n",myarr[i]);
}
}
The output returns the following:
location of stuff:0028FF08
a
b
c
d
location of myarr:0028FF08
Ä
ÿ
(
(a null character)
So I've verified that the locations between the two values are the same, however the values differ. I imagine that I'm missing some critical C caveat; I could speculate it's something to do with an array decaying into a pointer or a problem with the variable's scope, but and any light that could be shed on this would be much appreciated.
What you're attempting to do is return the address of a local variable, one that goes out of scope when the function exits, no different to:
char *fn(void) {
char xyzzy = '7';
return &xyzzy;
}
That's because, other than certain limited situations, an array will decay into a pointer to the first element of that array.
While you can technically return that pointer (it's not invalid in and of itself), what you can't do is dereference it afterwards with something like:
char *plugh = fn();
putchar (*plugh);
To do so is undefined behaviour, as per C11 6.5.3.2 Address and indirection operators /4 (my bold):
If an invalid value has been assigned to the pointer, the behaviour of the unary * operator is undefined.
Among the invalid values for dereferencing a pointer by the unary * operator are a null pointer, an address inappropriately aligned for the type of object pointed to, and the address of an object after the end of its lifetime.
Having stated the problem, there are (at least) two ways to fix it.
First, you can create the array outside of the function (expanding its scope), and pass its address into the function to be populated.
void makeArr (char *stuff) {
stuff[0]='a';
stuff[1]='b';
stuff[2]='c';
stuff[3]='d';
}
int main(void) {
char myarr[4];
makeArr (myarr);
// Use myarr here
}
Second, you can dynamically allocate the array inside the function and pass it back. Items created on the heap do not go out of scope when a function exits, but you should both ensure that the allocation succeeded before trying to use it, and that you free the memory when you're finished with it.
char *makeArr (void) {
char *stuff = malloc (4);
if (stuff != NULL) {
stuff[0]='a';
stuff[1]='b';
stuff[2]='c';
stuff[3]='d';
}
return stuff;
}
int main(void) {
char *myarr;
myarr = makeArr();
if (myarr != NULL) {
// Use myarr here
free (myarr);
}
}
stuff[] only exists on the stack during function call, it gets written over after return. If you want it to hold values declare it static and it will do what you want.
However, the whole idea is fundamentally lame, don't do that in real life. If you want a function to initialize arrays, declare an array outside of the function, pass a pointer to this array as a parameter to the function and then initialize an array via that pointer. You may also want to pass the size of the array as a second parameter.
Since you're learning, a sample code is omitted intentionally.
Your array stuff is defined locally to the function makeArr. You should not expect it to survive past the life of that function.
char * makeArr(void){
char stuff[4];
Instead, try this:
char * makeArr(void){
char *stuff=(char*)calloc(4, sizeof(char));
This dynamically creates an array which will survive until you free() it.

initialize a global 2-dimensional C array of integers at run time

I need to store an array of point (x,y). I read the points from a file, and the number of points are not constant, but i can get it at the first line of the file. So i write a procedure load() to loading the points from the file and store them in a global array. It doesn't work.
My code:
int *array[][]; // this is a pointer to a 2-dimensional array??
void load(){
..
int tempArray[2][n]; //n is the first line of the file
..
array = tempArray;
}
You're trying to return a pointer to memory that is local to the function that defines the variable. Once that function stops running ("goes out of scope"), that memory is re-used for something else, so it's illegal to try and reference it later.
You should look into dynamic allocation, and have the loading function allocate the needed memory and return it.
The function prototype could be:
int * read_points(const char *filename, size_t *num_points);
Where filename is of course the name of the file to open, num_points is set to the number of points found, and the returned value is a pointer to an array holding x and y values, interleaved. So this would print the coordinates of the first point loaded:
size_t num_points;
int *points;
if((points = load_points("my_points.txt", &num_points)) != NULL)
{
if(num_points > 0)
printf("the first point is (%d,%d)\n", points[0], points[1]);
free(points);
}
This declaration of yours does not work:
int *array[][]; // this is a pointer to a 2-dimensional array??
First, it is trying to declare a 2D array of int *. Second, when you declare or define an array, all dimensions except the first must be specified (sized).
int (*array)[][2]; // This is a pointer to a 2D array of unknown size
This could now be used in a major variant of your function. It's a variant because I misread your question at first.
void load(void)
{
...
int tempArray[n][2]; // Note the reversed order of dimensions!
...
array = &tempArray;
...there must be some code here calling functions that use array...
array = 0;
}
Note that the assignment requires the & on the array name. In the other functions, you'd need to write:
n = (*array)[i][j];
Note, too, that assigning the address of a local array to a global variable is dangerous. Once the function load() returns, the storage space for tempArray is no longer valid. Hence, the only safe way to make the assignment is to then call functions that reference the global variable, and then to reset the global before exiting the function. (Or, at least, recognize that the value is invalid. But setting it to zero - a null pointer - will more nearly ensure that the program crashes, rather than just accessing random memory.
Alternatively, you need to get into dynamic memory allocation for the array.
Your question actually is wanting to make a global pointer to a VLA, variable-length array, where the variable dimension is not the first:
int tempArray[2][n]; // Note the reversed order of dimensions!
You simply can't create a global pointer to such an array.
So, there are multiple problems:
Notation for pointers to arrays
Initializing pointers to arrays
Assigning global pointers to local variables
You can't have global pointers to multi-dimensional VLAs where the variable lengths are not in the first dimension.
You should minimize the use of globals.
A more elegant version might go like this:
typedef struct point_ { int x; int y; } point;
point * create_array(size_t n)
{
return calloc(n, sizeof(point));
}
void free_array(point * p)
{
free(p);
}
int main()
{
size_t len = read_number_from_file();
point * data = create_array(len);
if (!data) { panic_and_die(); }
for (size_t i = 0; i != len; ++i)
{
/* manipulate data[i].x and data[i].y */
}
free_array(data);
data = 0; /* some people like to do this */
}
You are trying to assign an array but in C arrays cannot be assigned.
Use memcpy to copy one array to another array. Arrays elements in C are guaranteed to be contiguous.
int bla[N][M] = {0};
int blop[N][M];
/* Copy bla array to blop */
memcpy(blop, bla, sizeof blop);

Resources