MODULE-3 Arrays and Strings
Arrays in C:
- Array = collection of variables of same type under one name
- Elements accessed by index
- Stored in contiguous memory locations
- Lowest address first element
- Highest address last element
- Types:
- Single-dimensional arrays
- Multi-dimensional arrays
- String = array of characters, ends with null ('\0')
Example:
int arr[5]; // array of 5 integers
arr[0] = 10; // first element
arr[4] = 20; // last element
char str[] = "Hello"; // string (array of chars ending with '\0')
Single-Dimension Arrays
. Definition of Single-Dimension Array:
- An array is a collection of elements of the same type stored in contiguous
memory locations.
- A single-dimension array stores data in a linear list format.
- Each element is accessed by using an index starting from 0.
. Declaration of Single-Dimensional Array:
- Syntax: type array_name[size];
- Example: double balance[100];
(This declares an array of 100 elements of type double)
. Array Size Rule:
- In C89, size must be a constant at compile time.
- In C99, size can be given at runtime.
. Accessing Array Elements:
- Syntax: array_name[index] = value;
- Example: balance[3] = 12.23;
(This assigns 12.23 to the 4th element of balance)
. Indexing in Arrays:
- Index starts from 0.
- The last element is at position size-1.
- Example: char p[10]; valid indices are p[0] to p[9].
. Example Program:
#include <stdio.h>
int main(void) {
int x[100];
int t;
for(t=0; t<100; ++t) x[t] = t; // store values
for(t=0; t<100; ++t) printf("%d ",x[t]); // print values
return 0;
}
. Concept of Arrays:
- Arrays are stored in contiguous memory locations.
- Example: char a[7];
(If starting at 1000, elements stored from 1000 onwards in order)
Generating a Pointer to an Array
1. Declare an array
int sample[10];
2. Understand:
The name "sample" itself represents the address of the first element
(sample[0]).
3. Example of memory layout (character array for simplicity):
Element : a[0] a[1] a[2] a[3] a[4] a[5] a[6]
Address : 1000 1001 1002 1003 1004 1005 1006
4. Declare a pointer:
int *p;
5. Assign pointer to the first element:
p = sample; // "p" now stores address of sample[0]
6. Alternative way (less common in practice):
p = &sample[0]; // same as above
7. Note:
In professional C code, you usually see "p = sample;"
rather than "p = &sample[0];"
Passing Single-Dimension Arrays to Functions
1. Rule:
You cannot pass the whole array directly as a function argument.
Instead, you pass the address (pointer) of the first element.
This is done by using the array name (without index).
2. Example in main():
int main(void)
{
int i[10]; // declare array
func1(i); // pass array name actually passes pointer to i[0]
}
3. Function Declaration Options:
A function that receives an integer array can be written in 3 ways:
a) As a pointer:
void func1(int *x)
{
// "x" is a pointer to int (points to i[0])
}
b) As a sized array:
void func1(int x[10])
{
// Compiler treats this as int *x
}
c) As an unsized array:
void func1(int x[])
{
// Also treated as int *x
}
4. Important Note:
All three methods mean the same to the compiler: a pointer is passed.
The size mentioned (like [10], [32]) is ignored by the compiler.
C does NOT check array bounds inside functions.
5. Key Point:
No matter how you declare it, the function always receives a pointer
to the first element of the array.
Strings
Topic: Strings in C (Character Arrays)
1. Definition:
In C, a string = a null-terminated character array.
Null character = '\0' (value 0).
Example: "hello" is stored as h e l l o \0
2. Declaring a string:
Always allocate +1 extra space for null terminator.
Example:
char str[11]; // Can hold a 10-character string + '\0'
3. String constants:
Written in double quotes, e.g. "hello there"
Compiler automatically adds '\0' at the end.
4. Common String Functions (in <string.h>):
strcpy(s1, s2) : Copy s2 into s1
strcat(s1, s2) : Append s2 to end of s1
strlen(s1) : Return length of s1 (excluding '\0')
strcmp(s1, s2) : Compare s1 and s2
returns 0 if equal
<0 if s1 < s2
>0 if s1 > s2
strchr(s1, ch) : Find first occurrence of ch in s1
strstr(s1, s2) : Find first occurrence of s2 inside s1
5. Example Program:
#include <stdio.h>
#include <string.h>
int main(void) {
char s1[80], s2[80];
gets(s1); // input first string
gets(s2); // input second string
printf("lengths: %d %d\n", strlen(s1), strlen(s2));
if(!strcmp(s1, s2)) // use ! because strcmp returns 0 if equal
printf("The strings are equal\n");
strcat(s1, s2); // join s2 to s1
printf("%s\n", s1);
strcpy(s1, "This is a test.\n"); // copy new string into s1
printf(s1);
if(strchr("hello", 'e')) // check if 'e' is in string
printf("e is in hello\n");
if(strstr("hi there", "hi")) // check if "hi" is in string
printf("found hi");
return 0;
}
6. Sample Output (if input is "hello" and "hello"):
lengths: 5 5
The strings are equal
hellohello
This is a test.
e is in hello
found hi
Two-Dimensional Arrays
Definition:
A two-dimensional array is an "array of arrays".
Think of it as a table with rows and columns.
Declaration:
int d[10][20]; // 10 rows, 20 columns
Note: In C dimensions are inside their own brackets, NOT separated by
commas.
Accessing elements:
d[1][2] // row = 1, column = 2
Example Program (filling and printing numbers 1–12):
int num[3][4]; // 3 rows, 4 columns
for t = 0 to 2
for i = 0 to 3
num[t][i] = (t*4) + i + 1
// Printing
for t = 0 to 2
for i = 0 to 3
print num[t][i]
Result:
Row 0 1 2 3 4
Row 1 5 6 7 8
Row 2 9 10 11 12
Memory storage:
Stored in row-major order (rows first, then columns).
Example: num[2][3] = 12
Formula for memory usage:
bytes = rows × columns × sizeof(base type)
Example: int d[10][5] with 4-byte int
= 10 × 5 × 4 = 200 bytes
Passing 2D array to functions:
Only pointer to first element is passed.
Function must know rightmost dimension size.
Example:
void func1(int x[][10]) // ok
void func1(int x[10][10]) // also ok
Example Program: Student Grades Database
- Classes: 3
- Students per class: 30
- grade[3][30]
Example
#include <stdio.h>
#define STUDENTS 3
#define SUBJECTS 3
int main() {
int grades[STUDENTS][SUBJECTS]; // 3 students, 3 subjects
int i, j;
// Input grades
for(i = 0; i < STUDENTS; i++) {
printf("Enter grades for Student %d:\n", i+1);
for(j = 0; j < SUBJECTS; j++) {
printf(" Subject %d: ", j+1);
scanf("%d", &grades[i][j]);
}
}
// Display grades
printf("\n--- Student Grades Database ---\n");
for(i = 0; i < STUDENTS; i++) {
printf("Student %d: ", i+1);
for(j = 0; j < SUBJECTS; j++) {
printf("%d ", grades[i][j]);
}
printf("\n");
}
return 0;
}
Multidimensional Arrays in C
General Form:
type name[Size1][Size2][Size3]...[SizeN];
Example:
int m[4][3][6][5]; // 4D array
Memory Usage:
Total bytes = Size1 × Size2 × ... × SizeN × sizeof(base type)
Example: char arr[10][6][9][4]
10 × 6 × 9 × 4 = 2,160 bytes (1 byte each)
If int (2 bytes) 4,320 bytes
If double (8 bytes) 17,280 bytes
Adding more dimensions = memory grows very fast!
Performance:
- More dimensions = slower access
- Because computer must calculate multiple indices
Passing to Functions:
- Must declare all dimensions except the first
Example:
int m[4][3][6][5];
void func1(int d[][3][6][5]) {
// function works on 4D array
}
Array Initialization
General Form:
type array_name[size] = {value1, value2, ..., valueN};
If fewer values are given, remaining elements are set to 0.
If more values are given than size ERROR.
Example: 1D Array
int a[5] = {10, 20, 30, 40, 50}; // all values given
int b[5] = {1, 2}; // b = {1, 2, 0, 0, 0}
int c[] = {5, 6, 7}; // size auto = 3
Example: Character Array (string)
char str1[] = {'h','e','l','l','o','\0'}; // manual null
char str2[] = "hello"; // compiler adds '\0'
Example: 2D Array
int num[2][3] = {
{1, 2, 3},
{4, 5, 6}
};
// Table:
// Row0 123
// Row1 456
int num2[2][3] = {1,2,3,4,5};
// Row0 1 2 3
// Row1 4 5 0 (last one auto-filled with 0)
Example: 3D Array
int cube[2][2][2] = {
{ {1,2}, {3,4} },
{ {5,6}, {7,8} }
};
// Access cube[0][1][1] 4
// Access cube[1][0][0] 5
Key Points:
- Arrays can be initialized at declaration time only.
- Uninitialized elements default = 0.
- Size can be omitted if initializer is given (compiler calculates).
- Multidimensional arrays initialized row by row.
Variable-Length Arrays (VLA)
In C89:
- Array size must be fixed (constant).
- Example:
int arr[10]; // OK
int n;
scanf("%d",&n);
int arr[n]; // NOT allowed in C89
In C99:
- Array size can be decided at runtime.
- This is called Variable-Length Array (VLA).
- Works only for local arrays (inside functions).
Example:
void f(int dim) {
char str[dim]; // size decided at runtime
...
}
- Each call to f() creates "str" with different length.
Usage:
- Useful in numeric/data processing where size depends on input.
- Cannot use for global arrays.
- Not supported in C89 or C++.
Tic-Tac-Toe Game
Define a 3x3 matrix (board) filled with spaces (' ').
Functions:
- init_matrix() fill board with spaces.
- disp_matrix() display board in grid format.
- get_player_move() ask player for X,Y coordinates.
- If spot is empty place 'X'
- Else invalid move, ask again.
- get_computer_move() find first empty spot place 'O'.
- If no spot left print "Draw" and exit.
- check() check rows, columns, diagonals:
- If 3 X's return 'X' (player wins)
- If 3 O's return 'O' (computer wins)
- Else return ' ' (game continues)
Main Game Loop:
- Initialize board with spaces.
- Repeat until someone wins:
a) Display board.
b) Player makes move (X).
c) Check winner if yes, stop.
d) Computer makes move (O).
e) Check winner if yes, stop.
- Display final result:
- If winner = 'X' "You won!"
- If winner = 'O' "I won!"
#include <stdio.h>
#include <stdlib.h>
char board[3][3]; // 3x3 board
// Initialize board with spaces
void init_board() {
for(int i=0; i<3; i++)
for(int j=0; j<3; j++)
board[i][j] = ' ';
}
// Show board
void display_board() {
for(int i=0; i<3; i++) {
printf(" %c | %c | %c ", board[i][0], board[i][1], board[i][2]);
if(i != 2) printf("\n---|---|---\n");
}
printf("\n");
}
// Player move (X)
void player_move() {
int row, col;
printf("Enter row and column (1-3 each): ");
scanf("%d %d", &row, &col);
row--; col--; // adjust to 0-based index
if(row<0 || row>2 || col<0 || col>2 || board[row][col] != ' ') {
printf("Invalid move! Try again.\n");
player_move();
} else {
board[row][col] = 'X';
}
}
// Computer move (O) just finds first empty spot
void computer_move() {
for(int i=0; i<3; i++) {
for(int j=0; j<3; j++) {
if(board[i][j] == ' ') {
board[i][j] = 'O';
return;
}
}
}
printf("It's a draw!\n");
exit(0);
}
// Check winner
char check_winner() {
for(int i=0; i<3; i++) {
if(board[i][0]==board[i][1] && board[i][0]==board[i][2] && board[i][0]!=' ')
return board[i][0]; // Row
if(board[0][i]==board[1][i] && board[0][i]==board[2][i] && board[0][i]!=' ')
return board[0][i]; // Column
}
// Diagonals
if(board[0][0]==board[1][1] && board[0][0]==board[2][2] && board[0][0]!=' ')
return board[0][0];
if(board[0][2]==board[1][1] && board[0][2]==board[2][0] && board[0][2]!=' ')
return board[0][2];
return ' '; // No winner
}
// Main game
int main() {
char winner = ' ';
init_board();
printf("Tic Tac Toe Game!\n");
while(winner == ' ') {
display_board();
player_move();
winner = check_winner();
if(winner != ' ') break;
computer_move();
winner = check_winner();
}
display_board();
if(winner == 'X') printf(" You won!\n");
else printf(" Computer won!\n");
return 0;
}
What are pointers?
A pointer is a variable.
Instead of storing a normal value (like 10 or 20),it stores a MEMORY
ADDRESS.
That memory address usually points to another variable.
Example: If variable A is stored at address 1000,
a pointer can store "1000".
This means the pointer "points to A".
So, pointer = variable that tells us:
"Hey, the actual value is stored at this memory location."
Important points:
- Normal variable stores a VALUE.
- Pointer variable stores an ADDRESS of another variable.
Pointer Variable
A pointer is a special variable that stores an ADDRESS.
To declare a pointer, we use: type *name;
Example:
int *p; p is a pointer to an integer
char *c; c is a pointer to a character
float *f; f is a pointer to a float
The "base type" tells the compiler what kind of data
the pointer will point to.
- int * means: "this pointer points to an integer"
- char * means: "this pointer points to a character"
Why base type matters?
- The compiler uses it to understand how many bytes to read/write.
- Example: int usually takes 4 bytes, char takes 1 byte.
- So pointer arithmetic (like p+1) moves differently
depending on base type.
Rule:
- Pointer type must match the variable type it points to.
- int * points to int variable
- char * points to char variable
Pointer Operators
Operator: &
- Meaning: "address of"
- It gives the memory address of a variable.
Example:
m = &count;
m now stores the address where "count" lives in memory.
If count is at location 2000, then m = 2000.
Note: & does NOT give the value of count, only its address.
Operator: *
- Meaning: "value at address"
- It gives the actual value stored at a memory address.
Example:
q = *m;
q will get the value stored at the memory address inside m.
If m = 2000 and count = 100 at address 2000,
then q = 100.
In simple words:
- & "Where is it stored?"
- * "What is stored there?"
Pointer Expression
1. POINTER ASSIGNMENTS
- You can assign one pointer to another if both are of same type.
- Example process:
a. Let variable x = 99
b. Let p1 point to x (p1 = address of x)
c. Let p2 = p1 (so p2 also points to x)
- Now:
*p1 = 99
*p2 = 99
p1 and p2 both store same address of x
2. POINTER CONVERSIONS
- General rule: pointer operations follow the pointer's base type.
- Types:
a. void * (generic pointer)
can point to any type without cast
can be assigned to/from any pointer
b. Explicit casts required for other pointer types
Example:
- double variable x
- int pointer p
- Force assign p = (int *)&x
- Problem: p only sees memory as int
- Only part of double is read
- Leads to incorrect result
- Converting pointer to integer or integer to pointer requires explicit cast
- Exception: assigning 0 is allowed called NULL pointer
3. POINTER ARITHMETIC
- Allowed operations: addition, subtraction
- Rule:
* Increment (p++) moves pointer to next element of its base type
* Decrement (p--) moves pointer to previous element of its base type
- Size step depends on base type:
* If int = 2 bytes p++ adds 2
* If char = 1 byte p++ adds 1
- Example logic:
- If p1 points at memory 2000
- If base type = int (2 bytes)
- p1++ now 2002
- Other operations NOT allowed:
* No multiplication, division
* No adding two pointers
* No float/double + pointer
4. POINTER COMPARISONS
- Relational operators (<, >, ==) can compare pointers
- Useful when pointers point inside same array
- Example:
If p points to arr[0]
And q points to arr[4]
Then p < q is true (p is lower memory)
5. STACK USING POINTERS (Concept only)
- A stack = list with "last in, first out"
- Two main operations:
a. push(value) puts value on stack
b. pop() removes value from stack
- Implementing with pointers:
- Use array as storage
- Use pointer p1 to track current top
- Use pointer tos as base (to detect limits)
- Push:
* Move pointer up
* Place value at new position
* If beyond limit Overflow
- Pop:
* Move pointer down
* Return last stored value
* If below base Underflow
Pointer And Arrays
1. Relationship:
- An array name represents the address of its first element.
- A pointer can be assigned to this address.
- Example idea:
Let str = character array
Let p1 = pointer
Assign p1 = str (so p1 points to str[0])
2. Accessing array elements:
- Using array indexing:
str[4] gives 5th element
- Using pointer arithmetic:
*(p1 + 4) also gives 5th element
- Reason:
p1 points to str[0]
Adding 4 makes p1 point to str[4]
Dereferencing (*) retrieves the value there
3. General principle:
- C allows two equivalent methods for array access:
a. Array indexing (easy to read)
b. Pointer arithmetic (often faster in execution)
4. Practical usage:
- Many C programmers prefer pointer arithmetic when speed matters
- Both styles ultimately mean the same thing to the compiler
5. Example function putstr() (concept only):
- Purpose: output characters of a string one by one
- Two approaches:
a. Using array indexing
Loop through array positions: s[0], s[1], ...
Print each character until null terminator is found
b. Using pointer arithmetic
While current character at pointer is not null:
Print it
Move pointer to next position (s++)
- Both versions behave the same
Array of pointers
1. Declaring pointer arrays:
- Pointers can themselves be stored in arrays.
- Example concept:
Let x be an array of 10 integer pointers
x[0] to x[9] can each store address of an int variable
2. Assigning a pointer to an element:
- Let var = integer variable
- Store address of var in third element of pointer array:
x[2] = address of var
3. Accessing the value through pointer array:
- To get value of var via pointer array:
value = *x[2] // dereference the pointer stored in x[2]
4. Passing pointer arrays to functions:
- Use array name without subscripts
- Inside function, declare parameter as array of pointers
For example, display_array(q):
Loop through array positions:
Print value pointed to by q[t] (*q[t])
- Important:
* q is not a simple pointer
* q is an array of integer pointers
5. Pointer arrays and strings:
- Pointer arrays can store addresses of strings
- Example concept:
Let err[] = array of pointers to error messages
Each element points to a string constant
- Access:
Given index num, output err[num] // prints corresponding error message
6. Real-world example:
- Command line arguments (argv) is an array of character pointers
- Each pointer points to a string representing a command line argument
Multiple Indirection
1. Concept:
- A normal pointer stores the address of a variable.
- A pointer to a pointer stores the address of another pointer.
- The second pointer then points to the actual variable/value.
2. Structure:
- Let x = target value
- Let p = pointer to x (p = &x)
- Let q = pointer to p (q = &p)
- Access value of x via q:
**q value of x
3. Declaration:
- Use additional asterisk (*) for each level of indirection
- Example:
float **newbalance
// newbalance is a pointer to a pointer of type float
4. Accessing values:
- Apply the * operator as many times as levels of indirection
- Example:
**q // two levels value of x
5. Notes:
- Multiple indirection can be extended to more levels, but rarely needed
- Do not confuse with complex data structures like linked lists
- Excessive indirection is hard to follow and prone to mistakes
Initializing Pointers
1. Uninitialized pointers:
- Local (nonstatic) pointers contain unknown values if not initialized.
- Using them before assignment may crash the program.
- Global or static pointers are automatically initialized to null.
2. Null pointer concept:
- Null (0) indicates a pointer points to nothing.
- Most C programmers initialize unused pointers to null.
- Example: char *p = 0; or p = NULL;
- Using a null pointer to access memory causes a crash:
int *p = 0;
*p = 10; // WRONG! leads to runtime error
3. Advantages of using null pointers:
- Marks unused or end of pointer arrays.
- Simplifies code logic for pointer operations.
- Example: ending an array of strings with NULL.
4. Pointer arrays with null terminator:
- char *names[] = { "Herb", "Rex", "Dennis", "John", NULL };
- Use null to detect end of array in functions.
5. Searching with pointer arrays:
- Pass array of char* and target string to search function.
- Loop through array:
for each pointer in array until null:
compare string at pointer with target string
if match found return index
- Return -1 if not found
6. Pointers to string constants:
- char *p = "hello world";
- p points to the address of the string stored in the string table by the
compiler.
- p is not an array; it’s a pointer to the string constant.
7. Using pointer to string:
- Can access and print string like a normal array:
- Forward: printf(p)
- Backward: loop from strlen(p)-1 to 0, print each character