Logo  

CS351 - Computer Organization

Reading:

Arrays

Briefly an array is a sequence of similarly typed data under one name. Arrays can be single dimensional, like a column of data in a spreadsheet, 2 dimensional, like rows and columns in a spreadsheet or 3 or more dimensional. Most array we'll have to worry about are 1 or 2 dimensional.

Example:

int ar[5] = { 5, 2, 0, -10, 15 }; // An array of 5 integers

ar
index value reference
0 5 ar[0]
1 2 ar[1]
2 0 ar[2]
3 -10 ar[3]
4 15 ar[4]

Defining Arrays

Consider the simple one dimensional case. To define an array of 30 integers for example would look like:

int ar[30];

The grammar then for an array definition is:

data-type variable-name [ integer-size ]

The size of the array for each dimension is enclosed in square brackets ([]), thus for a 2-dimensional array, the grammar would be:

data-type variable-name [ integer-size ][ integer-size ]

So to define a 10 row by 20 column array of characters, would be:

char strs[10][20];

To assign a value to arrays while defining them, use a compound literal as described below. When assigning values to an array using a compound literal it is unecessary to specify the size of the array, as the size will be big enough to hold all the values in the compound literal, i.e.:

int ar[] = {1,2,3,4}; // ar will be 4 integers in size.

Array Indexes

To access or change data in an array, you provide a zero based index value to that location, i.e. the first location in the array is at index 0, the second at 1 and so on. Thus if an array is of size 10, the value index values for an array are 0 through 9.

Example:

char str[4];    // Defines space for 4 characters.

str[0] = 'H';   // The first character
str[1] = 'i';   // The second
str[2] = '!';   // The third
str[3] = '\0';  // The fourth, which is the null character, terminating the string.

printf("%s\n", str);
// Prints: Hi!

if (str[0] >= 'A' && str[0] <= 'Z')
  printf("The string starts with an upper-case letter\n");


If the index is negative or beyond the length of the array the result could be a program crash, most likely a segmentation fault, which is an attempt to access invalid memory by your program. It could also access the data stored in other variables, in other words, strange things could happen, so while programming in C, one needs to be careful with your indexes.

Compound Literals

A compound literal is a sequence of comma separated values enclosed in curly braces ({}). A compound literal is essentially an array, although they can also be used to initialize/represent structured data (yet to be talked about.)

Compound literals can be used to assign values to an array when its being defined, and can be used directly as an array, but usually require that they are cast to the correct type in order for the compiler to make sense of the data.

Examples:

// Sets all the elements of ar to 0. This is a special form just for initialization.
int ar[5] = {0};

int ar[5] = {1, 2, 3, 4, 5};
float ar[] = {5.0, 4.8, 3.14, 2.1, 1.1};
char hi[10] = {'H', 'i', '\0'};  // Size of the array can be bigger than the literal

for(int i=0; i < 5; i++)
  printf("%d\n", (int[]){5,4,3,2,1}[i]);
                 └──┬──┘└────┬────┘└─┴─ The index into the array
                    │        └───────── The compound literal as an array
                    └────────────────── The type-cast that makes it an integer array

Example of reading values into an array:

#include <stdio.h>

int main(void)
{
  int n = 0;        // This will store how many valid integers in 'values'
  int values[1000]; // A place for up to 1000 integers

  while(scanf("%d", &values[n]) == 1) {
    n++;
    // If we run out of space (1000 integers), stop reading numbers.
    if (n >= 1000) break;
  }
  // At this point n will be the number of valid integers in 'values', so we'll
  // print them out.
  for(int i=0; i < n; i++) {
    printf("%d: %d\n", i, values[i]);
  }

  return 0;
}

Strings:

Strings as we've seen are lists of characters enclosed in double quotes. In C these lists of characters are just a special form of character array with a null character at the end to terminate or signal the end of the string.

Each character in the string can be accessed individually by specifying the integer index inside of []'s that are appended to the variable name or string constant. i.e.:

str[i]

or:

"abc"[i]

Just like with arrays, the first character in a string is at index 0, the second at index 1, etc. If a string array has been allocated 20 characters, then only indexes 0-19 are valid (and one of those indexes needs to contain the null character ('\0') terminator character.)

The strlen() function will give us the length of a string:

int len = strlen(str);

would give us the length of str in characters (not counting the null character) and that length would then be saved in len.

Defining a string

#include <stdio.h>
int main(void)
{
  // 3 different ways to define a string:
  char  s1[] = "Hello 1";   // Array method 1
  char *s2   = "Hello 2";   // Pointer method (to be discussed later)
  char  s3[] = {'H', 'e', 'l', 'l', 'o', ' ', '3', '\0'}; // Array method 2
  // Note that the last way requires a null character ('\0') at the end.

  // The \" is so we can print a double quote inside of double quotes.
  printf("s1 = \"%s\"\n", s1);
  printf("s3 = \"%s\"\n", s3);
  printf("s2 = \"%s\"\n", s2);

  return 0;
}
// Outputs:
s1 = "Hello 1"
s2 = "Hello 2"
s3 = "Hello 3"

String array vs. String pointer

Without going to much into detail about what pointers are, a string pointer might look something like:

char *str = "Hello";

Note the * which defines the variable as a pointer. Pointers do not allocate space in memory for data, but merely point to data defined elsewhere. In the above example, the "Hello" string constant is defined in memory elsewhere and str is made to point to it. The data in the string constant can be accessed via str using the array indexes (e.g. str[0]), just like normal, however the data cannot be modified in this case (string constants are read-only data.)

String pointers can point to non-constant strings, and they are often the preferred method of passing strings to functions.

char buf[1024]; // A string array
char *p = buf;  // A string pointer pointing to the string array
// p and buf are now essentially the same string.

// This is essentially the strlen() function:
int strlen(char *s)
{
  int len = 0;
  while (s[len] != '\0') {
    len++;
  }
  return len;
}

String pointers can be incremented or decremented to make them point at the next or previous character, but we'll cover that sort of idea more in depth when we get to pointers.

Examples

int main(void)
{
  char strbuf[1000];

  // Reads a "word" (sequence of characters terminated by a space, newline or tab
  // character) into strbuf.  Note we don't use & for strings w/ scanf.
  while (scanf("%s", strbuf) == 1) {
    printf("The word read was: %s\n", strbuf);
  }
  return 0;
}


// Print each character in the string 's' one to a line:
void printchars(char *s)
{
  for(int i=0; s[i] != '\0'; i++) {
    printf("%c\n", s[i]);
  }
}


// Will print out the string 's' in reverse.  Starts at the last character
// (at index len-1) and decrements the index towards 0.
void reverse(char *s)
{
  int len = strlen(s);

  for(int i = len-1; i >= 0; i--) {
    printf("%c", s[i]);
  }
}