-1

I have an application to work, where i need to use an array of structure type as a member of structure . I have created models with structure but as you can see I need a member as an array inside the contact structure(dynamically depending on the user's input). I am allocating the size for it in the getContacts function by passing a variable named contactPersonLength from main,but as soon as the getContacts returns to main value of contactPersonLength variable changes and garbage value gets printed in main. So i am having trouble passing the varible to print function. Please tell me where i am wrong and how to allocate size for array which is a structure member

struct address
{
    char *name,*street,*district;
    int doorNo;
};

struct contactPerson
{
    char *name,*contactNumber;
};

struct contact
{
    char *firstName,*lastName,*emailId;
    struct address billingAddress;
    struct address shippingAddress;
    struct contactPerson contactPersons[];
};

void getContacts(struct contact *contacts,int n,int contactPersonLength)
{
    int isSame,i,j;
    for(i=0;i<n;i++)
    {
        printf(".......Enter Contact Details %d  ........\n",i+1);
        contacts[i].firstName = (char *)malloc(sizeof(char));
        printf("Enter the First Name");
        scanf("%s",contacts[i].firstName);

        contacts[i].lastName = (char *)malloc(sizeof(char));
        printf("Enter the Last Name");
        scanf("%s",contacts[i].lastName);

        contacts[i].emailId = (char *)malloc(sizeof(char));
        printf("Enter the email id");
        scanf("%s",contacts[i].emailId);

        printf(".....Billing address Details.....\n");
        contacts[i].billingAddress.name = (char *)malloc(sizeof(char));
        printf("Enter the name");
        scanf("%s",contacts[i].billingAddress.name);

        printf("Enter the DoorNo");
        scanf("%d",&contacts[i].billingAddress.doorNo);

        contacts[i].billingAddress.street = (char *)malloc(sizeof(char));
        printf("Enter the Street name");
        scanf("%s",contacts[i].billingAddress.street);


        contacts[i].billingAddress.district = (char *)malloc(sizeof(char));
        printf("Enter the District");
        scanf("%s",contacts[i].billingAddress.district);

        printf(".....Shipping Address Details....\n");
        printf("Is your Shipping Address same as Billing Address Press 1 Or else Press 0");
        scanf("%d",&isSame);
        if(isSame==1)
        {
            contacts[i].shippingAddress = contacts[i].billingAddress;
        }
        else
        {
            contacts[i].shippingAddress.name = (char *)malloc(sizeof(char));
            printf("Enter the name");
            scanf("%s",contacts[i].shippingAddress.name);

            printf("Enter the DoorNo");
            scanf("%d",&contacts[i].shippingAddress.doorNo);

            contacts[i].shippingAddress.street = (char *)malloc(sizeof(char));
            printf("Enter the Street name");
            scanf("%s",contacts[i].shippingAddress.street);

            contacts[i].shippingAddress.district = (char *)malloc(sizeof(char));
            printf("Enter the District");
            scanf("%s",contacts[i].shippingAddress.district);
        }

        printf(" ContactPersonLength %d \n",contactPersonLength);
        contacts[i].contactPersons[contactPersonLength];
        for(j=0;j<contactPersonLength;j++)
        {
            printf(".....ContactPerson %d.....\n",j+1);
            contacts[i].contactPersons[j].name = (char *)malloc(sizeof(char));
            printf("Enter Contact Person Name");
            scanf("%s",contacts[i].contactPersons[j].name);

            contacts[i].contactPersons[j].contactNumber = (char *)malloc(sizeof(char));
            printf("Enter Contact Person Contact Number");
            scanf("%s",contacts[i].contactPersons[j].contactNumber);
        }
    }

}



void main()
{   
    struct contact contacts[n];

    getContacts(contacts,n,contactPersonLen);
}
Sibi
  • 1
  • In C, a string is an array of characters with a NUL byte at the end. The line `contacts[i].firstName = (char *)malloc(sizeof(char));` allocates only enough room for the NUL byte and nothing else. – user3386109 Aug 05 '18 at 16:59
  • input is working fine only problem i have is that if i allocate the array size for contactPerson member in getContacts function and when it returns contactsPersonLength variable gets filled with garbage value – Sibi Aug 05 '18 at 17:03
  • 1
    That's the thing about [undefined behavior](https://en.wikipedia.org/wiki/Undefined_behavior). Just because your code appears to work doesn't mean it's correct. – user3386109 Aug 05 '18 at 17:06
  • You had bad luck that `scanf` didn't segfaulted as @user3386109 mentioned. Using `scanf` without bound checks `nParsed = scanf("%SIZEs");` is potentially dangerous. Either fix it or use char Arrays instead. (Where `SIZE` is an actual number of your allocated size-1 to store the NUL) – Inrin Aug 05 '18 at 17:07
  • 1
    You can read more about undefined behavior [here](https://stackoverflow.com/questions/33797630) and [here](https://stackoverflow.com/questions/2397984) – user3386109 Aug 05 '18 at 17:08
  • Possible duplicate of [C flexible arrays vs pointers](https://stackoverflow.com/questions/34249886/c-flexible-arrays-vs-pointers) – Inrin Aug 05 '18 at 17:36

2 Answers2

3

I would suggest that your function should work as follows:

char buffer[256];
for(i=0;i<n;i++)
{
    printf(".......Enter Contact Details %d  ........\n",i+1);
    do {
        printf("Enter the First Name");
    } while (scanf("%255s",buffer)!=1);
    contacts[i].firstName = malloc(strlen(buffer)+1);
    strcpy(contacts[i].firstName, buffer);
    //...etc

So you use a single buffer to get the input, then allocate memory exactly the size of the input, plus a terminating null character, then copy the buffer to that memory and reuse the buffer for the next input.

Notes: the size of a char is always 1, so sizeof(char) is not needed. Also, the result of malloc should not be cast.

You ask the input in a do...while loop and check that scanf was able to read input. In scanf, the format specifier limits the input to 255 characters so the buffer will not overflow.

Paul Ogilvie
  • 25,048
  • 4
  • 23
  • 41
  • Could you also answer the actual main question, how to allocate space for the flexible array member in the flexible struct? – Inrin Aug 05 '18 at 17:58
0

(char *)malloc(sizeof(char)); allocates only one byte of memory. If you want to store a string, say 20 chars long, the code is: (char *)malloc(sizeof(char) * 20 + 1); //explicitly showed +1 for clarity, based on comment.


EDIT

Generally it is a good idea to set the maximum possible size of the array in malloc. But if the size is too large, and/or you are concerned about memory, do the following:

contacts[i].firstName = (char *)malloc(sizeof(char) * MAX_POSSIBLE_SIZE);
printf("Enter the First Name");
scanf("%s",contacts[i].firstName);
char *temp = (char *)realloc(contacts[i].firstName, strlen(contacts[i].firstName) + 1);
if(temp!=NULL)  contacts[i].firstName = temp;

Do this for every string.

Susmit Agrawal
  • 3,649
  • 2
  • 13
  • 29
  • 2
    ..plus 1 for the terminating null character! – Paul Ogilvie Aug 05 '18 at 17:06
  • Right, my mistake. – Susmit Agrawal Aug 05 '18 at 17:07
  • I don't know the exact size of the input from user ,so how can I handle it – Sibi Aug 05 '18 at 17:11
  • Generally this wastes a lot of memory and should be discouraged. Now it is just fixed strings that could have defined in the typedef. – Paul Ogilvie Aug 05 '18 at 17:25
  • The longest recorded Name in history was 746 letters long. (All names + Surname). [source](https://en.wikipedia.org/wiki/Hubert_Blaine_Wolfeschlegelsteinhausenbergerdorff,_Sr.) – Inrin Aug 05 '18 at 17:27
  • Okay thanks for the optimization.Kindly instruct me how to allocate memory for contactPerson which is an array inside the contact Structure – Sibi Aug 05 '18 at 17:27
  • `contacts[i].contactPersons = malloc(sizeof(struct contactPerson) * REQUIRED_NUMBER);` You should also change `contactPersons[]` to `*contactPersons` in the definition. – Susmit Agrawal Aug 05 '18 at 17:30