// Making a constant for things like this means that it can be changed in
// only one place rather than in several when needs evolve.
#define BUFSIZE 100
char buffer[BUFSIZE] = "abcdef";
char *str = buffer; // assign str to start of buffer
char *str2 = buffer + 3; // assign str2 to the "def" in buffer
char *str3 = &buffer[3]; // exactly the same as above
buffer[3] == 'd'; // buffer[3] is a char
strcmp(&buffer[3], "def") == 0; // &buffer[3] is a char *, so string
// No difference between a pointer to a character vs a string, except that
// in the latter case we are assuming there are more characters after the
// first one and they end with a null terminator ('\0')
// Two-dimensional array of characters.
char fields[NUMFIELDS][BUFSIZE];
// One-dimensional array of pointers to characters (strings). Note that
// none of these pointers actually point to storage until you set them
// to point to somewhere. These can point to existing strings that are
// stored elsewhere in some manner. The way this often works is there
// is an int variable that starts at zero and represents how many words
// in the array have been filled in. Often these are filled in dynamically
// as we shall soon learn. Of course, you need to check that this number
// never gets to be greater than or equal to MAXWORDS.
char *words[MAXWORDS];
// Pointer-to-pointer to char, which usually represents a pointer to an
// array of strings. This can be used when you don't know what the maximum
// is. Typically one starts with an array of N pointers, and if you use
// that up you can reallocate it to be twice as large. You need to track
// both how many words have been stored and also what the current capacity
// of the array is.
char **words2 = NULL;
// Weirdness of C:
// a[b] is the same as *(a + b) is the same as b[a]
// Note that one of a or b needs to be a pointer or array expression and the
// other an int expression.
// Two dimensional array of ints.
int nums[4][4] = {
{ 0, 2, 4, 6 },
{ 1, 3, 5, 7 },
{ 2, 4, 8, 16 },
{ 0, 0, 1, 1 },
};
// The above is really stored as one long sequence of int cells.
//
// nums:
// +---------------+---------------+---------------+---------------+
// +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
// | 0| 2| 4| 6| 1| 3| 5| 7| 2| 4| 8| 16| 0| 0| 1| 1|
// +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
// +---------------+---------------+---------------+---------------+
//
// The dimensionality of a multi-dimensional array controls how the
// offset calculations are made to find the element.
int main()
{
int *numptr = nums[2]; // pointer to int or more than one int
int (*arrptr)[4] = &nums[1]; // pointer to array of four ints, or ...
int *ptrs[] = { // array of pointers to int(s)
nums[1], &nums[2][1], &nums[0][1]
};
printf("%d\n", numptr[1]); // 4
printf("%d\n", arrptr[1][2]); // 8
// Produces
// 1 1
// 4 8
// 2 6
for (int i = 0; i < sizeof(ptrs) / sizeof(*ptrs); ++i) {
printf("%d %d\n", ptrs[i][0], ptrs[i][i]);
}
printf("%d\n", ptrs[2][10]); // 16
}
// Scanf is a little odd, because to store into a simple scalar variable
// like an int, you need to use the address-of operator:
scanf("%d", &number);
// But to store into an array, you just need the name of the array
// because it's already an address, and arrays are passed by reference.
scanf("%s", buffer);
// Note you can pass a pointer value as well, but beware because there has
// to be storage there which can hold whatever the user types.
// For this reason it is safer to use the "%99s" format, which gives the
// maximum number of chars to put into the buffer (a null is then appended,
// so it should be one less than the actual size of the buffer).