Summary

This document discusses functions and arrays in the context of C programming. It covers topics such as function prototypes, variable-length arrays, mixed-type expressions, and best practices for C code. Concepts of memory (stack and heap) are mentioned briefly.

Full Transcript

CST8234 – C Programming Week 3 – Functions and Arrays Functionalizing a Program ❑ MOTIVATION: ▪ Divide-and-Conquer: Breaking down a problem into smaller, manageable functions which can be developed, tested, and debugged independently. ▪ Software Reusabil...

CST8234 – C Programming Week 3 – Functions and Arrays Functionalizing a Program ❑ MOTIVATION: ▪ Divide-and-Conquer: Breaking down a problem into smaller, manageable functions which can be developed, tested, and debugged independently. ▪ Software Reusability: Functions can be reused across different programsde. ▪ Abstraction: This involves hiding the complex details of function implementation and exposing only the necessary functionality. ▪ Single Responsibility Principle: Each function should perform a single, well-defined task. If a function is trying to do too many things, it can be broken down into smaller functions, a process known as decomposition. 2 Declaring and Defining Functions A function declaration, also known as a function prototype, specifies the function’s name, return type, and parameters without providing the actual implementation. It tells the compiler what the function looks like, so it can be used before its definition appears in the code. return_type function_name(parameter_list); In C, functions are defined once and can be used (or "called") multiple times from different parts of the program. This modular approach allows you to organize your code better by hiding the details of function implementations. double areaOfCircle(double radius) { return 3.14159 * radius * radius; } 3 Calling and Returning from Functions Functions are invoked using a function call. #include int main() { double radius = 5.0; double area = areaOfCircle(radius); printf("The area of the circle is: %f\n", area); return 0; } In this analogy, the main function (the "boss") requests the areaOfCircle function (the "worker") to perform a task. The worker performs the task and reports back the result. 4 Putting it all together include int add(int a, int b); double multiply(double x, double y); int main() { int sum = add(5, 3); double product = multiply(4.5, 2.0); printf("Sum: %d\n", sum); printf("Product: %f\n", product); return 0; } int add(int a, int b) { return a + b; } double multiply(double x, double y) { return x * y; 5 } Function Prototypes – Mixed Type Expressions 1) Arithmetic Conversions in Mixed-Type Expressions: If any operand in an expression is of type long double, all operands are converted to long double. If any operand is of type double but none are of type long double, all operands are converted to double. Integer promotion rules ensure that smaller integer types (like char and short) are promoted to int before the expression is evaluated. 6 Mixed Type Expressions Data type printf conversion specification scanf conversion specification long double %Lf %Lf double %f %lf float %f %f Data type printf conversion specification scanf conversion specification unsigned long long int %llu %llu long long int %lld %lld unsigned long int %lu %lu long int %ld %ld unsigned int %u %u int %d %d unsigned short %hu %hu short %hd %hd char %c %c 7 Best Practices 1) Include Function Prototypes: Always provide function prototypes for functions you define or use. This practice ensures that function calls are checked for type correctness and helps prevent unexpected behaviors and compilation errors. 2) Use of Header Files: To maintain clarity and avoid redundancy, function prototypes are often placed in header files (.h files), which are then included in the source files (.c files) where the functions are defined or used. 3) Location of Prototypes: 1) Global Scope: useful for functions that are used across multiple files. 2) Local Scope: can be used for functions that are only relevant within a specific function. 8 Arrays Fundamental data structure used to store a collection of elements of the same type. ❑ Declaration and Initialization To declare an array, you specify the type of its elements and the number of elements it will hold. int numbers; You can initialize an array at the time of declaration: int numbers = {1, 2, 3, 4, 5}; int numbers = {1, 2}; // numbers will be {1, 2, 0, 0, 0} int numbers[] = {1, 2, 3, 4, 5}; // size is inferred to be 5 9 Defining and allocating space for Arrays When you define an array in C, you reserve space for both the array itself and its elements. Example 1: unsigned long studentIDs; This statement does two things: 1. Reserves Space for the Array Variable: The variable studentIDs itself is a pointer to the start of the array. The size of this pointer depends on the architecture (e.g., 4 bytes on a 32-bit system or 8 bytes on a 64-bit system). However, for practical purposes, in many systems, the space required for the pointer is a constant 4 or 8 bytes, not specifically relevant in the context of the array data storage. 2. Allocates Space for Array Elements: It reserves space for 200 unsigned long elements. The size of unsigned long typically depends on the system but is often 4 bytes or 8 bytes. Assuming a system where unsigned long is 4 bytes, the total space for the elements is 200*4=800 bytes. Total Space Reserved = 4 (or 8) bytes + 800 bytes = 804 (or 808) bytes 10 Defining and allocating space for Arrays Example 2: unsigned long professorIDs[]; This declaration is incomplete and is used for defining arrays with a size that will be determined later, typically in the context of initialization. This is often used in the context of defining static arrays with an initial size. unsigned long professorIDs[] = {1001, 1002, 1003}; In this case: 1. The size of the array is determined by the number of elements in the initialization list. The compiler calculates the size of the array based on the initializer. 2. No Explicit Size: Since no explicit size is given, the compiler figures out the size from the initialization data. Total Space Reserved = For the variable itself 4 (or 8) bytes For the data: None allocated at this point (The array variable itself is typically a pointer or reference to an array that is not yet defined) 11 Key Points 1) Variable Size vs. Data Size: The size of the variable itself (such as a pointer to an array) is separate from the size of the data it points to. The variable studentIDs and professorIDs itself takes up space for the pointer/reference, but the actual data (the array elements) takes up additional space. 2) Memory Layout: In memory, arrays are contiguous blocks. If studentIDs is defined first, the subsequent variables will follow the space allocated for the array. Similarly, if professorIDs is later allocated or initialized, its data will follow in memory. 12 Variable Length Arrays (VLAs) Variable-length arrays are declared using a variable to specify the size of the array: int n = 5; int arr[n]; // `arr` is a variable-length array with size `n` You can initialize VLAs similarly to fixed-size arrays: int n = 3; int arr[n] = {1, 2, 3}; // Initialize `arr` with values VLAs can be used as function parameters: void processArray(int size, int arr[size]) { // Process array `arr` with `size` } int main() { int n = 10; int arr[n]; processArray(n, arr); return 0; } 13 Benefits and Limitations of VLAs 1. Dynamic Sizing: VLAs allow for the creation of arrays with sizes determined at runtime. 2. Memory Efficiency 3. Flexibility: VLAs provide flexibility in algorithms and data structures where the size may change based on user input or other runtime conditions. Cons: 1. Variable-length arrays are a feature of the C99 standard and later. In older standards (such as C89/C90), arrays must have a constant size known at compile time. 2. VLAs are allocated on the stack, which can lead to stack overflow if the arrays are too large. 3. The size of a VLA is not checked at compile time, which means errors related to out-of-bounds access or excessive size must be handled carefully 14 at runtime. Example of VLAs include void printArray(int size, int arr[size]) { for (int i = 0; i < size; i++) printf("%d ", arr[i]); printf("\n"); } int main() { int n; printf("Enter the number of elements: "); scanf("%d", &n); int arr[n]; // Create a variable-length array based on user input for (int i = 0; i < n; i++) // Initialize the array with some values { arr[i] = i * 2; // Example values } printArray(n, arr); // Print the array return 0; } 15 Char Array Initialization Character arrays can be initialized with individual character constants. char string1[] = {'f', 'i', 'r', 's', 't', '\0'}; // Equivalent to "first“ char string1[] = "first"; // Automatically adds '\0' at the end Reading Input with scanf: scanf("%19s", string2); // Read up to 19 characters to avoid buffer overflow Printing Strings with printf: printf("%s\n", string2); // Prints the string stored in `string2` Buffer Overflow: If a user inputs more characters than the array can hold, it can lead to buffer overflow, which may crash the program or create security vulnerabilities. Prevention: Always ensure the array is large enough and use format specifiers to limit input size. 16 Handling Special chars Scanf stops reading at whitespace (space, tab, newline). For reading strings with spaces, consider using fgets instead of scanf : fgets(string2, sizeof(string2), stdin); // Read a line of text including spaces fgets: used for reading strings from a file or standard input (stdin) safely. preferred alternative to scanf for reading strings, especially when dealing with user input. char *fgets(char *str, int n, FILE *stream); str: A pointer to the character array where the read string will be stored. n: The maximum number of characters to read, including the null terminator. This means fgets will read up to n-1 characters, leaving space for the null terminator. stream: The input file stream to read from, commonly stdin. Success: Returns the str pointer if a string is successfully read. Failure: Returns NULL if an error occurs or end-of-file is reached before any characters are read. 17 Example string handling #include #include int main() { char string2; printf("Enter a string (max 19 characters): "); scanf("%19s", string2); // Reads up to 19 characters printf("You entered: %s\n", string2); while (getchar() != '\n’); // Clear input buffer printf("Enter another string (up to 19 characters): "); // Using fgets fgets(string2, sizeof(string2), stdin); // Reads up to 19 characters + null terminator char *newline = strchr(string2, '\n’); // Remove newline if present if (newline) *newline = '\0’; // Replace newline with null terminator printf("You entered: %s\n", string2); return 0; } 18 Multi-Dimensional Arrays ❑ Multi-Dimensional Arrays int matrix; // 3 rows and 4 columns int matrix = { {1, 2, 3}, {4, 5, 6} }; int value = matrix; // Gets the value 6 strings and arrays boil down to the same thing o a block of data o C text strings are represented as an array of characters o ‘H’, ‘e’, ‘l’, ‘l’, ‘o’, ‘!’, NULL 19 Array Identifiers ❑ A single identifier is used for the block of data ❑ in C, this identifier holds the start of memory where the data is stored char myStr[]; unsigned long studentIDs[]; Address Value Address Value 0x00104300 ‘H’ 0x00260020 932650 ‘e’ 88416 ‘l’ 333229 ‘l’ 141415 ‘o’ ‘!’ NULL 20 Two-Dimensional Arrays You can declare short teamPlayerIDs[NUM_TEAMS][NUM_PLAYERS]; ‘teamPlayerIDs’ is 8832 ‘teamPlayerIDs’ is 9002 Address Value Team 0 0x0303390 0001 1900 8832 4992 Team 1 6631 7786 0517 9002 21 Defining vs Declaring 2-D Arrays #define NUM_TEAMS 2 #define NUM_PLAYERS 4 int teamPlayerIDs[NUM_TEAMS][NUM_PLAYERS]; Total number of int elements is NUM_TEAMS * NUM_PLAYERS Space for the array elements: NUM_TEAMS * NUM_PLAYERS * sizeof(int) Bytes Initialization Example: int teamPlayerIDs = { {1, 2, 3, 4}, {5, 6, 7, 8} }; 22 Memory Concepts Every variable has a name, a type, a value and a location in the computer’s memory After placing 45 in integer1 When a value is placed in a memory location, it replaces the location’s previous value which is lost After placing 72 in integer2 These locations are not necessarily adjacent in memory. After calculating sum of integer1 and integer2 Stack In C programming, memory management is crucial for ensuring efficient and correct program execution. Purpose: The stack is used for static memory allocation, which includes function call management, local variables, and function parameters. Memory Allocation: Memory is allocated and deallocated automatically as functions are called and return. Characteristics: 1. Size and Lifespan: Fixed Size (predetermined by the system or compiler settings) and Memory is automatically managed. 2. Fast Access (push/pop) 3. Scope and Lifetime: Variables on the stack are only accessible within the function that created them. The lifetime of stack variables is limited to the duration of the function execution. They are destroyed when the function returns. 26 Stack void exampleFunction() { int localVariable = 5; // Allocated on the stack } Limitations 1. The stack has a limited size, and deep recursion or large local variables can lead to a stack overflow. 2. Scope Restriction 27 Heap The heap is used for dynamic memory allocation, which allows you to allocate memory during runtime. Memory on the heap must be explicitly allocated and deallocated using functions like malloc, calloc, realloc and free. Characteristics: 1. Size and Lifespan: Variable Size and Memory is manually managed (manually allocate and free memory. Failure to free allocated memory leads to memory leaks). 2. Slower Access 3. Scope and Lifetime: Memory allocated on the heap is accessible from anywhere in the program, provided you have a pointer to it. The lifetime of heap-allocated memory persists until it is explicitly freed. 28 Heap int *ptr = (int *)malloc(sizeof(int)); // Allocate memory on the heap if (ptr != NULL) { *ptr = 10; // Use the allocated memory free(ptr); // Free the allocated memory } Advantages 1. Flexibility: Allows for dynamic memory allocation which is useful when the size of the data is not known at compile time. 2. Lifetime Control: Memory persists beyond the scope of function calls. 29 Heap Disadvantages 1. Manual Management: Requires explicit allocation and deallocation. Improper management can lead to memory leaks or undefined behavior. 2. Performance Overhead: Typically, slower than stack memory access due to overhead in managing dynamic memory. 30

Use Quizgecko on...
Browser
Browser