Re: Struct Array with Varying Size Structs--Clarification - c

I have a question regarding one of the solutions that was posted--the accepted one on this thread:
https://stackoverflow.com/a/4982586/5854333 .
I would have left a comment on it instead of starting a new question thread, but I do not currently have the experience necessary. The program indeed runs as promised and is similar to what I intend to actually implement, but I'm still confused as to whether there may be subtle memory issues in it.
For example, in the portion:
void addStringToHolder(stringHolder * holder, const char * string) {
char ** newStrings = realloc(holder->strings, newStringCount * sizeof(char *));
if (newStrings != NULL) {
holder->strings = newStrings;
}
}
(we are working in this function with the struct)
typedef struct {
int numberOfStrings;
char ** strings;
}stringHolder;
Can the double pointer strings really be modified in this function? I thought we always had to pass in a pointer to the thing we wanted to modify, rather than the thing itself. Wouldn't we have to pass in a triple pointer if we wanted to modify the double pointer?
Of course we are also passing in a pointer to the struct in the first place, so does that make this work? I think I'm getting lost in all of these pointers. A little clarity would be helpful. Hopefully understanding this case will allow me to understand the others.

Can the double pointer strings really be modified in this function?
Shortly, yes.
To elaborate:
A pointer in C is just a location in the memory, when you pass it to a function you simply tell the function where to preform its operation.
By passing in a pointer to the struct, we are calling all of its elements by reference, and thus we can modify any of its elements, including the double pointer strings.
Say we have a pointer to your struct stringHolder* h_ptr where:
typedef struct {
int numberOfStrings;
char ** strings;
}stringHolder;
Now using * to dereference the pointer(s) you can access every level:
h_ptr /*some adress in memory*/
*h_ptr /*the value stored in said adress (we know its a stringHolder)*/
using the syntax x->y instead of (*x).y for readability
h_ptr->numberOfStrings /*the integer value stored in this struct*/
h_ptr->strings /*a pointer to an array of C string pointers*/
*(h_ptr->strings) /*the first "string" in said array, same as saying
a pointer to the first char in the first "string"*/
**(h_ptr->strings) /*the first char of the first "string"*/
And with pointer arithmetic we can get wherever we want and modify the values (as long as we keep the C convention of null terminated strings)
*(h_ptr->strings + 1) /*the second "string" in strings array*/
*(*(h_ptr->strings + 2) + 4) /*the fifth char in the third "string"*/
and so on.

Related

Misunderstanding in particular user case of pointers and double-pointers

I'm dealing with pointers, double-pointers and arrays, and I think I'm messing up a bit my mind. I've been reading about it, but my particular user-case is messing me up, and I'd appreciate if someone could clear a bit my mind. This is a small piece of code I've built to show my misunderstanding:
#include <stdio.h>
#include <stdint.h>
void fnFindValue_vo(uint8_t *vF_pu8Msg, uint8_t vF_u8Length, uint8_t **vF_ppu8Match, uint8_t vF_u8Value)
{
for(int i=0; i<vF_u8Length; i++)
{
if(vF_u8Value == vF_pu8Msg[i])
{
*vF_ppu8Match = &vF_pu8Msg[i];
break;
}
}
}
int main()
{
uint8_t u8Array[]={0,0,0,1,2,4,8,16,32,64};
uint8_t *pu8Reference = &u8Array[3];
/*
* Purpose: Find the index of a value in u8Array from a reference
* Reference: First non-zero value
* Condition: using the function with those input arguments
*/
// WAY 1
uint8_t *pu8P2 = &u8Array[0];
uint8_t **ppu8P2 = &pu8P2;
fnFindValue_vo(u8Array,10,ppu8P2,16); // Should be diff=4
uint8_t u8Diff1 = *ppu8P2 - pu8Reference;
printf("Diff1: %u\n", u8Diff1);
// WAY 2
uint8_t* ppu8Pos; // Why this does not need to be initialized and ppu8P2 yes
fnFindValue_vo(u8Array,10,&ppu8Pos,64); // Should be diff=6
uint8_t u8Diff2 = ppu8Pos - pu8Reference;
printf("Diff2: %u\n", u8Diff2);
}
Suppose the function fnFindValue_vo and its arguments cannot be changed. So my purpose is to find the relative index of a value in the array taking as reference the first non-zero value (no need to find it, can be hard-coded).
In the first way, I've done it following my logic and understanding of the pointers. So I have *pu8P2 that contains the address of the first member of u8Array, and **ppu8P2 containing the address of pu8P2. So after calling the funcion, I just need to substract the pointers 'pointing' to u8Array to get the relative index.
Anyway, I tried another method. I just created a pointer, and passed it's address, without initializing the pointer, to the funcion. So later I just need to substract those two pointers and I get also the relative index.
My confusion comes with this second method.
Why ppu8Pos does not have to be initialized, and ppu8P2 yes? I.e. Why couldn't I declare it as uint8_t **ppu8P2;? (it gives me Segmentation fault).
Which of the two methods is more practical/better practice for coding?
Why is it possible to give the address to a pointer when the function's argument is a double pointer?
Why ppu8Pos does not have to be initialized, and ppu8P2 yes
You are not using the value of ppu8Pos right away. Instead, you pass its address to another function, where it gets assigned by-reference. On the other hand, ppu8P2 is the address of ppu8Pos you pass to another function, where its value is used, so you need to initialise it.
Which of the two methods is more practical/better practice for coding
They are identical for all intents and purposes, for exactly the same reason these two fragments are identical:
// 1
double t = sin(x)/cos(x);
// 2
double s = sin(x), c = cos(x);
double t = s/c;
In one case, you use a variable initialised to a value. In the other case, you use a value directly. The type of the value doesn't really matter. It could be a double, or a pointer, or a pointer to a pointer.
Why is it possible to give the address to a pointer when the function's argument is a double pointer?
These two things you mention, an address to a pointer and a double pointer, are one and the same thing. They are not two very similar things, or virtually indistinguishable, or any weak formulation like that. No, the two wordings mean exactly the same, to all digits after the decimal point.
The address of a pointer (like e.g. &pu8P2) is a pointer to a pointer.
The result of &pu8P2 is a pointer to the variable pu8P2.
And since pu8P2 is of the type uint8_t * then a pointer to such a type must be uint8_t **.
Regarding ppu8Pos, it doesn't need to be initialized, because that happens in the fnFindValue_vo function with the assignment *vF_ppu8Match = &vF_pu8Msg[i].
But there is a trap here: If the condition vF_u8Value == vF_pu8Msg[i] is never true then the assignment never happens and ppu8Pos will remain uninitialized. So that initialization of ppu8Pos is really needed after all.
The "practicality" of each solution is more an issue of personal opinion I believe, so I leave that unanswered.
For starters the function fnFindValue_vo can be a reason of undefined behavior because it does not set the pointer *vF_ppu8Match in case when the target value is not found in the array.
Also it is very strange that the size of the array is specified by an object of the type uint8_t. This does not make a sense.
The function should be declared at least the following way
void fnFindValue_vo( const uint8_t *vF_pu8Msg, size_t vF_u8Length, uint8_t **vF_ppu8Match, uint8_t vF_u8Value )
{
const uint8_t *p = vF_pu8Msg;
while ( p != vF_pu8Msg + vF_u8Length && *p != vF_u8Value ) ++p;
*vF_ppu8Match = ( uint8_t * )p;
}
The difference between the two approaches used in your question is that in the first code snippet if the target element will not be found then the pointer will still point to the first element of the array
uint8_t *pu8P2 = &u8Array[0];
And this expression
uint8_t u8Diff1 = *ppu8P2 - pu8Reference;
will yield some confusing positive value (due to the type uint8_t) because the difference *ppu8P2 - pu8Reference be negative.
In the second code snippet in this case you will get undefined behavior due to this statement
uint8_t u8Diff2 = ppu8Pos - pu8Reference;
because the pointer ppu8Pos was not initialized.
Honestly, not trying to understand your code completely, but my advice is do not overcomplicate it.
I would start with one fact which helped me untangle:
if you have int a[10]; then a is a pointer, in fact
int x = a[2] is exactly the same like int x = *(a+2) - you can try it.
So let's have
int a[10]; //this is an array
//a is a pointer to the begging of the array
a[2] is an int type and it is the third value in that array stored at memory location a plus size of two ints;
&a[2] is a pointer to that third value
*(a) is the first value in the array a
*(a+1) is the same as a[1] and it is the second int value in array a
and finally
**a is the same as *(*a) which means: *a is take the first int value in the array a (the same as above) and the second asterisk means "and take that int and pretend it is a pointer and take the value from the that location" - which is most likely a garbage.
https://stackoverflow.com/questions/42118190/dereferencing-a-double-pointer
Only when you have a[5][5]; then a[0] would be still a pointer to the first row and a[1] would be a pointer to the second row and **(a) would then be the same as a[0][0].
https://beginnersbook.com/2014/01/2d-arrays-in-c-example/
Drawing it on paper as suggested in comments helps, but what helped me a lot is to learn using debugger and break points. Put a breakpoint at the first line and then go trough the program step by step. In the "watches" put all variants like
pu8P2,&pu8P2,*pu8P2,**pu8P2 and see what is going on.

What does int * and double ** mean for elements outside the C function's arguments?

I am learning C language and doing a lot of practice. I understand that * and ** are pointers in .c function.
Please consider the following function (another .c function)
void pcc(int* n, int* d, int* family, int* type, double* par, double* nu, double* out)
{
int i, j, in=1, k, **fam;
double *w, **v, t, **theta, **x, **ny;
…some works
}
My question is, why do we use the pointer in the argument of the function? Because as I understand we use the pointer to point the previous identifed elements.
Also, why do we use pointer for some elements that are not already defined in the arguments of the function. For example, in the last function we define a new element after writing the argument of the function:
int i, j, in=1, k, **fam;
double *w, **v, t, **theta, **x, **ny;
For instance, double *w was not in the argument of the function! also **v and other elements. How do we know they must get ** or *.
Any help please?
The reasons for declaring a variable a * or ** are countless, it's better to try and get a grip of what they actually mean instead of getting hung up on why they're used in this specific instance.
A pointer * is a reference to a memory location where a value is stored. In the case of a char it is a reference to a single memorylocation holding a byte, and in the case of an int it's usually 4 bytes on a 32bit system.
You can pass a pointer as an argument to indicate this is where you want the result to be stored. Another reason might be efficiency. If you have a very large struct it's better to pass a 4byte (on a 32bit system) reference to the area of memory where the struct lies instead of loading the entire struct on the stack.
A ** is a double pointer. It is pointing to a specific memory location that itself is storing the memory location of something else.
char a[5];
Here, the variable a is actually a char * pointing at the first element of a[], namely a[0].
char a[5][5];
Here a is a char **, pointing to the first element of a[][], namely a[0], which will return a char * pointing at a[0][0].
The second example is better when you want to fiddle with the pointers. Maybe you have a char** (an 'Array of strings'), and you want to replace one of the 'strings' (a string is just a char[] in c), you simply change the char* pointed to by the char**).
I hope this makes it a little clearer for you.
Pointers are used when we want the location of a value, as opposed to just the value. Now why would we want this? One simple scenario is actually illustrated in your question. In c, it is often inconvenient (if not impossible) to return more than one value from a function. An easy way to get around that is with pointers! When you pass arguments into a function normally, for example
int myFunction(int some_parameter);
you are actually passing a copy of some_parameter into your function. When the function returns, the original value of some_parameter is unchanged. But what if we want to change some_parameter in the function? We pass a pointer to the value instead. This allows us to directly change the value of some_parameter at its original memory location, instead of a copy. So as you can see, if we instead had
void myFunction(int* parameter1, int* parameter2) {
*parameter1 = 1;
*parameter2 = 2;
}
When you exit the function, your values parameter1 and parameter 2 will be 1 and 2 respectively, even though you never actually returned a value!
Pointers are one of the most useful and difficult parts about c, and I recommend you consult the other sources that others have selected in order to learn more about them.
In C you traditionally use pointers to modify variables that were declared at a different scope than the one of your function.
Pointers to pointers (**) though, are usually used when you want to manipulate those addresses in some way.
Now as for you question:
How do we know they must get ** or *?
Well it depends on what you want to do with the data. If you want to manipulate the value you only need a pointer; if you want to manipulate the address you may need a pointer to a pointer.

function with a struct array pointer as an argument, C language

typedef struct {
char manufacturer[SIZE];
char model[SIZE];
int size;
int id;
int qty;
double cost;
double price;
} tv;
void firstSix(tv *tvarr[]);
void firstSix(tv *tvarr[])
{
(*tvarr[0]).manufacturer = "Vizio";
}
I am making an inventory program. It consists of an array of structs that will store information about different televisions. In my program I am required to hardcode six entries into the array, so I am trying to make a function that will take a struct array pointer argument. In the above code, I included the struct declaration, the function prototype and function definition that I am trying to make. Everything is placed before and after main in the respective order. I don't understand why Visual Studio is highlighting the first parenthesis in the code inside the function definition and saying "expression must be a modifiable lvalue". I don't understand what it is that I am doing wrong. Please help.
You cannot assign an array like that. You need to do
strcpy ((*tvarr[0]).manufacturer, "Vizio");
Make sure that you don't go out of bounds when copying the string into the array.
You can either check the size of the string in advance or use strncpy which will limit the maximum number of characters to be copied.
An array is not a modifiable l-value. So basically you cannot have it on the left hand side of an assignment.
Or may be you also might want to define manufacture as char *manufacture and then dynamically allocate the string.
manufacturer = strdup ("Vizio"); //manufacturer is char *
Or depending on the length first allocate the buffer
manufacturer = malloc (sizeof (char) * needed_bytes);
Whenever you dynamically allocate the buffer, whenever you have finished working with it always remember to free it free (manufacturer).
I think you want to do something like
strncpy((tvarr[0])->manufacturer, "Vizio", SIZE - 1);
Kevin has it; you can't assign a string to a pointer, you must copy the data to the array. I suggest strncpy to keep from running off the end of the allocated space.

Better way of declaring an array?

I'm writing in C and compiling with GCC.
is there a better way of declaring points. I was surprised to see that points was an array. Is there some way of declaring points so it looks more like an array.
typedef struct Span
{
unsigned long lo;
unsigned long hi;
} Span;
typedef struct Series
{
unsigned long *points;
unsigned long count;
unsigned long limit;
} Series;
void SetSpanSeries(Series *self, const Span *src)
{
unsigned long *points;
if (src->lo < src->hi )
{
// Overlays second item in series.
points = self->points; // a pointer in self structure
points[0] = src->lo;
points[1] = src->hi;
self->count = 1;
}
}
Now lets say that points points to a structure that is an array.
typedef struct Span
{
unsigned long lo;
unsigned long hi;
} Span;
span *points[4];
now how do I write these lines of code? Did I get this right?
points = self->points; // a pointer in self structure
points[0].lo = src->lo;
points[0].hi = src->hi;
With the declaration unsigned long *points, points is a pointer. It points to the beginning of an array. arr[x] is the same as *(arr + x), so whether arr is an array (in which case, it takes the address of the array, adds x, and dereferences the 'pointer') or a pointer (in which case, it takes the pointer value, adds x, and dereferences the pointer), arr[0] still gets the same array access.
In this case, you can't declare points as an array because you're not using it as an array - you're using it as a pointer, which points to an array. A pointer is a shallow copy - if you change the data pointed to by a pointer, it changes the original data. To create a regular array, you'd need to do a deep copy, which would prevent your changes in pointer from affecting the array self, which is ultimately what you want.
In fact, you could rewrite the whole thing without points:
void SetSpanSeries(Series *self, const Span *src)
{
if (src->lo < src->hi )
{
self->points[0] = src->lo;
self->points[1] = src->hi;
self->count = 1;
}
}
As to your second example, yes, points[0].lo is correct. points->lo would also be correct, so long as you're only accessing points[0]. (Or self->points[0].lo if you take out points entirely.)
The ability to treat a pointer as an array definitely confuses most C beginners. Arrays even decay to pointers when passed as arguments to functions, giving the impression that arrays and pointers are completely interchangeable -- they aren't. An excellent description is in Expert C Programming: Deep C Secrets. (This is one of my favorite books; it's strongly recommended if you intend to understand C.)
Anyway, writing pointer[2] is the same as *(pointer+2) -- the array syntax is far easier for most people to read (and write).
Since you are using this *points variable to provide easier access to another block of memory (the pointer points in the struct Series), you cannot use an array for your local variable because you cannot re-assign the base of an array to something else. Consider the following illegal code:
int foo[10];
int *bar;
int wrong[10];
bar = foo; /* fine */
wrong = foo; /* compile error -- cannot assign to the array 'wrong' */
Another option for re-writing this code is to remove the temporary variable:
if (src->lo < src->hi) {
self->points[0] = src->lo;
self->points[1] = src->hi;
self->count = 1;
}
I'm not sure the temporary variable helps with legibility -- it just saved typing a few characters at the expense of adding a lot of characters. (And a confusing variable, too.)
In the middle section you say points is an array 4 of pointer to struct span. In the third section you are assigning points from self->points (meaning the previous value of points, that array, has been lost). You then dereference points as if it were an array of struct Span and not an array of pointers to struct Span.
In other works, this cannot compile because you are mixing types and even if you were not, you are overwriting the memory allocated by your definition of the points variable.
Providing the definition of Series might help explain what is going on.
But certainly in the first example, points should probably be a Span *points but without seeing Series we cannot tell for sure.

Using pointers with functions and structs

Hello i'm selfstudying C and i'm a bit confused about the following code since i don't know if i'm understanding the code properly. I would be very thankful if someone could read my explanation and correct me if i'm wrong.
The code is from a header file. The function of the program should be uninteresting at this point, since my comprehension problem is about the pointers and the values the functions give back. So first of all i'm declaring 3 arrays of char and an integer in my employee struct.
struct employee
{
char firstname[11];
char lastname[11];
char number[11];
int salary;
}
5 functions are declared in the header file. The first function takes 4 values (3 pointers and one int) and gives back a pointer to a struct. The second function gets a pointer to the "struct employee" and gives back a pointer to an element of the array "char firstname" in the struct employee. The functions 3 and 4 are doing the same for the other both arrays. The function 5 gets a pointer to the struct employee but gives back an int and not a pointer. So it is just using the declared variable in the struct.
struct employee* createEmployee(char*, char*, char*, int); //1
char* firstname (struct Employee*); //2
char* lastname (struct Employee*); //3
char* number (struct Employee*); //4
int salary (struct Employee*); //5
Your understanding is pretty much correct. To be a little more accurate and/or less abusive of the English language, functions 2-4 return a pointer to an element of the corresponding array.
The idea is that the contents of each array represent some kind of text, with each element corresponding a character of text, up until the first appearance of a zero value (used to mark the end of the "string"). Keep in mind that there is no provision for Unicode here, or even for specifying an encoding: we assume ASCII, and for any bytes not in the range 0..127, all bets are off. A better name for the type char would be byte; but we didn't really know any better back then. (You should also be aware that char is a separate type from both signed char and unsigned char, and that char may or may not be signed.)
This way, the names and number can be any length up to ten (an 11th byte is reserved in order to have room for the "null terminator" with the zero value), and the returned pointer can be used to inspect - and modify; but that might not be a good idea - the data in the arrays that are part of the Employee structure.
The int returned as the Employee 's salary is a copy of the one in the struct. So although we can see the whole value, this does not let us modify the value in the struct. Of course, as long as we have the struct definition and an Employee instance, there is no protection; we can access the member directly instead of going through the function.
In C, we get "encapsulation" and "data hiding" by not providing these definitions. Instead, we would just put struct Employee; and the function declarations in the header, and the struct definition in the implementation file. Now calling code doesn't know anything about what an Employee is; only about what it can do.
Almost right, except when you read the functions, the input "char*" should be read as a string is passed in though technically it is a pointer. for integers the actual value is passed, so you are right there.
so,
struct employee* createEmployee(char*, char*, char*, int);
would mean that the procedure creates a employee with the four inputs passed (the first three are strings (Char*) which probably are first name, last name and number/id in that order and the last one is the salary.)
What you cannot be sure by just reading the function signature whether the values/pointers returned are reference to same values/pointers from the sturct, or the function(s) is creating a copy and returning pointer to the new value. This is why its a good idea to also write the documentation as comments with the function signature in the header file.
Your explanations make sense, except #2-4: since they return char*, they cannot return an element of a char array (the correct type for the latter would be simply char). Each of the three functions returns a pointer to char. One presumes that they return the pointer to the first element of the corresponding array, which is basically how arrays are passed around in C.
There is a problem in 1. What you're doing I assume is:
struct employee* createEmployee(const char* f, const char* l, const char* n,
const int sal)
{
struct employee* e;
strcpy(e->firstname, f);
strcpy(e->lastname, l);
/* ... */
return e;
}
The problem here is the arrays coming in. It is perfectly feasible for a char array of any size to be passed in; anything over the length of 11 would cause you to start overwriting data at &(e->firstname[0])+11;. Over what? Exactly. You've no idea (and nor have I, it'd be determined at run-time). This could cause some serious problems.
One way around that is to use functions from stdlib.h and string.h i.e. strlen() to test the length of the data being passed in to ensure it fits your field size.
A better method might be to write:
int createEmployee(struct employee* e, const char* f, const char* l, const char* n,
const int sal)
{
int error = 0;
if ( strlen(f) < 11 )
{
strncpy(e->firstname, f);
}
else
{
error++;
}
/* ... */
return error;
}
See what I've done? Yes it will work - anything passed in as a pointer can be modified. It's not pass-by-reference, quite. Edit: as aix says, pointers are "how arrays are passed around in C".
Another potential method is strncpy() which will truncate the source string according to the last argument, so strncpy(e->firstname, f, 11); would be safe.
You might well try dynamic memory allocation for the field sizes based on requirement, too. I'm guessing you'll be learning that later/as another challenge.
Also, another suggestion whilst we're at it is to define the pointer to a struct using typedef. It makes things a little more readable although the way you've done it is definitely clearer for someone learning.

Resources