ThingWorx Edge C SDK > C SDK Data Structures and Types > twInfoTable
The twInfoTable is a non-ordered collection, composed of columns and rows. Infotables serve as the primary mechanism for sending data to and from ThingWorx platform. Data that is sent to ThingWorx Platform using an infotable is not guaranteed to be in any particular order. However, the Data Shape used to specify an infotable supports an ordinal that can be used to display values in a specific order, but not through the C SDK. Note that infotable properties store field values by key, not by index. The properties should be referenced by key and not by index.
Structure of a twInfoTable
A twInfoTable is essentially a self-describing collection of twPrimitive values. The structure of a twInfoTable follows:
typedef struct twInfoTable {
twDataShape * ds;
twList * rows;
uint32_t length;
} twInfoTable;
The ds element is a pointer to a twDatashape structure that describes what each field (column) of the table is – its name, description, and the base type of that field. The base type of a field can be any one of the base types described in ThingWorx Base Types (C SDK Details), including a twInfoTable, as the SDK and ThingWorx Platform allow nesting of these tables.
The rows element is a pointer to a list of values. Each entry in the list is a pointer to a twInfoTableRow structure. The twInfoTableRow structure contains values for each of the fields described in the Data Shape and must contain the values in the same order as in the Data Shape. The number of rows in an twInfoTable is a 32-bit value and therefore only practically limited to how much memory you wish to allow the twInfoTable to consume.
The length and mtx elements of the twInfoTable structure are for internal use and are typically not accessed directly. All the pointer elements of an infotable are owned and managed by the twInfoTable and should not be deleted or freed on their own.
Creating a twInfoTable
Creating an InfoTable is a three step process, as follows:
1. Create your Data Shape and add any necessary entries (fields) to the Data Shape.
twDataShapeEntry * twDataShapeEntry_Create(const char * name,
const char description, enum BaseType type);

twDataShape * twDataShape_Create(twDataShapeEntry * firstEntry);

int twDataShape_AddEntry(struct twDataShape * ds,
struct twDataShapeEntry * entry);
You must create a Data Shape to hold the schema for the twInfoTable before creating the table. Once the table is created, data is added one row at a time. When a row is created, data must be added to the row in the same order that it is in Data Shape. If the data is not added in the correct order, the table does not form correctly. There is no warning about this, and it becomes evident that the data is being added incorrectly only when a user views the data in ThingWorx Composer or a mashup that the data is being added incorrectly.
2. Create the twInfoTable, which requires its Data Shape to be passed in as a parameter.
twInfoTable * twInfoTable_Create(twDataShape * shape)
3. Add data to the twInfoTable by individually creating the rows and adding them to the it.
twInfoTableRow * twInfoTableRow_Create(twPrimitive * firstEntry)
int twInfoTableRow_AddEntry(twInfoTableRow * row, twPrimitive * entry)
int twInfoTable_AddRow(twInfoTable * it, twInfoTableRow * row)
Adding Ordinal to the Data Shape in the C SDK
If you want to display the data in an infotable in a particular order, you can add the ordinal aspect to the Data Shape, as follows:
1. Create the Data Shape entry, using twDataShapeEntry_Create(<name>,<descr>,<BaseType>);.
2. Create a twPrimitive to hold the ordinal value, using twPrimitive_CreateFromInteger(<ordinal>);.
3. Add the ordinal aspect, using twDataShapeEntry_AddAspect(<DataShapeEntry pointer>,"Ordinal",<twPrimitive pointer>);.
4. Create the Data Shape, using twDatashape_Create(), or add to an existing Data Shape, using twDataShape_AddEntry(), passing the DataShapeEntry pointer created above.
Helper Functions for twInfoTables
One very common pattern is a twInfoTable that contains a single field and a single row, for example the current value of a single property. The API provides several helper functions that make it easy to create these simple tables, using just a single function call.

twInfoTable * twInfoTable_CreateFromString(const char * name,
char * value, char duplicate);
twInfoTable * twInfoTable_CreateFromNumber(const char * name,
double value);
twInfoTable * twInfoTable_CreateFromInteger(const char * name,
int32_t value);
twInfoTable * twInfoTable_CreateFromLocation(const char * name,
twLocation * value);
twInfoTable * twInfoTable_CreateFromDatetime(const char * name,
DATETIME value);
twInfoTable * twInfoTable_CreateFromBoolean(const char * name,
char value);
twInfoTable * twInfoTable_CreateFromPrimitive(const char * name,
twPrimitive * value);
twInfoTable * twInfoTable_CreateFromBlob(const char * name,
char * value, int32_t length, char isImage, char duplicate);
Accessing data contained in a twInfoTable is also easy with several helper functions defined to assist with the common usage patterns. You simply pass in the name of the field and which row you wish to retrieve the value from.

int twInfoTable_GetString(twInfoTable * it, const char * name,
int32_t row, char ** value);
int twInfoTable_GetNumber(twInfoTable * it, const char * name,
int32_t row, double * value);
int twInfoTable_GetInteger(twInfoTable * it, const char * name,
int32_t row,int32_t * value);
int twInfoTable_GetLocation(twInfoTable * it, const char * name,
int32_t row, twLocation * value);
int twInfoTable_GetBlob(twInfoTable * it, const char * name,
int32_t row, char ** value, int32_t * length);
int twInfoTable_GetDatetime(twInfoTable * it, const char * name,
int32_t row, DATETIME * value);
int twInfoTable_GetBoolean(twInfoTable * it, const char * name,
int32_t row, char * value);
int twInfoTable_GetPrimitive(twInfoTable * it, const char * name,
int32_t row, twPrimitive ** value);