Thread: Assigning values to an array data types that are members of a structure in aFunctio

  1. #1
    Registered User
    Join Date
    Dec 2015
    Posts
    92

    Assigning values to an array data types that are members of a structure in aFunctio

    Hello everyone,
    I am trying to initiliaze Date struct fields that are array type in a function
    Date* new_Date(int day, int month, int year, int i)



    , but I don't know a proper way to do it

    This one doesn't work.
    Code:
    *dateObj = {
                    {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
                    {"Sunday", "Monday", "Tuesday", "Wednesday",
                        "Thursday", "Friday", "Saturday"
                    },
                  };


    Whole code

    Code:
    /**
     *  Date Class
     */
    typedef struct _Date Date;
    typedef int (*fptrGetDayOfWeek)(Date*, int, int, int);
    
    typedef struct _Date
    {
        int month[12];
        char* days[7];
        int nDay;
        int nMonth;
        int nYear;
        int i;
    
        fptrGetDayOfWeek getDayOfWeek;
    }Date;
    
    
    int Date_getDayOfWeek(Date* this, int day, int month, int year);
    
    Date* new_Date(int day, int month, int year, int i)
    {
        Date* dateObj = NULL;
        dateObj = (Date*)malloc(sizeof(Date));
        if (dateObj == NULL)
        {
            return NULL;
        }
        *dateObj = {
                    {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
                    {"Sunday", "Monday", "Tuesday", "Wednesday",
                        "Thursday", "Friday", "Saturday"
                    },
                  };
    
        if (day > 0 && day <= 7)
            dateObj->nDay = day;
        else
            dateObj->nDay = 0;
    
        if (month > 0 && month <= 31)
            dateObj->nMonth = month;
        else
            dateObj->nMonth = 0;
    
        if (year > 0)
            dateObj->nYear = year;
        else
            dateObj->nYear = 0;
    
        dateObj->getDayOfWeek = &Date_getDayOfWeek;
    }
    
    void delete_Date(Date* const dateObj)
    {
        free (dateObj);
        dateObj = NULL;
    }
    Thank you in advance.

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    This works if you compile in C99 mode.
    Code:
        *dateObj = (Date){
                    {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
                    {"Sunday", "Monday", "Tuesday", "Wednesday",
                        "Thursday", "Friday", "Saturday"
                    },
                  };
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    Dec 2015
    Posts
    92
    Quote Originally Posted by Salem View Post
    This works if you compile in C99 mode.
    Code:
        *dateObj = (Date){
                    {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
                    {"Sunday", "Monday", "Tuesday", "Wednesday",
                        "Thursday", "Friday", "Saturday"
                    },
                  };
    I am using GNU GCC compiler, I don't think I am allowed to compile in C99 mode because other old programs maybe would not compile in that case.

    I am getting following errors:

    Src/_Date.c: In function 'new_Date':
    Src/_Date.c:34:18: error: extra brace group at end of initializer
    Src/_Date.c:34:18: error: (near initialization for '(anonymous)')
    Src/_Date.c:34:18: warning: excess elements in struct initializer [enabled by default]
    Src/_Date.c:34:18: warning: (near initialization for '(anonymous)') [enabled by default]
    Src/_Date.c:35:18: error: extra brace group at end of initializer
    Src/_Date.c:35:18: error: (near initialization for '(anonymous)')
    Src/_Date.c:37:18: warning: excess elements in struct initializer [enabled by default]
    Src/_Date.c:37:18: warning: (near initialization for '(anonymous)') [enabled by default]


    I tried to do something similiar I would do in C++, declaring those fields to be static so I can be able to assign values to data fields.
    Code:
    typedef struct _Date
    {
        static const int month[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
        static const char* days[] =  {
                                 "Sunday", "Monday", "Tuesday", "Wednesday",
                                 "Thursday", "Friday", "Saturday"
                                };
        int nDay;
        int nMonth;
        int nYear;
        int i;
    
        fptrGetDayOfWeek getDayOfWeek;
    }Date;
    But I was getting:
    error: expected specifier-qualifier-list before 'static'

  4. #4
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    Well if you can't do it inline, then you need to create a separate dummy object.
    Code:
    static Date dateInitializer = {
                    {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
                    {"Sunday", "Monday", "Tuesday", "Wednesday",
                        "Thursday", "Friday", "Saturday"
                    },
                  };
    *dateObj = dateInitializer;
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  5. #5
    Registered User
    Join Date
    Dec 2015
    Posts
    92
    Alright I have another qeustion.

    After trying to call
    Code:
    nDayOfTheWeek = date->getDay(date, aDate);
    date->Delete(date);
    which are struct functions that are implemented via virtual function table in my struct Date
    I am getting the following error :

    error: dereferencing pointer to incomplete type
    error: dereferencing pointer to incomplete type

    Code:
    Date* date = Date_Create();
    nDayOfTheWeek = date->getDay(date, aDate);
    date->Delete(date);
    In Header File
    Code:
    typedef struct _Date Date;
    
    typedef uint16_t (*fPtrGetDay)(const Date* this, const uint16_t nDateLen, const char* pDate );
    
    uint16_t Date_GetDay(
        const Date* this,
        const uint16_t nDateLen,  ///< Length of date
        const char* pDate  ///< Pointer to date data
        )
    In C file
    Code:
    typedef struct _Date
    {
         ....
         fPtrGetDay    GetDay;
         ....
    }Date;
    In costructor
    Code:
    Date* Date_Create(void)
    {
        Date* dateObj;
        dateObj = (Date*)malloc(sizeof(Date));
        if (dateObj == NULL)
        {
            return NULL;
        }
        ....
        dateObj->GetDay             =    Date_GetDay;
        ....
        return dateObj;
    }
    Last edited by High Voltage; 03-22-2017 at 08:06 AM.

  6. #6
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    The struct needs to be declared in the header file.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  7. #7
    Registered User
    Join Date
    Dec 2015
    Posts
    92
    Thank you salem.
    So I can look at function pointers simply as data fields of the class/class variables?

    MyClass.h
    Code:
    class MyClass
    {
          private:
                 function_pointer_t pointerToAMethod;
                 function_pointer_t pointerToAnotherMethod;
                 int aIntegerVariable;
         public:
                 void someClassMethod(int);
    };

  8. #8
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    This is wrong:
    Code:
    void delete_Date(Date* const dateObj)
    {
        free (dateObj);
        dateObj = NULL;
    }
    Making the pointer constant is strange since you then try to assign NULL to it. And assigning NULL to it is pointless anyway since it's a local variable. Presumably you meant to say:
    Code:
    void delete_Date(Date **date)
    {
        free(*date);
        *date = NULL;
    }
    // call it like
    Date a_date;
    //...
    delete_Date(&a_date);
    Also, here:
    Code:
        static const char* days[];
    You presumably want to make not just the chars themselves const but also the pointers:
    Code:
        static const char * const days[];
    And what in the world is "i"? That's a terrible name for a struct member!

    It's actually kind of silly to put month (shouldn't it be months?) and days into the struct. That's not how it's done in C. Instead, make them static global objects in the date source file. That way they are private to the date functions and you don't have to initialize them in silly ways.

    Also, a consistent naming scheme would be a good idea. Probably the best scheme is to prefix the functions with the struct name (as you did with Date_getDayOfWeek) :
    Date_new, Date_delete, etc.

  9. #9
    Registered User
    Join Date
    Dec 2015
    Posts
    92
    Quote Originally Posted by algorism View Post
    This is wrong:

    Code:
    void delete_Date(Date **date)
    {
        free(*date);
        *date = NULL;
    }
    // call it like
    Date a_date;
    //...
    delete_Date(&a_date);
    Also, here:
    Code:
        static const char* days[];
    You presumably want to make not just the chars themselves const but also the pointers:
    Code:
        static const char * const days[];
    And what in the world is "i"? That's a terrible name for a struct member!

    It's actually kind of silly to put month (shouldn't it be months?) and days into the struct. That's not how it's done in C. Instead, make them static global objects in the date source file. That way they are private to the date functions and you don't have to initialize them in silly ways.

    Also, a consistent naming scheme would be a good idea. Probably the best scheme is to prefix the functions with the struct name (as you did with Date_getDayOfWeek) :
    Date_new, Date_delete, etc.
    Ignore i variable forgot to remove it and also accidentally put const in free function.

    I don't understand Why do you pass double pointer in free function instead of a single pointer?

    Also why should pointer to a char* be declared const?

  10. #10
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    I don't understand Why do you pass double pointer in free function instead of a single pointer?
    I was trying to make sense of your code. You were setting a local variable to NULL, which was pointless since it has no effect on the variable that the function was called with. I assumed you wanted to set the caller's variable to NULL, which is a common idiom.

    Also why should pointer to a char* be declared const?
    Because you presumably don't want the pointers to be changed.


    Here's some example code. To run it in one file, just comment out the includes of date.h.
    Code:
    // date.h ///////////////////////////////////////////////////
    
    #ifndef DATE_H_
    #define DATA_H_
    
    typedef struct {
        int year;  // 1800 and above (because of dayOfWeek)
        int month; // 1 to 12
        int day;   // 1 to max for month (and leap year status)
    } Date;
    
    Date *      Date_new        (int year, int month, int day);
    void        Date_delete     (Date **date);
    void        Date_print      (Date *date);
    int         Date_isLeapYear (Date *date);
    const char *Date_dayOfWeek  (Date *date);
    
    #endif
    
    
    // date.c ///////////////////////////////////////////////////
    
    #include "date.h"
    #include <stdio.h>
    #include <stdlib.h>
    
    static const char * const month_names[] = {
        "January",   "February", "March",    "April",
        "May",       "June",     "July",     "August",
        "September", "October",  "November", "December"
    };
    
    static const char * const day_names[] = {
        "Sunday", "Monday", "Tuesday", "Wednesday",
        "Thursday", "Friday", "Saturday"
    };
    
    static const int month_lengths[] = {
        31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
    };
    
    static int isLeapYear(int y) {
        return (y % 4 == 0 && y % 100 != 0) || y % 400 == 0;
    }
    
    int Date_isLeapYear(Date *date) {
        return isLeapYear(date->year);
    }
    
    // Somewhat cheesy day-of-week algorithm.
    // Only works from year 1800 on.
    // January 1, 1800 is a Wednesday (day 3)
    const char *Date_dayOfWeek(Date *date) {
        int y = date->year - 1800;
        int d = 3 + y * 365 + y / 4 - y / 100 + (y + 200) / 400;
        for (int m = 0; m < date->month - 1; m++)
            d += month_lengths[m];
        if (date->month <= 2 && isLeapYear(date->year))
            d--; // remove leap day that was added previously
        d += date->day - 1;
        return day_names[d % 7];
    }
    
    Date *Date_new(int year, int month, int day) {
        if (year < 1800) {
            printf("bad year\n");
            return NULL;
        }
        if (month < 1 || month > 12) {
            printf("bad month\n");
            return NULL;
        }
        if (day < 1 || day > month_lengths[month-1]
                             + (month==2 && isLeapYear(year))) {
            printf("bad day\n");
            return NULL;
        }
    
        Date *date = malloc(sizeof *date);
        date->year = year;
        date->month = month;
        date->day = day;
    
        return date;
    }
    
    void Date_delete(Date **date) {
        free(*date);
        *date = NULL;
    }
    
    void Date_print(Date *date) {
        printf("%s %d, %d\n", month_names[date->month - 1],
               date->day, date->year);
    }
    
    
    // main.c ////////////////////////////////////////////////
    
    #include <stdio.h>
    #include "date.h"
    
    int main() {
        Date *date = NULL;
        int y, m, d;
    
        printf("Enter year, month, day: ");
        scanf("%d %d %d", &y, &m, &d);
    
        date = Date_new(y, m, d);
        if (date == NULL)
            return 0;
    
        Date_print(date);
        printf("%s\n", Date_dayOfWeek(date));
    
        Date_delete(&date);
    
        return 0;
    }

  11. #11
    Registered User
    Join Date
    Dec 2015
    Posts
    92
    Thank you algorism,
    this line:

    Code:
        Date *date = malloc(sizeof *date);
    Why do you take sizeof pointer, I thought it should allocated like this
    Code:
    Date *date = malloc(sizeof(Date));

  12. #12
    Registered User
    Join Date
    Jun 2015
    Posts
    1,640
    date is a pointer to a Date.
    *date is a Date.
    So sizeof *date is the same as sizeof(Date).
    (Note that you only need the parentheses if you're using an actual type.)

    It's just a different way of doing the same thing, but it's better because of a situation where we change something like this:
    Code:
    int *a = malloc(size * sizeof *a);
    to this
    Code:
    long *a = malloc(size * sizeof *a);
    We only have to change the type in one place. If we used sizeof with the type then we'd have to change the type in two places and might forget to change one of them.

  13. #13
    Registered User
    Join Date
    Mar 2016
    Posts
    36
    Because date is a pointer to a Date structure as algorism mentioned.
    Maybe writing Date *date confused you.

    I also prefer writing
    Code:
    Date* date;
    int* integerPointer;
    seems more logical to me than

    Code:
    Date *date
    but it's a matter of style anyways.
    Last edited by ZeroesAndOnes; 03-27-2017 at 02:09 AM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Assigning values in array
    By newprogrammer32 in forum C Programming
    Replies: 2
    Last Post: 10-14-2011, 07:37 PM
  2. Re-Assigning Values To Array
    By Windu102 in forum C Programming
    Replies: 5
    Last Post: 08-21-2008, 09:57 AM
  3. Replies: 7
    Last Post: 07-31-2007, 09:27 AM
  4. static data members in structure
    By bhagwat_maimt in forum C++ Programming
    Replies: 9
    Last Post: 11-06-2006, 11:47 AM
  5. Dynamically assigning data-types
    By Morgan in forum C Programming
    Replies: 3
    Last Post: 03-30-2005, 10:14 AM

Tags for this Thread