Problem with passing array of pointers to struct among functions in C - c

The Code that follows segfaults on the call to strncpy and I can't see what I am doing wrong. I need another set of eyes to look it this. Essentially I am trying to alloc memory for a struct that is pointed to by an element in a array of pointers to struct.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_POLICY_NAME_SIZE 64
#define POLICY_FILES_TO_BE_PROCESSED "SPFPolicyFilesReceivedOffline\0"
typedef struct TarPolicyPair
{
int AppearanceTime;
char *IndividualFile;
char *FullPolicyFile;
} PolicyPair;
enum {
bwlist = 0,
fzacts,
atksig,
rules,
MaxNumberFileTypes
};
void SPFCreateIndividualPolicyListing(PolicyPair *IndividualPolicyPairtoCreate )
{
IndividualPolicyPairtoCreate = (PolicyPair *) malloc(sizeof(PolicyPair));
IndividualPolicyPairtoCreate->IndividualFile = (char *)malloc((MAX_POLICY_NAME_SIZE * sizeof(char)));
IndividualPolicyPairtoCreate->FullPolicyFile = (char *)malloc((MAX_POLICY_NAME_SIZE * sizeof(char)));
IndividualPolicyPairtoCreate->AppearanceTime = 0;
memset(IndividualPolicyPairtoCreate->IndividualFile, '\0', (MAX_POLICY_NAME_SIZE * sizeof(char)));
memset(IndividualPolicyPairtoCreate->FullPolicyFile, '\0', (MAX_POLICY_NAME_SIZE * sizeof(char)));
}
void SPFCreateFullPolicyListing(SPFPolicyPair **CurrentPolicyPair, char *PolicyName, char *PolicyRename)
{
int i;
for(i = 0; i < MaxNumberFileTypes; i++)
{
CreateIndividualPolicyListing((CurrentPolicyPair[i]));
// segfaults on this call
strncpy((*CurrentPolicyPair)[i].IndividualFile, POLICY_FILES_TO_BE_PROCESSED, (SPF_POLICY_NAME_SIZE * sizeof(char)));
}
}
int main()
{
SPFPolicyPair *CurrentPolicyPair[MaxNumberFileTypes] = {NULL, NULL, NULL, NULL};
int i;
CreateFullPolicyListing(&CurrentPolicyPair, POLICY_FILES_TO_BE_PROCESSED, POLICY_FILES_TO_BE_PROCESSED);
return 0;
}

Problem is in the prototype of function:
...
void SPFCreateIndividualPolicyListing(PolicyPair *IndividualPolicyPairtoCreate )
{
...
The function gets a NULL pointer value, sets it to a valid location by malloc but doesn't in any way return it to calling function.
It should be
...
void SPFCreateIndividualPolicyListing(PolicyPair **IndividualPolicyPairtoCreate )
{
*IndividualPolicyPairtoCreate = malloc (...);
...

void SPFCreateIndividualPolicyListing(PolicyPair *IndividualPolicyPairtoCreate )
{
IndividualPolicyPairtoCreate = (PolicyPair *) malloc(sizeof(PolicyPair));
That just assigns to the local IndividualPolicyPairtoCreate variable - C is pass by value, not pass by reference. You're leaking memory, and the caller won't see any changes to the struct you're passing in.
Change that function to e.g. return the newly allocated memory, and instead of
CreateIndividualPolicyListing((CurrentPolicyPair[i]));
Do
CurrentPolicyPair[i] = CreateIndividualPolicyListing();

Because I can't read your code with its excessively long variable and function names, I've rewritten the offending function as follows. So, my first suggestion is: use shorter variable names.
void create_policies(SPFPolicyPair **policies, char *name, char *newname) {
int i;
for(i = 0; i < MaxNumberFileTypes; i++) {
create_policy(policies[i]);
strncpy((*policies)[i].IndividualFile, POLICY_FILES_TO_BE_PROCESSED, SPF_POLICY_NAME_SIZE);
}
}
There are multiple problems with this code.
First, as others have pointed out, create_policy(policies[i]) can not change the value of policies[i] because C is purely pass by value. Write it as
polices[i] = create_policy();
and change create_policy to return the address of policy pair it allocates.
Second, (*policies)[i].IndividualFile is wrong. It should be
(*policies[i]).IndividualFile
or even better
policies[i]->IndividualFile.
Third, you don't use name or newname.
Problem (1) and (2) will both lead to segfaults. Problem (3) indicates either that you've been trying to strip this code down to understand the segfault, or that you're not sure exactly what this function should do.
The rest of this post explains the second bug and its fix in more detail.
You have correctly passed in policies as a pointer to the first element of an array of SPFPolicyPair *s. So, very roughly
policies --> [ ptr0 | ptr1 | ptr2 | ... ]
Each ptri value is a SPFPolicyPair *. There are two ways to interpret such a value: (a) the base of an array of SPFPolicyPair objects, or (b) a pointer to a single such object. The language itself doesn't care which interpretation your using, but in your case, by looking at how you've initialized the policies array, it's clearly case (b).
So, how does the evaluation ((*policies)[i]).IndividualFile go wrong?
*policies returns ptr0 from the diagram above.
That value is now subscripted, as ptr0[i].
The first indication of trouble is that you're only ever using policies[0], and then treating this value, ptr0, as a pointer to the first element of an array of full-sized policy pair objects, eg,
ptr0 -> [ ppair0 | ppair1 | ppair2 | ... ]
This is the array you're indexing. Except that ptr0 does not point to a sequence of policy pair objects, it points to exactly one such object. So, as soon as i is greater than zero, you're off referencing undefined memory.
The revised expression, policies[i]->IndividualFile, works like this:
policies[i] is equivalent to *(policies + i), and returns one of ptr0, ptr1, etc.
ptri->IndividualFile is equivalent to (*ptri).IndividualFile, and returns the base address of the file name for the ith policy pair.

Related

Assign array without element by element copy?

I have a function which creates an array, of say, size 5.
Is it possible for the function to accept a pointer (or maybe it needs a pointer to a pointer?) and then point said pointer at an array, so that when the callee then looks at the pointer, it can see all values of the array.
Something along the lines of this (except this will not work):
#define LENGTH 5
void assignArray(int *pointer)
{
int arr[LENGTH] = {0,1,2,3,4};
// Point the pointer at the array, without manually copying each element
pointer = arr;
}
void main()
{
int *pointer;
pointer = malloc(sizeof(int) * LENGTH);
assignArray(pointer);
int i;
for (i = 0 ; i < LENGTH ; i++) printf("%d\n", pointer[i]);
}
C assign array without element by element copy
In C, arrays (compile-time allocated) cannot be assigned. You need to copy the elements from one array to another.
To avoid element-by-element copy, you can copy the whole array all at a time using library function.
I'm not very sure what you want to ask here, but it seems, you need to do memcpy() to achieve your goal.
If you have a secondary array arr to copy from, you can write
memcpy( pointer, arr, ( (sizeof arr[0]) * LENGTH ));
The code to do what you are describing might look like:
#define LENGTH 5
void assignArray(int **pp)
{
static int arr[LENGTH] = {0,1,2,3,4};
// Point the pointer at the array, without manually copying each element
*pp = arr;
}
int main()
{
int *pointer;
assignArray(&pointer);
for (int i = 0 ; i < LENGTH ; i++)
printf("%d\n", pointer[i]);
}
Note that one does not simply point *pp at a non-static local variable arr. That is because int arr[] = .... would go out of scope when assignArray returns.
If you want each call to assignArray to "return" a different array then of course you will have to allocate space and use memcpy each time you want to make a copy of the original array.
int arr[LENGTH] = {0,1,2,3,4}; will be stack allocated, so attempting to return the pointer to any of its elements will give you undefined behaviour as the whole thing will be out of scope when the function returns.
If you want to change what a pointer is pointing to then use 2 levels of indirection ** (i.e. pass a pointer to a pointer). You'll need to allocate the array arr on the heap using malloc or something similar.
As you are trying to do it, it is not possible due to the fact that your local arr is saved to the stack and is cleaned up after the function assignArry finished. As already mentioned you need to memcpy.
This answer will have two parts:
As mentioned in other answers, this is now how you're supposed to do it. A common construct in similar code is:
void assignArray(int *dest, size_t size)
{
int i;
// initialize with some data
for (i=0; i<size; i++)
dest[i] = i;
}
This way you're not wasting space and time with an intermediate buffer.
Second part of this answer is about wrapping arrays in a struct. It's a silly trick, that in a way achieves exactly what you asked, and also something that you probably don't want because of extra data copying.
Example code:
#include <stdio.h>
#include <stdlib.h>
#define LENGTH 5
struct foo { int arr[LENGTH]; };
struct foo assignArray()
{
struct foo bar = { .arr = {0,1,2,3,4} };
/* return the array wrapper in struct on stack */
return bar;
}
int main()
{
struct foo *pointer;
pointer = malloc(sizeof(*pointer));
*pointer = assignArray(); /* this will copy the data, not adjust pointer location */
int i;
for (i = 0 ; i < LENGTH ; i++) printf("%d\n", pointer->arr[i]);
return 0;
}

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.

C using malloc and duplicating array

I am supposed to follow the following criteria:
Implement function answer4 (pointer parameter and n):
Prepare an array of student_record using malloc() of n items.
Duplicate the student record from the parameter to the array n
times.
Return the array.
And I came with the code below, but it's obviously not correct. What's the correct way to implement this?
student_record *answer4(student_record* p, unsigned int n)
{
int i;
student_record* q = malloc(sizeof(student_record)*n);
for(i = 0; i < n ; i++){
q[i] = p[i];
}
free(q);
return q;
};
p = malloc(sizeof(student_record)*n);
This is problematic: you're overwriting the p input argument, so you can't reference the data you were handed after that line.
Which means that your inner loop reads initialized data.
This:
return a;
is problematic too - it would return a pointer to a local variable, and that's not good - that pointer becomes invalid as soon as the function returns.
What you need is something like:
student_record* ret = malloc(...);
for (int i=...) {
// copy p[i] to ret[i]
}
return ret;
1) You reassigned p, the array you were suppose to copy, by calling malloc().
2) You can't return the address of a local stack variable (a). Change a to a pointer, malloc it to the size of p, and copy p into. Malloc'd memory is heap memory, and so you can return such an address.
a[] is a local automatic array. Once you return from the function, it is erased from memory, so the calling function can't use the array you returned.
What you probably wanted to do is to malloc a new array (ie, not p), into which you should assign the duplicates and return its values w/o freeing the malloced memory.
Try to use better names, it might help in avoiding the obvious mix-up errors you have in your code.
For instance, start the function with:
student_record * answer4(const student_record *template, size_t n)
{
...
}
It also makes the code clearer. Note that I added const to make it clearer that the first argument is input-only, and made the type of the second one size_t which is good when dealing with "counts" and sizes of things.
The code in this question is evolving quite quickly but at the time of this answer it contains these two lines:
free(q);
return q;
This is guaranteed to be wrong - after the call to free its argument points to invalid memory and anything could happen subsequently upon using the value of q. i.e. you're returning an invalid pointer. Since you're returning q, don't free it yet! It becomes a "caller-owned" variable and it becomes the caller's responsibility to free it.
student_record* answer4(student_record* p, unsigned int n)
{
uint8_t *data, *pos;
size_t size = sizeof(student_record);
data = malloc(size*n);
pos = data;
for(unsigned int i = 0; i < n ; i++, pos=&pos[size])
memcpy(pos,p,size);
return (student_record *)data;
};
You may do like this.
This compiles and, I think, does what you want:
student_record *answer4(const student_record *const p, const unsigned int n)
{
unsigned int i;
student_record *const a = malloc(sizeof(student_record)*n);
for(i = 0; i < n; ++i)
{
a[i] = p[i];
}
return a;
};
Several points:
The existing array is identified as p. You want to copy from it. You probably do not want to free it (to free it is probably the caller's job).
The new array is a. You want to copy to it. The function cannot free it, because the caller will need it. Therefore, the caller must take the responsibility to free it, once the caller has done with it.
The array has n elements, indexed 0 through n-1. The usual way to express the upper bound on the index thus is i < n.
The consts I have added are not required, but well-written code will probably include them.
Altought, there are previous GOOD answers to this question, I couldn't avoid added my own. Since I got pascal programming in Collegue, I am used to do this, in C related programming languages:
void* AnyFunction(int AnyParameter)
{
void* Result = NULL;
DoSomethingWith(Result);
return Result;
}
This, helps me to easy debug, and avoid bugs like the one mention by #ysap, related to pointers.
Something important to remember, is that the question mention to return a SINGLE pointer, this a common caveat, because a pointer, can be used to address a single item, or a consecutive array !!!
This question suggests to use an array as A CONCEPT, with pointers, NOT USING ARRAY SYNTAX.
// returns a single pointer to an array:
student_record* answer4(student_record* student, unsigned int n)
{
// empty result variable for this function:
student_record* Result = NULL;
// the result will allocate a conceptual array, even if it is a single pointer:
student_record* Result = malloc(sizeof(student_record)*n);
// a copy of the destination result, will move for each item
student_record* dest = Result;
int i;
for(i = 0; i < n ; i++){
// copy contents, not address:
*dest = *student;
// move to next item of "Result"
dest++;
}
// the data referenced by "Result", was changed using "dest"
return Result;
} // student_record* answer4(...)
Check that, there is not subscript operator here, because of addressing with pointers.
Please, don't start a pascal v.s. c flame war, this is just a suggestion.

Changing pointer address in function

What do I need to change here so that animal contains {3,4}?
void funct(unsigned char *elf)
{
unsigned char fish[2]={3,4};
elf=fish;
}
int main()
{
unsigned char animal[2]={1,2};
funct(animal);
return 0;
}
EDIT: I see memcpy is an option. Is there another way just manipulating pointers?
Is there another way just manipulating pointers?
No, because animal is not a pointer. animal is an array. When you pass it as an argument to the function, it decays to a pointer to its first element, just as if you had said &animal[0].
Even if you use a pointer and take a pointer to it in funct, it still won't work:
void funct(unsigned char** elf)
{
unsigned char fish[2] = { 3, 4 };
*elf = fish; // oh no!
}
int main()
{
unsigned char animal[2] = { 1, 2 };
unsigned char* animal_ptr = animal;
funct(&animal_ptr);
}
After the line marked "oh no!" the fish array ceases to exist; it goes away when funct returns because it is a local variable. You would have to make it static or allocate it dynamically on order for it to still exist after the function returns.
Even so, it's still not the same as what you want because it doesn't ever modify animal; it only modifies where animal_ptr points to.
If you have two arrays and you want to copy the contents of one array into the other, you need to use memcpy (or roll your own memcpy-like function that copies array elements in a loop or in sequence or however).
Since animal decays to a pointer when passed to a function, you can replace:
elf=fish;
with:
elf[0] = fish[0]; // or: *elf++ = fish[0]
elf[1] = fish[1]; // *elf = fish[1]
or, assuming they're the same size:
memcpy (elf, fish, sizeof (fish));
Post question edit:
EDIT: I see memcpy is an option. Is there another way just manipulating pointers?
There is no safe way to do this by manipulating the pointers if you mean changing the value of the pointer itself. If you pass in a pointer to a pointer, you can change it so that it points elsewhere but, if you point it at the fish array, you're going to get into trouble since that goes out of scope when you exit from funct().
You can use the pointer to transfer characters as per my first solution above (elf[n] array access is equivalent to *(elf+n) pointer access).
One option is to assign the elements individually:
void funct(unsigned char *elf){
elf[0] = 3;
elf[1] = 4;
}
Another option is to use memcpy (which requires including string.h):
void funct(unsigned char *elf){
unsigned char fish[2]={3,4};
memcpy(elf, fish, 2);
}
memcpy takes as parameters the destination, the source, and then the number of bytes to copy, in this case 2.
void funct(unsigned char *elf) {
unsigned char fish[2]={3,4}; // stack variable, will dissapear after the function is exited
// elf=fish; this one assigns to the local copy of elf, that will also dissapear when we return
memcpy(elf, fish, sizeof(fish)); // so we have to copy values
// careful though, because sizeof(fish) can be bigger than sizeof(elf)
}
To help deal with maintenance issues, you're probably better off making a function that returns the pointer you want, and then making sure you've really freed any memory from the original array first.
unsigned char * func()
{
unsigned char * fish = malloc( sizeof(unsigned char) * 2 );
fish[0] = 3;
fish[1] = 4;
return fish;
}
int main ( void )
{
unsigned char * animal = malloc( sizeof(unsigned char) * 2 );
animal[0] = 1;
animal[1] = 2;
free( animal );
animal = func();
}
Trying to reassign an array declared using the 'unsigned char animal[2]' syntax is asking for trouble because it's put the entire original array on the stack, and even if the compiler allowed you to do that, you'd end up with a chunk of unusable memory on the stack. I don't design programming languages, but that feels very wrong.

C vector as char *** vector

A function I need to use requires a vector argument for return storage with the following signature:
char ***vvar
What am I supposed to pass in there?
How do I access elements afterward?
Let's say you want a function that creates a vector of strings. You might define it and call it like this:
#include "stdio.h"
#include "stdlib.h"
void make_vector(char*** vvar)
{
/* We're going to create a vector of strings. */
char** vector = malloc(sizeof(char*) * 3 );
vector[0] = "Hello";
vector[1] = "world!";
vector[2] = NULL;
/* Now we give the address of our vector to the caller. */
*vvar = vector;
}
int main(void)
{
char** vector_of_strings = NULL;
make_vector(&vector_of_strings);
printf("%s\n", vector_of_strings[0]);
return 0; /* Memory leak is an exercise for the reader. :-) */
}
(In this example it would be simpler to have make_vector return the array, but in a more complex example it's reasonable to pass the address of vector_of_strings.)
I will assume that the vector will contain strings, as that makes the most sense with the signature you describe.
As you also did not give any code, I will assume the function you need to call looks similar to this:
/* This function creates a vector with room for 'length' strings and places it in 'vvar' */
void create_string_vector(int /* in */ length, char*** /* out */ vvar);
As the function expects to be able to change vvar and have that change reflected in the caller, you must pass the address of some variable, so the call should look like
create_string_vector(my_length, &my_var);
That takes care of one level of pointers.
This leaves just the question of how to declare my_var. As it will be a vector, or array, of unknown size, you need to declare it as a pointer. And a string is also a kind of array of unknown size of characters, so you need a pointer for that as well. This leads to the declaration
char* *my_var;
Element access is the easy part: You can treat my_var just as an array:
my_var[0] = "Hello";
This is not a vector by the looks of it.
If the function signature is somethings like function(...,char ***vvar,...), then your solution is not simple.
You need to know how much buffer space you need in each dimension, then create the complicated array as follows:
int dim_1 = 5, dim_2 = 4, dim_3 = 10;
char ***buffer = malloc(sizeof(char**)*dim_1);
for (int i=0;i++;i<dim_1) {
char **buffer_2 = malloc(sizeof(char*)*dim_2);
for (int j=0;j++;j<dim_2) {
char *buffer_3 = malloc(dim_3);
buffer_2[j] = buffer_3;
}
buffer[i] = buffer_2;
}

Resources