Problem with passing array of pointers to struct among functions in 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 * siz开发者_Python百科eof(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
returnsptr0
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 ofptr0
,ptr1
, etc.ptri->IndividualFile
is equivalent to(*ptri).IndividualFile
, and returns the base address of the file name for thei
th policy pair.
精彩评论