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

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.

Related

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".

c char pointers memory and global variables

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);
}

C function returning incorrect data

I'm making a game using C and I have a function the reads a file and returns a pointer that holds the data for the level.
File: levelbuilder.c
bunker *read_rooms(char *rooms_file){
FILE *bunker_file = fopen(rooms_file, "r");
char room_name[MAX_ROOM_NAME_LEN];
fscanf(bunker_file, "%s", room_name);
bunker *result = create_bunker(room_name);
fclose(bunker_file);
return result;
}
Obviously right it doesn't do the whole level as I'm still testing things as I go. I'll list create_bunker below.
File: room.c
bunker *create_bunker(char *room_name){
bunker *result = malloc(sizeof(bunker));
result->room_name = room_name;
for (int i = 0; i < MAX_ITEMS; i++) {
result->items[i] = NULL;
}
result->connected_to = NULL;
result->next = NULL;
return result;
}
This function works just fine.
When I check the variables in read_rooms using the debugger they all have the correct room name from file. However, in main the pointer to the level isn't NULL but it's room_name is. Where am I going wrong? Any help would be much appreciated :)
Variable room_name is a local array in function read_rooms.
As such, it is pointing to a piece of memory on the stack.
The contents of that memory are valid only as long as you're "inside" the function.
Once you're "out", you can no longer rely on this piece of memory to contain valid data.
It might contain the data you'd expect, but it might not.
And even if it does, it may be overridden at a later point in the execution of the program.
So instead of setting result->room_name = room_name, you should copy the actual contents:
result->room_name = malloc(strlen(room_name)+1);
strcpy(result->room_name,room_name);
And of course, don't forget to free(result->room_name) before you free(result)...
Change this line:
result->room_name = room_name;
For
strcpy (result->room_name, room_name);
To copy the contents of room_name in result->room_name. As you have it right now, you are making a char * pointer assigment and this is what will drive the program crazy.
You allocate room_name on stack, than you pass ponter to it, and save to result->room_name. You can't rely on value that is saved on stack (created without malloc or something), it gets overwritten very soon when function execution is finished. Just use strcpy as Hernan Velasquez suggested
For a start this line is wrong
result->room_name = room_name;
As it will go out of scope and hence to the wolves. Perhaps make a copy.
I am sure there are other problems

Pointer to local variable outside the scope of its declaration

Let's say I have a structure representing a PDF document pdf and a structure representing one of its pages pdf_page:
typedef struct pdf_page {
int page_no;
pdf_page *next_page;
char *content;
} pdf_page;
typedef struct {
pdf_page *first_page, *last_page;
} pdf;
From my main(), I call create_pdf_file(pdf *doc):
void main() {
pdf doc;
create_pdf_file(&doc);
// reading the linked list of pages here
}
Assume that create_pdf_file is something along these lines:
void
create_pdf_file(pdf *doc) {
for (int i = 0; i < 10; i++) {
pdf_page p;
p.page_no = i;
p.contents = "Hello, World!";
doc->last_page->next_page = p;
}
}
(This is merely an example source code, so no list processing is shown. Obviously, the first_page and last_page members of pdf need to be set first.)
My question: If I access doc->first_page - as well as the other pages in the linked list - after the create_pdf_file() call in my main(), is it possible that I get segmentation faults because of "taking the local variable p out of its context"?
(I am not sure whether I have guaranteed that the corresponding memory location will not be used for something else.)
If so, how do I avoid this?
yes, p is a local variable stored on the stack, when the lifetime ends (every loop iteration) any pointer to it gets invalid. you need to allocate every page with malloc() and free() it after you are finished.
this would look similar to:
for (int i = 0; i < 10; i++)
{
pdf_page* p = malloc(sizeof(pdf_page));
p->page_no = i;
p->contents = "Hello, World!";
doc->last_page->next_page = p;
}
and when you call your function you have to pass a pointer to doc:
create_pdf_file(&doc);
is it possible that I get segmentation faults because of "taking the local variable p out of its context"?
Once the block in which p is declared terminates, any pointer to p is invalid (a "dangling pointer") and attempting to dereference such a pointer is Undefined Behaviour. In other words, don't do it: you could get segmentation faults, or any other behaviour (including random memory corruption or the use of the wrong data without any error condition.)
(I am not sure whether I have guaranteed that the corresponding memory location will not be used for something else.)
You've guaranteed that the lifetime of p is shorter than a pointer to p.
If so, how do I avoid this?
Use malloc to dynamically allocate a memory region of the correct size to hold the datum. Don't forget to free the memory when you no longer need it.

pointer and which is pointed by the pointer

Update : Sorry, just a big mistake. It is meaningless to write int *a = 3; But please just think the analogy to the case like TCHAR *a = TEXT("text"); (I edited my question, so some answers and comments are strange, since they are for my original question which is not suitable)
In main function, suppose I have a pointer TCHAR *a = TEXT("text"); Then it excutes the following code:
int i;
for (i = 0; i < 1000; i++) {
a = test(i);
}
with the function TCHAR* test(int par) defined by:
TCHAR* test(int par)
{
TCHAR *b = TEXT("aaa");
return b;
}
My question is, after executing the above code, but before the program ends, in the memory:
1. the pointer `a` remains?
2. The 1000 pointers `b` are deleted each time the function test(...) exits ?
3. But there are still 1000 memory blocks there?
In fact, my question is motivated from the following code, which shows a tooltip when mouse is over a tab item in a tab control with the style TCS_TOOLTIPS:
case WM_NOTIFY
if (lpnmhdr->code == TTN_GETDISPINFO) {
LPNMTTDISPINFO lpnmtdi;
lpnmtdi = (LPNMTTDISPINFO)lParam;
int tabIndex = (int) wParam; // wParam is the index of the tab item.
lpnmtdi->lpszText = SetTabToolTipText(panel->gWin.At(tabIndex));
break;
}
I am thinking if the memory usage increases each time it calls
SetTabToolTipText(panel->gWin.At(tabIndex)), which manipulates with TCHAR and TCHAR* and return a value of type LPTSTR.
Yes, the pointer a remains till we return from the main function
The variable b (a 4-byte pointer) is automatic. It is created each time we call test function. Once we return from it, the variable disappears (the pointer). Please note, the value to which b points isn't affected.
No. In most of the cases, I think, there will be only one block allocated during compilation time (most likely in the read-only memory) and the function will be returning the same pointer on every invocation.
If SetTabToolTipText allocates a string inside using some memory management facilities new/malloc or some os-specific, you should do an additional cleanup. Otherwise there'll be a memory leak.
If nothing like this happens inside (it's not mentioned in the documentation or comments etc), it's most likely returning the pointer to some internal buffer which you typically use as readonly. In this case, there should be no concerns about a memory consumption increase.
You dont allocate any memory so you don't have to worry about memory being freed. When your vaiables go out of scope they will be freed automatically. In this function
int test(int par)
{
int *b = par;
}
you don't have a return value even though the function says that is will return an int, so you should probably do so as in this line
for (i = 0; i < 1000; i++) {
a = test(i);
}
you assign to a the value that is returned by test(). Also
int* a = 3;
int* b = par;
are asking for trouble. You are assigning integer values to a pointer variable. You should probably rethink your above code.
Pointer should contain adress... so int* a = 3 is something meaningless... And in function you don't allocate memory for int (only for par variable, which then destroy when the function ends), you allocate memory for storing adress in int* b, this memory also free when the funciton ends.

Resources