There are two issues in representing tabular data:
1. Representing a row
2. Representing many rows.
In your example, the row can be represented by:
struct Table_Record
{
unsigned char ip_address[4];
char domain_name[MAX_DOMAIN_LENGTH];
};
I've decided to use a fixed field length for the domain name. This will make processing simpler.
The next question is how to structure the rows. This is a decision you will have to make. The simplest suggestion is to use an array. However, an array is a fixed size and needs to be reallocated if there are more entries than the array size:
struct Table_Record table[MAX_ROWS];
Another data structure for the table is a list (single or double, your choice). Unfortunately, the C language does not provide a list data structure so you will have either write your own or obtain a library.
Alternative useful data structures are maps (associative arrays) and trees (although many maps are implemented using trees). A map would allow you to retrieve the value for a given key. If the key is the IP address, the map would return the domain name.
If you are going to read and write this data using files, I suggest using a database rather than writing your own. Many people recommend SQLite.