A colleague of mine is going a bit nuts with const in ANSI C and I wanted to know what you guys thought about it. He writes stuff like this for example:
const uint8* const pt_data
I understand where he's going with this but for me it makes the reading and maintainability harder with all these const everywhere.
It's a const pointer pointing to const data.
The first const prevents *pt_data = 10;
The second const prevents pt_data = stuff;
It looks like it can be pretty legitimate.
const always refers to the word on its right, except if it is at the end of the line, where it refers to the item itself (in higher level languages)
const char* str; //This is a pointer to read-only char data
//Read as to (const char)* str;
//Thus :
// *str = 'a';
//Is forbidden
char* const str; //This is a read-only pointer to a char data
//Read as char* (const str);
//Thus :
// str = &a;
//Is forbidden
const char* const str; //This is a read-only pointer to read-only char data
//Read as (const char)* (const str);
//Thus :
// str = &a
// and
// *str = 'a';
//Is forbidden
You should always initialize those pointers when declaring them (Except if they're a parameter)
const keyword is great at ensuring something will not be modified, and also tells the developper it should not. For example int strlen(const char* str) tells you the char data in your string will not be modified whatsoever.
It is a constant pointer to an constant data.
it means you cannot change the data(whose address pt_data stores) and also cannot change the pointer(pt_data) to point to something else(some other address).
He probably needs it that way.
If you start at the variable name, and going counter-clockwise, pt_data is a const pointer to uint8 which is const.
See the following crude ASCII image:
,--------------------------------.
| |
| ,------------------------. |
| | | |
| | ,------------------. | |
| | | | | |
| | | ,-----------. | | |
| | | | | | | |
const uint8 * const pt_data; | | | |
| | | | | | | |
| | | `-----' | | |
| | | | | |
| | `-------------' | |
| | | |
| `--------------------' |
| |
`--------------------------'
Ever since I saw this scheme in an old C book many years ago, it has helped me understand complex declarations.
Related
In the below code, a *Pointer is passed to a function.
The address & symbol is omitted.
The functions can still modify the value in the passed pointer.
Does the compiler auto-add the &?
char * input();
void get_command() {
char * command_pointer = input();
char * second = second_arg(command_pointer); //second needs to be before first
char * first = first_arg(command_pointer); //becuase first adds a /0
choose(first, second);
free(command_pointer);
}
char * first_arg(char * arg) {
char * j = strchr(arg, '-');
if(j==NULL) {
return arg;
}
*j = '\0';
return arg;
}
char * second_arg(char * arg) {
char * j = strchr(arg, '-');
if( j==NULL ) {
return NULL;
}
return ++j;
}
Does the compiler auto-add the &?
No. & gets the address of a variable, and the address of command_pointer isn't passed. Only its value (the address of the buffer) is passed.
The functions can still modify the value in the passed pointer.
No, they can't. They can't modify (the value of) the pointer. They can only modify that to which the pointer points.
first_arg and second_arg can't change command_pointer (the variable in get_command) because they don't know anything about it and they don't have a pointer to it.
e.g. arg = NULL; would have no effect on command_pointer.
However, they can modify the data to which command_pointer points (the chars), because they have a copy of the same pointer.
e.g. *arg = 0 (aka arg[0] = 0;) would effect *command_pointer (aka command_pointer[0]).
Let's illustrate some of the variables of get_command and first_arg.
input()'s rv Buffer allocated by input
+----------+ +---+---+---+---+---+---+---
| 0x1000 -------+--->| | | | | | | ...
+----------+ | +---+---+---+---+---+---+---
| ^
command_pointer | |
+----------+ | |
| 0x1000 -------+ |
+----------+ | |
| |
arg | j |
+----------+ | +----------+ |
| 0x1000 -------+ | 0x1004 ---------+
+----------+ +----------+
input() returns an address to a bufer it allocated (0x1000 in the diagram).
The value returned by input() is copied into command_pointer.
The value of command_pointer is copied into arg.
A value based on arg is stored in j.
get_command can modify command_pointer and the buffer.
first_arg can modify arg, j and the buffer, but not command_pointer.
The value is changed only if you use the * on the pointer. if you will not the value will not change, the address will change. Consider these functions:
char * first_arg(char * arg) {
arg = 'a';
// some other code //
}
char * second_arg(char * arg) {
*arg = 'c';
// some other code //
}
the first function will change the address that arg is pointing at. This function can be dangerous because we don't now what is stored in the address 'a'. This function may change the behavior of otter scopes in an unexpected way. but it will not change the value that arg is pointing at. (except of the scenario that you hardcode the exact address of arg)
the second function will change the value in the address arg is pointing at. This is the well defined behavior that we are looking for. This will only change the value of the memory arg is pointing at.
I am struggling with memset.
If I write in my array my program crashes. If I comment out the memset i have no problems.
My type struct:
typedef struct
{
char Frage [maxLEN_F_A];
char Antwort[maxLEN_F_A];
} Fragenfeld;
My declaration of the struct:
Fragenfeld QuizFragen[maxFragen];
Fragenfeld *ptrQuizFragen = QuizFragen;
The memset call:
memset(&ptrQuizFragen,0,maxFragen*sizeof(Fragenfeld));
My function, where I edit the value of the adress:
int Fragen_einlesen(Fragenfeld *Quizfragen)
{
....
strncpy(Quizfragen->Frage,sEingabe, maxLEN_F_A);
}
When you write
memset(&ptrQuizFragen,0,maxFragen*sizeof(Fragenfeld));
you're saying "please set a lot of of bytes, starting at the address of the pointer variable ptrQuizFragen, to zero." Notice that this is different than saying "please set a lot of bytes, starting at the beginning of the array pointed at by ptrQuizFragen, to zero." This means the bytes are getting written to the wrong place, which is what's causing your segfault.
Graphically, the setup looks something like this:
ptrQuizFragen
+-----------+
| |
+-----------+
|
v
+-----------+-----------+-----------+ ... +-----------+
| | | | | |
+-----------+-----------+-----------+ ... +-----------+
QuizFragen
The line you've written puts the bytes starting where ptrQuizFragen is located in memory, which does this:
ptrQuizFragen
+-----------+
| 00000000000000000000000000000000000 ... 000000000000 (oops!)
+-----------+
+-----------+-----------+-----------+ ... +-----------+
| | | | | |
+-----------+-----------+-----------+ ... +-----------+
QuizFragen
The line you want is
memset(ptrQuizFragen, 0, maxFragen * sizeof(Fragenfeld));
which says to put the bytes at the memory location pointed at by ptrQuizFragen. That would do this:
ptrQuizFragen
+-----------+
| |
+-----------+
|
v
+-----------+-----------+-----------+ ... +-----------+
| 000000000 | 000000000 | 000000000 | | 000000000 |
+-----------+-----------+-----------+ ... +-----------+
QuizFragen
This ...
memset(&ptrQuizFragen,0,maxFragen*sizeof(Fragenfeld));
... requests that the memory starting at the address of variable ptrQuizFragen be written, but what you want is that memory at the location to which the pointer points is written:
memset(ptrQuizFragen, 0, maxFragen*sizeof(Fragenfeld));
Alternatively, for the same reason that you can initialize ptrQuizFragen as you do, you could also do away with it altogether:
memset(QuizFragen, 0, maxFragen*sizeof(Fragenfeld));
Additionally, it would be clearer to express the wanted size directly in terms of the object being written to:
memset(QuizFragen, 0, sizeof(QuizFragen));
However, if this is for one-time initialization then I would not use memset at all:
Fragenfeld QuizFragen[maxFragen] = {0};
Although that's valid C with well-defined sematics, some compilers may warn. If yours does, and that makes you uncomfortable, then one alternative would be to expand a bit to
Fragenfeld QuizFragen[maxFragen] = { { {0}, {0} } };
I am trying to avoid memory leaks in my code. I need to de-allocate pElement, line and pSecond, without losing the values inside pImage. Because I need to print those values inside my print function.
My add function contains struct GraphicElement *pElements;, struct GraphicElement *pSecond;, struct Point point;.
I allocate memory using malloc for each struct and then add the values and then I pass the final values into pImage. All my other functions work perfectly besides the fact that I always end up with 3 memory leaks. Because I didnt not free(pSecond);....free(pElement)...free(line);
If I try to free them before my function exits and after passing the values into pImage. My values all get erased.
How can I free those values inside my add function locally?
struct Point
{
int x, y;
};
struct Line
{
Point start;
Point end;
};
struct GraphicElement
{
enum{ SIZE = 256 };
unsigned int numLines; //number of lines
Line* pLines; //plines points to start and end
char name[SIZE];
};
typedef struct
{
unsigned int numGraphicElements;
GraphicElement* pElements; //the head points to pLines
} VectorGraphic;
void InitVectorGraphic(VectorGraphic*); //initializes pImage->pElement
void AddGraphicElement(VectorGraphic*); //Used to add
void ReportVectorGraphic(VectorGraphic*); // prints pImage contents
void CleanUpVectorGraphic(VectorGraphic*); //deallocates memory
How can I free those values inside my add function locally?
It is not possible to explicitly free a memory allocated locally. Nor to locally free some memory. Once freed, a memory slot cannot be accessed and the data stored inside are lost.
In C, you have two option to allocate some memory: you can allocate it on the heap or on the stack. The memory slots reserved on the heap can be accessed globally and will remain until they are explicitly freed. The one reserved on the stack are only valid while you stay within the context they were created.
Let's say you execute the following code :
void func()
{
int x = 3; // [2]
int * p = & x; // [3]
}
int main()
{
func(); // [1]
// [4]
return 0;
}
The instruction [2] will allocate some memory on the stack. The second one ([3]) will do the same and will store the address of the of the first variable in the new memory slot. After the function returns ([4]), this memory is freed. Graphically, here is what happens :
Context STACK Address
+---------+
| | 0xa1
main | | 0xa0
+---------+
[1] +---------+
=====> | |
func | | 0xa2
+---------+
| | 0xa1
main | | 0xa0
+---------+
[2] +---------+
=====> | |
func | 3 | 0xa2 <-- x
+---------+
| | 0xa1
main | | 0xa0
+---------+
[3] +---------+
=====> | 0xa2 | 0xa3 <-- p
func | 3 | 0xa2 <-- x
+---------+
| | 0xa1
main | | 0xa0
+---------+
[4] +---------+
=====> | | 0xa1
main | | 0xa0
+---------+
So if i use malloc inside a function. Once I exist the function the allocated memory on the heap is freed automatically?
It's the opposite. If you use, a function like malloc, the memory slot will be allocated on the heap. So if we change the line [3] above to something like
int * p = malloc(sizeof(int)); // [3]
The memory allocated on the stack will be freed as you'll leave the function, but the memory allocated on the heap will remain allocated and will still be accessible, until you free it. Graphically :
HEAP Address Free (y/n)
+---------+
| | 0xb4 - Yes
| | 0xb3 - Yes
+---------+
Context STACK Address
[3] +---------+ +---------+
=====> | 0xb4 | 0xa3 <-- p | | 0xb4 - No
func | 3 | 0xa2 <-- x | | 0xb3 - Yes
+---------+ +---------+
| | 0xa1
main | | 0xa0
+---------+
[4] +---------+ +---------+
=====> | | 0xa1 | | 0xb4 - No !!! Leak !!!
main | | 0xa0 | | 0xb3 - Yes
+---------+ +---------+
As you can see, after you leave the function, you have a memory leak as you don't have any pointer to the dynamically allocated memory. One way to avoid this is to return the pointer (so to pass the address of the new memory slot to the calling function) or to store it somewhere to free it later. It's also possible to allocate the memory before calling the function and to pass it to the function as a parameter. It really depends on your application.
I'm testing shallow copy for struct with this code:
#include "stdio.h"
#include "conio.h"
int main() {
struct str {
char * name;
int value;
};
struct str str_1 = {"go", 255};
struct str str_2;
str_2 = str_1;
str_1.name = "back";
printf("%s\n",str_1.name);
printf("%s\n",str_2.name);
printf("\n");
system("pause");
return 0;
}
I expected the result should be:
back
back
But it was:
back
go
Edit: I expected that because with shallow copy, str_1.name and str_2.name should always point to same place.
Edit: And with dynamic allocation, I got what I expected:
#include <stdio.h>
#include <conio.h>
#include <string.h>
int main() {
struct str {
char * name;
int value;
};
struct str str_1;
struct str str_2;
str_1.name = (char*) malloc(5);
strcpy(str_1.name,"go");
str_2 = str_1;
strcpy(str_1.name,"back");
printf("%s\n",str_1.name);
printf("%s\n",str_2.name);
printf("\n");
system("pause");
return 0;
}
The result is:
back
back
What was I misunderstand here ?
Take a piece of paper and draw what you think is happening at each step slowly, and this should become clear.
Let's draw struct str as so:
---------------------
| const char * name |
---------------------
| int value |
---------------------
And let's denote a string at address 0xabcdef10 as so:
--0xabcdef10---------------------
| "string\0" |
---------------------------------
So, when we initialise str_1, we need some memory location which will hold "go", lets call that 0xaaaaaa00
--0xaaaaaa00---------------------
| "go\0" |
---------------------------------
Then we initialise str_1 with a pointer to that:
struct str str_1 = {"go", 255};
--str_1---------------------------
| const char * name = 0xaaaaaa00 |
----------------------------------
| int value = 255 |
----------------------------------
Now we take a shallow copy of str_1, and call it str_2:
--str_2---------------------------
| const char * name = 0xaaaaaa00 |
----------------------------------
| int value = 255 |
----------------------------------
Next we execute str_1.name = "back";. As before, we first want to create the new string. Lets put that at 0xbbbbbb00:
--0xbbbbbb00---------------------
| "back\0" |
---------------------------------
Then we assign it to str_1.name, so str_1 now looks like:
--str_1---------------------------
| const char * name = 0xbbbbbb00 |
----------------------------------
| int value = 255 |
----------------------------------
Note that we haven't changed str_2.
So, when we look at our final "memory", we see:
--0xaaaaaa00---------------------
| "go\0" |
---------------------------------
....
--0xbbbbbb00---------------------
| "back\0" |
---------------------------------
....
--str_1---------------------------
| const char * name = 0xbbbbbb00 |
----------------------------------
| int value = 255 |
--str_2---------------------------
| const char * name = 0xaaaaaa00 |
----------------------------------
| int value = 255 |
----------------------------------
So str_1 points at the new string, and str_2 points at the old string.
In case you describe as dynamic, you never update the pointers in the struct, you could go through the same exercise to draw out what happens to memory in that case.
str_2 = str_1; did take a shallow copy.
But that doesn't mean that that any subsequent alteration to what name points to in str_1 will be automatically reflected in str_2.
(Really you should use const char* as the string type as you are assigning read-only string literals).
str_2 = str_1; makes a hard copy of the struct itself. For example the value member will be unique for every struct.
But you got a soft copy of any pointer members, since the copy does not affect the pointed-at data of any pointer. Meaning that after the copy, the name pointer of both str_1 and str_2 points at the literal "go".
And then str_1.name = "back"; only changes where str_1.name points at. It doesn't change where str_2.name points at.
When you used malloc and strcpy, you change the pointed-at data and get a complete hard copy of everything.
printf("%p\n\n", element); //0x1000020c0
table->head->element = element;
printf("%p\n\n", table->head->element); //0x1000020c0
I have a pointer to a struct which points to another struct where is char* variable is stored. The problem is a pointer(char * element) which is sent to this method is modified somewhere else, and I don't want those modifications to be affected in table->head->element. Simply said I want to make their values equal, not the reference.
I knew that we can assign same values to 2 pointers like this: *p1=*p2. However, I am not sure how to do that with structs, I tried:
*(table->head->element) = *element;
But it did not work.
I hope I could clarify my question.
If you want the pointed-to string by a copy, not simply a reference, you'll need to strcpy() it into some new memory. e.g.
int len = strlen(element);
table->head->element = malloc(len+1); // +1 for string-terminating null
strcpy(table->head->element, element);
(or use strdup() for a one-line solution, as pointed out in R Sahu's reply).
Responding to OP's comments in the answer by #GrahamPerks.
That will work, but I don't want using additional coping, because we can do it with pointer
Let's say the memory used by element looks like below:
element +---------+ +---+---+---+---+---+---+---+---+------+
| ptr1 | -> | a | | s | t | r | i | n | g | '\0' |
+---------+ +---+---+---+---+---+---+---+---+------+
If you use:
table->head->element = element;
the value of table->head->element is ptr1.
If some time later, you went ahead and changed the contents of ptr1 through element, such as by using:
fscanf(file, "%s", element);
You could end up with:
element +---------+ +---+---+---+---+---+---+---+---+---+---+------+
| ptr1 | -> | n | e | w | | s | t | r | i | n | g | '\0' |
+---------+ +---+---+---+---+---+---+---+---+---+---+------+
At that point, the string that you see from table->head->element is "new string", not "a string".
This is what happens when you don't copy the contents of element but just copy the pointer value of element.
If you want the value of table->head->element to remain "a string" while the value of element changes, you have to copy the contents of element using
int len = strlen(element);
table->head->element = malloc(len+1);
strcpy(table->head->element, element);
or, if your complier supports strdup, by using
table->head->element = strdup(element);