Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
0 views

Arrays in C Programming Language

The document provides an overview of arrays in C programming, explaining their structure, declaration, and usage for storing multiple values under a single name. It covers both one-dimensional and multi-dimensional arrays, including examples of how to access and manipulate their elements. Additionally, it discusses C-style strings, their characteristics, and functions for string manipulation, emphasizing the importance of proper memory management and avoiding buffer overflows.

Uploaded by

kisherno.webster
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
0 views

Arrays in C Programming Language

The document provides an overview of arrays in C programming, explaining their structure, declaration, and usage for storing multiple values under a single name. It covers both one-dimensional and multi-dimensional arrays, including examples of how to access and manipulate their elements. Additionally, it discusses C-style strings, their characteristics, and functions for string manipulation, emphasizing the importance of proper memory management and avoiding buffer overflows.

Uploaded by

kisherno.webster
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 22

Arrays in C Programming Language

Additional information can be found in the texts,


Understanding Computer Science for Advanced
Level 3rd Edition Chapter 6 page 103 and C How to
Program 5th Edition Chapter 6 page 208, Chapter
8 page 325.
Arrays are useful critters that often show up when
it would be convenient to have one name for a
group of variables of the same type that can be
accessed by a numerical index. For example, a tic-
tac-toe board can be held in an array and each
element of the tic-tac-toe board can easily be
accessed by its position (the upper left might be
position 0 and the lower right position 8). At heart,
arrays are essentially a way to store many values
under the same name. You can make an array out
of any data-type including structures and classes.

One way to visualize an array is like this:

[][][][][][]
Each of the bracket pairs is a slot in the array, and
you can store information in slot--the information
stored in the array is called an element of the
array. It is very much as though you have a group
of variables lined up side by side.

1
Let's look at the syntax for declaring an array.

int examplearray[100]; /* This declares an array */


This would make an integer array with 100 slots
(the places in which values of an array are stored).
To access a specific part element of the array, you
merely put the array name and, in brackets, an
index number. This corresponds to a specific
element of the array. The one trick is that the first
index number, and thus the first element, is zero,
and the last is the number of elements minus one.
The indices for a 100 element array range from 0
to 99. Be careful not to "walk off the end" of the
array by trying to access element 100!

What can you do with this simple knowledge? Let's


say you want to store a string, because C has no
built-in datatype for strings, you can make an array
of characters.

For example:

char astring[100];
will allow you to declare a char array of 100
elements, or slots. Then you can receive input into
2
it from the user, and when the user types in a
string, it will go in the array, the first character of
the string will be at position 0, the second
character at position 1, and so forth. It is relatively
easy to work with strings in this way because it
allows support for any size string you can imagine
all stored in a single variable with each element in
the string stored in an adjacent location--think
about how hard it would be to store nearly
arbitrary sized strings using simple variables that
only store one value. Since we can write loops that
increment integers, it's very easy to scan through a
string:

char astring[10];
int i = 0;
/* Using scanf isn't really the best way to do this;
we'll talk about that
in the next tutorial, on strings */
scanf( "%s", astring );
for ( i = 0; i < 10; ++i )
{
if ( astring[i] == 'a' )
{
3
printf( "You entered an a!\n" );
}
}
Let's look at something new here: the scanf
function call is a tad different from what we've
seen before. First of all, the format string is '%s'
instead of '%d'; this just tells scanf to read in a
string instead of an integer. Second, we don't use
the ampersand! It turns out that when we pass
arrays into functions, the compiler automatically
converts the array into a pointer to the first
element of the array. In short, the array without
any brackets will act like a pointer. So we just pass
the array directly into scanf without using the
ampersand and it works perfectly.

Also, notice that to access the element of the


array, we just use the brackets and put in the index
whose value interests us; in this case, we go from
0 to 9, checking each element to see if it's equal to
the character a. Note that some of these values
may actually be uninitialized since the user might
not input a string that fills the whole array--we'll
look into how strings are handled in more detail in
the next tutorial; for now, the key is simply to
understand the power of accessing the array using
a numerical index. Imagine how you would write
that if you didn't have access to arrays! Oh boy.

4
Multidimensional arrays are arrays that have more
than one index: instead of being just a single line
of slots, multidimensional arrays can be thought of
as having values that spread across two or more
dimensions. Here's an easy way to visualize a two-
dimensional array:

[][][][][]
[][][][][]
[][][][][]
[][][][][]
[][][][][]
The syntax used to actually declare a two
dimensional array is almost the same as that used
for declaring a one-dimensional array, except that
you include a set of brackets for each dimension,
and include the size of the dimension. For example,
here is an array that is large enough to hold a
standard checkers board, with 8 rows and 8
columns:

int two_dimensional_array[8][8];

5
You can easily use this to store information about
some kind of game or to write something like tic-
tac-toe. To access it, all you need are two
variables, one that goes in the first slot and one
that goes in the second slot. You can make three
dimensional, four dimensional, or even higher
dimensional arrays, though past three dimensions,
it becomes quite hard to visualize.

Setting the value of an array element is as easy as


accessing the element and performing an
assignment. For instance,

<arrayname>[<arrayindexnumber>] = <value>
for instance,

/* set the first element of my_first to be the letter c


*/
my_string[0] = 'c';
or, for two dimensional arrays

<arrayname>[<arrayindexnumber1>]
[<arrayindexnumber2>] = <whatever>;

6
Let me note again that you should never attempt
to write data past the last element of the array,
such as when you have a 10 element array, and
you try to write to the [10] element. The memory
for the array that was allocated for it will only be
ten locations in memory, (the elements 0 through
9) but the next location could be anything. Writing
to random memory could cause unpredictable
effects--for example you might end up writing to
the video buffer and change the video display, or
you might write to memory being used by an open
document and altering its contents. Usually, the
operating system will not allow this kind of reckless
behavior and will crash the program if it tries to
write to unallocated memory.

You will find lots of useful things to do with arrays,


from storing information about certain things under
one name, to making games like tic-tac-toe. We've
already seen one example of using loops to access
arrays; here is another, more interesting, example!

#include <stdio.h>

int main()
{

7
int x;
int y;
int array[8][8]; /* Declares an array like a
chessboard */

for ( x = 0; x < 8; x++ ) {


for ( y = 0; y < 8; y++ )
array[x][y] = x * y; /* Set each element to a
value */
}
printf( "Array Indices:\n" );
for ( x = 0; x < 8;x++ ) {
for ( y = 0; y < 8; y++ )
{
printf( "[%d][%d]=%d", x, y, array[x][y] );
}
printf( "\n" );
}
getchar();

8
}

What is a String?
Note that along with C-style strings, which are
arrays, there are also string literals, such as "this".
In reality, both of these string types are merely just
collections of characters sitting next to each other
in memory. The only difference is that you cannot
modify string literals, whereas you can modify
arrays. Functions that take a C-style string will be
just as happy to accept string literals unless they
modify the string (in which case your program will
crash). Some things that might look like strings are
not strings; in particular, a character enclosed in
single quotes, like this, 'a', is not a string. It's a
single character, which can be assigned to a
specific location in a string, but which cannot be
treated as a string. (Remember how arrays act like
pointers when passed into functions? Characters
don't, so if you pass a single character into a
function, it won't work; the function is expecting a
char*, not a char.)
To recap: strings are arrays of chars. String literals
are words surrounded by double quotation marks.

"This is a static string"

9
Remember that special sauce mentioned above?
Well, it turns out that C-style strings are always
terminated with a null character, literally a '\0'
character (with the value of 0), so to declare a
string of 49 letters, you need to account for it by
adding an extra character, so you would want to
say:

char string[50];
This would declare a string with a length of 50
characters. Do not forget that arrays begin at zero,
not 1 for the index number. In addition, we've
accounted for the extra with a null character,
literally a '\0' character. It's important to remember
that there will be an extra character on the end on
a string, just like there is always a period at the
end of a sentence. Since this string terminator is
unprintable, it is not counted as a letter, but it still
takes up a space. Technically, in a fifty char array
you could only hold 49 letters and one null
character at the end to terminate the string.

Note that something like

char *my_string;

10
can also be used as a string. If you have read the
tutorial on pointers, you can do something such as:

arry = malloc( sizeof(*arry) * 256 );


which allows you to access arry just as if it were an
array. To free the memory you allocated, just use
free:

For example:

free ( arry );
Using Strings
Strings are useful for holding all types of long
input. If you want the user to input his or her name,
you must use a string. Using scanf() to input a
string works, but it will terminate the string after it
reads the first space, and moreover, because scanf
doesn't know how big the array is, it can lead to
"buffer overflows" when the user inputs a string
that is longer than the size of the string (which acts
as an input "buffer").

There are several approaches to handling this


problem, but probably the simplest and safest is to
use the fgets function, which is declared in stdio.h.

11
The prototype for the fgets function is:

char *fgets (char *str, int size, FILE* file);


There are a few new things here. First of all, let's
clear up the questions about that funky FILE*
pointer. The reason this exists is because fgets is
supposed to be able to read from any file on disk,
not just from the user's keyboard (or other
"standard input" device). For the time being,
whenever we call fgets, we'll just pass in a variable
called stdin, defined in stdio.h, which refers to
"standard input". This effectively tells the program
to read from the keyboard. The other two
arguments to fgets, str and size, are simply the
place to store the data read from the input and the
size of the char*, str. Finally, fgets returns str
whenever it successfully read from the input.

When fgets actually reads input from the user, it


will read up to size - 1 characters and then place
the null terminator after the last character it read.
fgets will read input until it either has no more
room to store the data or until the user hits enter.
Notice that fgets may fill up the entire space
allocated for str, but it will never return a non-null
terminated string to you.

12
Let's look at an example of using fgets, and then
we'll talk about some pitfalls to watch out for.

For a example:

#include <stdio.h>

int main()
{
/* A nice long string */
char string[256];

printf( "Please enter a long string: " );

/* notice stdin being passed in */


fgets ( string, 256, stdin );

printf( "You entered a very long string, %s",


string );

13
getchar();
}
Remember that you are actually passing the
address of the array when you pass string because
arrays do not require an address operator (&) to be
used to pass their addresses, so the values in the
array string are modified.

The one thing to watch out for when using fgets is


that it will include the newline character ('\n') when
it reads input unless there isn't room in the string
to store it. This means that you may need to
manually remove the input. One way to do this
would be to search the string for a newline and
then replace it with the null terminator. What
would this look like? See if you can figure out a way
to do it before looking below:

char input[256];
int i;

fgets( input, 256, stdin );

for ( i = 0; i < 256; i++ )

14
{
if ( input[i] == '\n' )
{
input[i] = '\0';
break;
}
}

Here, we just loop through the input until we come


to a newline, and when we do, we replace it with
the null terminator. Notice that if the input is less
than 256 characters long, the user must have hit
enter, which would have included the newline
character in the string! (By the way, aside from this
example, there are other approaches to solving
this problem that use functions from string.h.)
Manipulating C strings using string.h
string.h is a header file that contains many
functions for manipulating strings. One of these is
the string comparison function.

int strcmp ( const char *s1, const char *s2 );

15
strcmp will accept two strings. It will return an
integer. This integer will either be:

Negative if s1 is less than s2.


Zero if s1 and s2 are equal.
Positive if s1 is greater than s2.
Strcmp performs a case sensitive comparison; if
the strings are the same except for a difference in
cAse, then they're countered as being different.
Strcmp also passes the address of the character
array to the function to allow it to be accessed.

char *strcat ( char *dest, const char *src );


strcat is short for "string concatenate";
concatenate is a fancy word that means to add to
the end, or append. It adds the second string to the
first string. It returns a pointer to the concatenated
string. Beware this function; it assumes that dest is
large enough to hold the entire contents of src as
well as its own contents.

char *strcpy ( char *dest, const char *src );

16
strcpy is short for string copy, which means it
copies the entire contents of src into dest. The
contents of dest after strcpy will be exactly the
same as src such that strcmp ( dest, src ) will
return 0.

size_t strlen ( const char *s );


strlen will return the length of a string, minus the
terminating character ('\0'). The size_t is nothing to
worry about. Just treat it as an integer that cannot
be negative, which is what it actually is. (The type
size_t is just a way to indicate that the value is
intended for use as a size of something.)

Here is a small program using many of the


previously described functions:

#include <stdio.h> /* stdin, printf, and fgets */


#include <string.h> /* for all the new-fangled
string functions */

/* this function is designed to remove the newline


from the end of a string

17
entered using fgets. Note that since we make this
into its own function, we
could easily choose a better technique for
removing the newline. Aren't
functions great? */
void strip_newline( char *str, int size )
{
int i;

/* remove the null terminator */


for ( i = 0; i < size; ++i )
{
if ( str[i] == '\n' )
{
str[i] = '\0';

/* we're done, so just exit the function by


returning */
return;
}
18
}
/* if we get all the way to here, there must not
have been a newline! */
}

int main()
{
char name[50];
char lastname[50];
char fullname[100]; /* Big enough to hold both
name and lastname */

printf( "Please enter your name: " );


fgets( name, 50, stdin );

/* see definition above */


strip_newline( name, 50 );

/* strcmp returns zero when the two strings are


equal */
19
if ( strcmp ( name, "Alex" ) == 0 )
{
printf( "That's my name too.\n" );
}
else
{
printf( "That's not my name.\n" );
}
// Find the length of your name
printf( "Your name is %d letters long", strlen
( name ) );
printf( "Enter your last name: " );
fgets( lastname, 50, stdin );
strip_newline( lastname, 50 );
fullname[0] = '\0';
/* strcat will look for the \0 and add the second
string starting at
that location */
strcat( fullname, name ); /* Copy name into
full name */
20
strcat( fullname, " " ); /* Separate the names
by a space */
strcat( fullname, lastname ); /* Copy lastname
onto the end of fullname */
printf( "Your full name is %s\n",fullname );

getchar();

return 0;
}
Safe Programming
The above string functions all rely on the existence
of a null terminator at the end of a string. This isn't
always a safe bet. Moreover, some of them,
noticeably strcat, rely on the fact that the
destination string can hold the entire string being
appended onto the end. Although it might seem
like you'll never make that sort of mistake,
historically, problems based on accidentally writing
off the end of an array in a function like strcat,
have been a major problem.

Fortunately, in their infinite wisdom, the designers


of C have included functions designed to help you

21
avoid these issues. Similar to the way that fgets
takes the maximum number of characters that fit
into the buffer, there are string functions that take
an additional argument to indicate the length of
the destination buffer. For instance, the strcpy
function has an analogous strncpy function

char *strncpy ( char *dest, const char *src, size_t


len );
which will only copy len bytes from src to dest (len
should be less than the size of dest or the write
could still go beyond the bounds of the array).
Unfortunately, strncpy can lead to one niggling
issue: it doesn't guarantee that dest will have a
null terminator attached to it (this might happen if
the string src is longer than dest). You can avoid
this problem by using strlen to get the length of src
and make sure it will fit in dest. Of course, if you
were going to do that, then you probably don't
need strncpy in the first place, right? Wrong. Now it
forces you to pay attention to this issue, which is a
big part of the battle.

22

You might also like