Files of C
▶ C programs are made of two kinds of files:
• Code files: .c files e.g. myCode.c
• Header files: .h files e.g. myHeaderfile.h
▶ Header files contain compile-time artifacts:
Artifacts used when program is being compiled
• Type definitions
• Function declarations
• Variable declarations
▶ Code files contain compile-time & run-time artifacts
Artifacts used when program is being compiled
Artifacts used when the program is running
• Global or Static function definitions
• Global or Static variable definitions
▶ A declaration specifies the characteristics of a function/variable, but
does not create it. No space is alloc. and no function body is
specified.
▶ A definition specifies characteristics of a function/variable and
specifies the body of the function or allocates space for the variable.
1 / 12
1. Header files are included by other files using the #include
statement. e.g. #include <stdio.h>
2. During compilation, the contents of the header file replaces
the include statement.
3. #include < filename.h>: used to include standard library
header files
#include "afilename.h": used to include the program’s
own header files.
4. Common for header files to contain other header files.
2 / 12
Why do we need header files?
▶ Note: Code files do have compile time information - So, why
header files?
▶ 1. Avoid duplicate type definitions across files.
2. Provide a manifest of run-time artifacts in a code file.
▶ In C, each file is compiled independently of other C files. This
necessitates header files.
▶ Avoiding duplicate type declarations:
• Type declaration only used at compile time.
If two code files need the same definition, both would need to define
it.
Leads to duplicate code and the possibility of programming errors
▶ Instead, a type used by multiple code files should be defined
once, in a header file and then include the header file in every
file that uses the definition:
struct node {
strut node *next;
int value;
} 3 / 12
The correct way
node.h
struct node {
strut node *next;
int value; }
/* stack.c */ /* queue.c */
#include "node.h" #include "node.h"
void push(struct node **n){ void enqueue(struct node **n){
... } ... }
4 / 12
Aside on Structs
Structs are like classes except: struct node {
▶ ▶ There are no methods
struct node *next;
▶ All fields are public int priority;
int value;
▶ All fields are instance
};
variables
▶ Variables are accessed using the · operator.
struct node start;
[Link] = 1;
[Link] = 42;
5 / 12
Aside on Structs continued
/* [Link] prev slide
*/
struct node *ptr; struct node {
ptr = &start; struct node *next;
ptr->priority = 3; int priority;
ptr->value = 37; int value;
struct node *ptr2 = ptr; };
ptr2->priority = 4;
ptr2->value = 73;
6 / 12
The Manifest of a Code File
▶ The C compiler can only process one file at a time.
▶ If a function in one file uses a function/variable defined in
another file, the compiler cannot do error checking.
▶ Header files can be used as manifest of what code files
contain. Includes:
▶ Type definitions
▶ Function declarations
▶ Variable declarations
▶ The header file is included in and code file that uses those
types, functions and variables.
▶ Best Practice: Header file should have the same name as the
code file. (stack.c should include stack.h
7 / 12
Allocating Dynamic Memory
▶ Java allocates memory with the new statement.
Not available in C (exists in C++).
▶ One way C allocates dynamic memory is with the malloc
function:
It has a prototype:
void* malloc(size t size)
▶ Allows programmer to specify amount of memory needed for
the variable/data structure at run-time. e.g. malloc(8)
returns a pointer to an 8-byte block of memory
▶ int *A = (int*)malloc(100*sizeof(int));
Note: malloc returns a void* and then it is typecast to int*
to be type compatible.
Now A can be used like a regular int array of size 100
8 / 12
Strings
▶ In C a string is an array of characters that is NULL (i.e. \0)
terminated.
▶ Without \0 at the end, you have an array of char.
▶ Allocate static memory with char str[100]. 100 bytes
allocated. Max. size of string that can be stored is 99 bytes.
▶ To read a string into an array:
char temp[100];
fscanf(stdin, "%s", temp)
▶ To copy to a permanent location:
char * line = malloc(strlen(temp) + 1);
strcpy(line, tmp)
▶ Array of Pointers”: An array of n char pointers can be
defined: char* A[n] this way each element iof the array is a
char-pointer, so, it can point to a char.
▶ Now assign a string to each A[i]:
A[i] = malloc(string length + 1);
9 / 12
Problems
1. What is the error wrong in the following code?
int* foo(int n) {
int A[10], *x;
strcpy(A, "vwxyz");
x = A;
return x; }
2. What could be wrong in the following code:
int A[10], i, *ptr;
for (i = 1; i < 10; i++)
ptr = A + i;
printf("%d", *(ptr + i));
10 / 12
Problems contd...
3 The C library string.h contains the function
strcpy(dest, src), that copies string src to a string dest.
The function returns 0 if successful and 1 if it fails for any
reason. Write a version of strcpy with the following
template:
int mystrcpy (char* dest, const char* src) {
}
3 Is it possible to check, inside the function, if there is enough
memory available to dest to copy src?
11 / 12
Problems contd...
12 / 12