How to add data without pre-defining variables?
Use the EEPROM. This allows data to remain intact and unchanged even when power is disconnected.

As you say you're new to programming, and because I wrote a similar program just last week as an experiment for something bigger, I'll talk you through some of it. However, I'm not going to give you the whole code to copy-and-paste, I'm only going to give you information on dealing with EEPROM and structures. C-aficionados may grumble at some bits, and Arduinites at others - sic vita est. This is something of a crash-course so it's not gospel, but it should be more than enough to guide you. You may already know some or most of it; it's included nonetheless for completeness, for those who don't.



For those who don't know

In C, data relevant to an object can be stored in a structure, or struct. You can put all sorts of different types of data in a struct, like so:

struct personalProfile {
    char    firstName[8];
    char    lastName[8];
    uint    cardID;           // 'uint' is an unsigned int...
    bool    accessAllowed;
};


You can then use that structure to create a 'personal profile' for however many people you want:

// within your main program:

struct personalProfile Person1;
struct personalProfile Person2;

// Now you can directly access individual aspects as so:

Person1.firstName = "John";
Person1.lastName = "Brown";
Person1.accessAllowed = TRUE;

Person2.firstName = "Dodgy";
Person2.lastName = "Dave";
Person2.accessAllowed = NOT_A_HOPE_IN_HELL;


You can use the members of a structure in exactly the same way you'd use that member type if it wasn't part of a structure. Nice and easy.

The best way to store multiple instances of a particular variable type is in an array:

struct personalProfile listOfPeople[5];


You now have an array of five (blank) structs, which can be accessed by listOfPeople[n].firstName = Potato;, where 'n' is between 0 and the number-of-entries-minus-one. So far so potato.

An array is pretty basic. It's present in all sorts of programming languages because it's inherently essential to almost any program, but the trouble is that it's static. Using the code above, once the array has been created with five structs in it you can't add or remove any. One solution is to create a massive array, and set all the values in each struct to zero, or some other 'empty' identifier, so you're always going to have enough entries (up to a point). However, that's lazy, time inefficient (you've got to set aaaaalll the individual elements to your 'empty' signifier), resource inefficient (look at all that unused space!), and the data only lasts while the program is running. As soon as you cut the power to the Arduino, the information is lost.

Next comes containers. These are part of the Standard Template Library (STL) in C++. They're great for creating and managing dynamic-length arrays. There are different types for different purposes (see the link), but they don't exist in C (at least as far as this post is concerned) and they're not available as part of the Arduino IDE without installing a bunch of libraries or some other intervention. Therefore you've got to make your own version. It's actually pretty easy...



EEPROM basics

The EEPROM library that comes with Arduino is of course essential for this. It doesn't have many functions, and the ones that exist are fantastically easy to understand. EEPROM, for those who don't know, is non-volatile memory. That means that when you store data it stays there forever, even if you remove the power. The only way to get rid of the data is to write over it. The downside of EEPROM is that it has limited amount of times it can be written to - 100,000 times per bit typically so you don't need to start keeping count, it just means you shouldn't be using it as regular program memory. Reading data from EEPROM isn't limited in the same manner.

Using the function EEPROM.put(address, data) you can put ANY data type - an int, char or - you guessed it - a struct into the EEPROM, starting at the byte specified by address. Of course there has to be enough space so you can't put an int, which takes up more than 1-byte of space, into the last address without the function failing. (Or can you? I haven't tried it yet because I'd never do it in practice.)

So you've created your structure, and made sure that all it's members are a fixed size. That means the structure has a fixed size. If you know that size, you can start putting them into the EEPROM.

// within main program

struct personalProfile Person1;
struct personalProfile Person2;

// fill in the details for Person 1...
// fill in the details for Person 2...

// ...then put Person1 in the EEPROM at address 0.
EEPROM.put(0, Person1);

// Done. Now put in Person2. But where?
// You need to make sure you put them AFTER Person1.

int AddressJump = sizeof(personalProfile);

// AddressJump now equals how many bytes are need to store one person.

EEPROM.put(AddressJump, Person2);


Simple as that.

If you create a Person3, you're going to need to put them sizeof(personalProfile) bytes AFTER Person2, i.e. EEPROM.put(AddressJump*2, Person3);. So, you add PersonN to address AddressJump * (N-1).

Retrieving data is the same principle, except you use EEPROM.get():

// provided you've used the above snippet somewhere to actually
// populate the EEPROM with something!

struct personalProfile personA;

EEPROM.get(0, personA);

Serial.print("Person A is called:");
Serial.println(personA.firstName);


Again, you're going to need sizeof(personalProfile) to read the second, third, or Nth person. If you 'send EEPROM.get() to the wrong address it will still populate the personalProfile instance with data, it will just be gobbledygook. Once you start putting people in the EEPROM you're going to need to keep track of things otherwise you'll end up lost. You need to manage the list to make sure you don't put one person on top of another (you could get in trouble for that) and you don't want to get someone that isn't there.



List management

This is where I leave you, for now. When you have digested the information above, and you want to continue, I'll carry on.

Your first task is to determine what sort of array you want. Inevitably it's going to be a Linked List. This is an array of structs, where each struct element in the list contains the memory address of the following element, thus the list is linked. You need to consider:


How the array will be linked (if at all);
Whether or not the array is space-critical (does it have to be as small as possible);
Where the array is going to start;
How you're going to keep track of how many people are in the array.


@TL140 I await your response, good luck!