C Typedef
C - typedef
Section titled “C - typedef”The typedef keyword in C provides a way to create an alias or a synonym for an existing data type. It doesn’t create a new type, but rather gives another name to a type that is already defined.
This is particularly useful for:
- Improving Readability: Using meaningful names for complex types.
- Simplifying Declarations: Making declarations of complex types (like pointers to structures or function pointers) easier to write and understand.
- Portability: Defining custom types (like
BYTEorINT32) that can be adjusted for different platforms in one place.
Syntax
Section titled “Syntax”The basic syntax follows the pattern of a variable declaration, but with the typedef keyword prepended:
typedef existing_type new_type_name;existing_type is the data type you want to create an alias for (e.g., unsigned char, int *, struct ComplexNumber). new_type_name is the alias (synonym) you want to define.
Examples
Section titled “Examples”1. Aliasing Basic Types:
Section titled “1. Aliasing Basic Types:”#include <stdint.h> // For int32_t
// Create aliases for basic or standard typestypedef unsigned char BYTE;typedef int32_t INTEGER32;typedef char* STRING; // Alias for pointer to char
int main(void) { BYTE status_flag = 0x01; // status_flag is actually an unsigned char INTEGER32 counter = -50000; // counter is actually an int32_t STRING message = "Hello typedef!"; // message is actually a char*
printf("Status: %u\n", status_flag); printf("Counter: %d\n", counter); printf("Message: %s\n", message);
return 0;}By convention, typedef names are often uppercase (like BYTE), but this is not a strict rule.
2. Aliasing Structure Types:
Section titled “2. Aliasing Structure Types:”Simplifies declaring structure variables by removing the need to write struct TagName repeatedly.
// Original structure definitionstruct Point2D { double x; double y;};
// Typedef for the structuretypedef struct Point2D Coordinate;// Or combine definition and typedef:typedef struct Vector3D { double x, y, z;} Vector; // Vector is now an alias for struct Vector3D
int main(void) { struct Point2D p1; // Using original struct name Coordinate p2; // Using the typedef alias - cleaner! Vector v1; // Using the combined typedef alias
p2.x = 1.0; p2.y = 2.0; v1 = (Vector){3.0, 4.0, 5.0}; // Compound literal with typedef
printf("Point p2: (%.1f, %.1f)\n", p2.x, p2.y); printf("Vector v1: (%.1f, %.1f, %.1f)\n", v1.x, v1.y, v1.z);
return 0;}3. Aliasing Pointer Types:
Section titled “3. Aliasing Pointer Types:”Can make pointer declarations less cluttered.
typedef int* IntPtr; // IntPtr is an alias for 'int *'typedef void (*CallbackFunc)(int); // CallbackFunc is an alias for a pointer // to a function that takes an int and returns void
void my_callback(int id) { printf("Callback called with ID: %d\n", id);}
int main(void) { int value = 10; IntPtr ptr1 = &value; // ptr1 is an int* IntPtr ptr2 = NULL; // ptr2 is an int*
CallbackFunc func_ptr = my_callback; // Assign function address
*ptr1 = 20; printf("Value via ptr1: %d\n", *ptr1);
if (func_ptr != NULL) { func_ptr(123); // Call the function via the pointer alias }
return 0;}typedef vs. #define
Section titled “typedef vs. #define”While both can create aliases, they work differently:
typedef: Handled by the compiler. It understands C syntax and creates true type synonyms. It respects scope.#define: Handled by the preprocessor (before compilation). It performs simple text substitution, unaware of C types or scope. Can lead to unexpected behavior, especially with pointers or complex types.
Example difference with pointers:
#define StringMacro char*typedef char* StringTypedef;
int main(void) { StringMacro p1, p2; // Preprocessor expands to: char* p1, p2; // Here, p1 is char*, but p2 is just char!
StringTypedef pt1, pt2; // Typedef applies to both: // pt1 is char*, and pt2 is char* return 0;}Best Practice: Use typedef for creating type aliases as it’s safer and better integrated with the C language’s type system.
C - Input & Output
Section titled “C - Input & Output”Input refers to feeding data into a program, typically from the keyboard or a file. Output refers to displaying data from the program, usually to the screen or a file.
C provides standard library functions, primarily declared in <stdio.h> (Standard Input/Output), to handle these operations.
The Standard Streams
Section titled “The Standard Streams”When a C program starts, three standard communication channels (streams) are automatically opened:
| Stream Name | File Pointer | Default Device |
|---|---|---|
| Standard Input | stdin | Keyboard (by default) |
| Standard Output | stdout | Screen/Console (by default) |
| Standard Error | stderr | Screen/Console (by default) |
stdin, stdout, and stderr are predefined FILE* pointers (file pointers) that allow access to these streams. Standard output is typically buffered (output may not appear immediately), while standard error is usually unbuffered (error messages appear promptly).
Character Input/Output: getchar() & putchar()
Section titled “Character Input/Output: getchar() & putchar()”int getchar(void): Reads the next available character fromstdinand returns it as anint. ReturnsEOF(a special integer constant indicating End-Of-File) on error or end of input.int putchar(int c): Writes the characterc(passed as anint) tostdoutand returns the character written, orEOFon error.
These functions handle one character at a time.
Example:
#include <stdio.h>
int main(void) { int input_char;
printf("Enter a character: "); input_char = getchar(); // Read one character
if (input_char == EOF) { printf("\nError or end of input detected.\n"); } else { printf("\nYou entered: "); putchar(input_char); // Print the character putchar('\n'); }
// Note: getchar() often reads the newline ('\n') too if you press Enter. // You might need extra getchar() calls to consume leftover input.
return 0;}Execution:
$ ./a.outEnter a character: HYou entered: HLine Input/Output: fgets() & puts()
Section titled “Line Input/Output: fgets() & puts()”char *fgets(char *str, int size, FILE *stream): Reads a line of text from the specifiedstream(e.g.,stdin) into the bufferstr. It stops reading whensize - 1characters are read, a newline character (\n) is encountered, or EOF occurs. Crucially,fgetsincludes the newline character in the buffer if it fits, and it always null-terminates the buffer (ifsize > 0). Returnsstron success,NULLon error or EOF before reading any characters. This is the recommended safe way to read strings.int puts(const char *str): Writes the stringstrtostdout, followed by a newline character (\n). Returns a non-negative value on success, orEOFon error.
Warning: The older gets(char *s) function is extremely dangerous because it doesn’t check buffer sizes, leading easily to buffer overflows. It has been removed from recent C standards. Never use gets(). Always use fgets().
Example using fgets:
#include <stdio.h>#include <string.h> // For strcspn
#define BUFFER_SIZE 100
int main(void) { char input_line[BUFFER_SIZE];
printf("Enter a line of text: "); if (fgets(input_line, sizeof(input_line), stdin) != NULL) { // Optional: Remove trailing newline if present input_line[strcspn(input_line, "\n")] = '\0';
printf("\nYou entered: "); puts(input_line); // puts adds its own newline } else { printf("\nError reading input or EOF reached.\n"); }
return 0;}Execution:
$ ./a.outEnter a line of text: This is a test line.You entered: This is a test line.Formatted Input/Output: scanf() & printf()
Section titled “Formatted Input/Output: scanf() & printf()”int printf(const char *format, ...): Writes formatted output tostdout. Theformatstring contains text to be printed and format specifiers (starting with%) that indicate how subsequent arguments should be converted and printed (e.g.,%dfor int,%ffor float/double,%cfor char,%sfor string,%pfor pointer). Returns the number of characters printed or a negative value on error.int scanf(const char *format, ...): Reads formatted input fromstdin. Theformatstring specifies the expected format of the input using format specifiers. Subsequent arguments must be pointers to variables where the read data will be stored. Returns the number of input items successfully matched and assigned, orEOFon input failure before any conversion.
Common Format Specifiers:
%dor%i: Signed integer%u: Unsigned integer%f: Floating-point number (float/double forprintf, float* forscanf)%lf: Long float (double* forscanf)%Lf: Long double%c: Single character%s: String (reads up to whitespace forscanf)%p: Pointer address%%: Literal ’%’ character
Example:
#include <stdio.h>
int main(void) { char name[50]; int age; float height;
printf("Enter your name, age, and height (e.g., Alice 30 1.65): ");
// Use width limits with %s in scanf to prevent buffer overflow! int items_read = scanf("%49s %d %f", name, &age, &height);
if (items_read == 3) { // Check if all 3 items were read successfully printf("\n--- User Info ---\n"); printf("Name : %s\n", name); printf("Age : %d years\n", age); printf("Height : %.2f meters\n", height); // Print float with 2 decimal places } else { printf("\nError: Invalid input format.\n"); // Clear remaining invalid input from buffer (simple example) while (getchar() != '\n'); }
return 0;}Execution:
$ ./a.outEnter your name, age, and height (e.g., Alice 30 1.65): Bob 25 1.8
--- User Info ---Name : BobAge : 25 yearsHeight : 1.80 metersscanf Pitfalls:
- Buffer Overflows: Using
%swithout a width limit (%49s) is dangerous. - Input Format Matching: Input must exactly match the format string (including whitespace).
- Whitespace Handling:
%sskips leading whitespace and stops at the next whitespace.%creads the next character, including whitespace. - Newline Character:
scanfoften leaves the newline character (\n) from the Enter key press in the input buffer, which can interfere with subsequentfgetsorgetcharcalls. - Error Checking: Always check the return value of
scanfto ensure the expected number of items were successfully read.
Due to these issues, fgets followed by parsing functions like sscanf or strtol is often a more robust way to handle user input.