Data Structures Part 1 (arrays)

advertisement
clark
cs1713
syllabus
lecture notes
programming assignments
Arrays
Arrays are very important in C.
 Subscripts begin with 0
 Character strings are implemented using arrays
 There can be multiple dimensions
 Initialization can be done with the declaration
 Automatically pass addresses when passed as function arguments
homework
set up
double dTemperatureM[]
= {45.0, 48.3, 52.1, 54.5, 62.0. 66.0, 72.3, 71.0, 70.3
,68.3, 66.3};
char dayWeekM[7][10] = { "Sunday", "Monday", "Tuesday"
, "Wednesday", "Thursday", "Friday", "Saturday" };
// Using a typedef for the day of the week */
typedef char DayOfWeek[10];
DayOfWeek dayWeekM[7] = { "Sunday", "Monday", "Tuesday"
, "Wednesday", "Thursday", "Friday", "Saturday" };
Exercise: Create and initialize and array named month which will contain the
3 character abbreviation for each month.
Multi-dimensional Arrays
Arrays can have many dimensions. You will more likely hit a limit in
addressable memory before you have too many dimensions.
C Arrays occupy contiguous memory and are stored in row-major order.
int iStuffM[3][2]
= { { 1, 2 }
, { 3, 4 }
, { 5, 6 } };
Showing it as two dimensional:
1
2
3
4
5
6
Showing it in contiguous memory:
1
2
3
4
5
int iA[4][3] =
{ {0,1,2}
, {10,11,12}
, {20,21,22}
, {30,31,32}};
Shown as two-dimensional:
Column 0
Column 1
Row 0
0
1
Row 1
10
11
Row 2
20
21
Row 3
30
31
Shown it in contiguous memory:
0
1
2
10
11
12
6
Three Dimensional Array Example
Suppose we want to represent a chess board where each piece is 2 characters
(plus a zero byte):
WQ - White Queen
WK - White King
WR - White Rook
[0][0]
[0][1]
first row
row 0
[0][2]
[1][0]
// Option 1
char chessBoard[8][8][3];
// Option 2
typedef char Piece[3];
Piece chessBoard[8][8];
[1][1]
[1][2]
second row
(row 1)
Column 2
2
12
22
32
20
21
22
30
31
[2][0]
[2][1]
third row
(row 2)
[2][2]
[3][0]
[3][1]
fourth row
(row 3)
WP - White Pawn
WN - White Knight
WB - White Bishop
// Option 3
typedef char Piece[3];
typedef Piece Board[8][8];
Board chessBoard;
How does a C compiler map an element reference to memory?
One dimensional:
 referencing element array[i]
 address of element array[i] =
addressOfFirstEntry + i * sizeof(anEntry)
// one dimensional
int iScoreM[5] = {80, 90, 75, 60, 95}
address 6800
80
90
75
60
95
Each element is 4 bytes (since int is 4 bytes)
Address of iScoreM[3] = addressOfFirstEntry + i * sizeof(anEntry)
Two dimensional:
 referencing element array[i][j]
 size of a row (we will call it rowSize) =
numberOfColumns * sizeof(anEntry)
 address of element array[i][j] =
addressOfFirstEntry + i * rowSize
+ j * sizeof(anEntry)
// two dimensional
int iStuffM[3][2]
= { { 1, 2 }
, { 3, 4 }
, { 5, 6 } };
= 6800 + 3 * 4 = 6812
Showing it as two dimensional:
1
2
3
4
5
6
Showing it in contiguous memory:
address 6820
1
2
3
4
5
6
rowSize = numberOfColumns * sizeof(anEntry)
= 2 * 4 = 8
Address of iStuffM[2][1] = addressOfFirstEntry + i * rowSize
+ j * sizeof(anEntry)
= 6820 + 2 * 8 + 1 * 4
= 6820 + 16 + 4 = 6840
More Examples of Initialization
int iCubeM[2][2][3]
={
{{000,001,002},{010,011,012}}
,{{100,101,102},{110,111,112}}
};
The function, memset(address, char, repetition) can be used to set the
contents of an array to a value.
char cDotM[20];
// option 1
memset(cDotM, '.', 20);
// option 2
memset(cDotM, '.', sizeof(cDotM));
/* iSampleM has 5 rows with 3 columns per row
** With this initialization, the first row is populated and
** then the second, and so on.
*/
int iSampleM[5][3]
= {10, 20, 30
,110, 120, 130
,210, 220, 230
,310, 320, 330
,410, 420, 430};
10
110
210
310
410
20
120
220
320
420
30
130
230
330
430
Since arrays are in contiguous memory, the array would look
like this in memory:
10
20
30
110
120
130
210
220
230
310
320
330
410
420
430
/* Same array, but the initialization specifies what is
** populated per row by using inner braces.
*/
int iSampleM[5][3]
= {{10, 20, 30}
,{110, 120, 130}
,{210, 220, 230}
,{310, 320, 330}
,{410, 420, 430}};
/* Using inner braces for each row, you don't have to populate
** the entire row.
*/
int iSampleM[5][3]
= {{10, 20, 30}
,{110, 120}
,{210, 220, 230}
,{310}
,{410, 420, 430}};
Does this initialize all elements of iSampleM to 0?
memset(iSampleM, 0, 15);
Why do subscripts in C, C++, and Java begin with 0?
Look at how addresses are calculated for an array entry.
Functions and Arrays
Arrays are automatically passed by address. C does not provide a mechanism
to allow a called function to know the dimensions of an array.
// Calling function
Passing Multi-Dimensional Arrays
Some languages (e.g., PL/I) can pass descriptors (which describe the
dimensions of an array) to functions. C only passes the starting address of an
array. For a two dimensional array, you must specify the number of columns.
You can also specify the number of rows.
// Calling function
int iValueM[10][5];
int iSum;
…
iSum = sum2dArray(iValueM, 10);
}
// code for sum2dArray function
In the function, sum2Darray (see to the right), what would be the result of
sizeof(iValueM) inside that function? At compile time, we don't know the size
of each dimension of iValueM in sum2dArray.
I wish the compiler would give an error. Both gcc and M/S VS give 4 (the size
of a pointer).
double dTemperatureM[]
= {45.0, 48.3, 52.1, 54.5, 62.0. 66.0, 72.3, 71.0, 70.3
,68.3, 66.3, 999};
double dAverage = calcAverage(dTemperatureM);
…
}
// Code for calcAverage function
double calcAverage(double dTemperatureM[])
{
int i;
double dSum = 0.0;
for (i = 0; dTemperatureM[i] != 999; i++)
dSum += dTemperatureM[i];
return dSum;
}
int sum2dArray(int iValueM[][5], int iRowCnt)
{
int i;
int j;
int isum = 0;
for (i = 0; i < iRowCnt; i++)
{
for (j = 0; j < 5; j++)
{
isum += iValueM[i][j];
}
}
return isum;
}
Using Typedefs for Multi-dimensional Arrays
For multi-dimensional arrays in C, we usually specify the size for each
dimension by using typedefs. This lets the complier know exactly how big the
array is.
Notice that bestMove (see example) returns a structure. In C, primitive types
and structures can be returned as functional results. C does not allow
functional results to be an array.
Assigning From one Array into Another
C doesn't support assignments from arrays to arrays using the assignment
operator "=".
Zero-Terminated strings use strcpy(szTo, szFrom). The number of bytes copied
is dependent on the '\0'.
Any array can be copied using memcpy(pTo, pFrom, iSize). It copies iSize bytes
from pFrom to pTo.
typedef
typedef
typedef
{
int
int
int
int
} Move;
char Piece[3];
Piece Board[8][8];
struct
iFromRow;
iFromCol;
iToRow;
iToCol;
// code for bestMove function
Move bestMove(Board chessBoard, int bWhiteMoveInd)
{
int i, j;
Move move;
for (i = 0; i < 8; i ++)
for(j = 0; i < 8; j ++)
{
if (bWhiteMoveInd && Board[i][j][0] == 'W')
// evaluate white piece
…
else
// evaluate black piece
…
}
return move;
}
// Copy Employee Name to Manager Name
char szEmpNm[30] = "Sue Melater";
char szMgrNm[30];
strcpy(szMgrNm, szEmpNm);
// This copied 12 bytes.
// Copy array of student grades to the best student grades
array
int iGradeM[20];
int iBestGradeM[20];
int iNumGrades = 12;
memcpy(iBestGradeM, iGradeM, sizeof(iGradeM));
bytes
// copied 80
memcpy(iBestGradeM, iGradeM, iNumGrades*sizeof(int)); // copied
48 bytes
Warning
If you are using memcpy to copy data from one part of an array to another
location in the same array, it may be necessary to use memmove() instead of
memcpy(). memmove is guaranteed to handle overlapping values. memcpy()
can be faster than memmove().
typedef char Name[30];
Name waitingLineM[50];
…
// move 5 people from element j (and the next 4 elements) to
// element i.
memcpy(&waitingLineM[i], &waitingLineM[j], 5 * sizeof(Name));
// If the from and to overlap, use memmove()
memmove(&waitingLineM[i], &waitingLineM[j], 5 * sizeof(Name));
Download