Curated questions covering pointers, memory management, arrays, strings, structures, file handling, and data structures in C.
C is a general-purpose procedural language developed by Dennis Ritchie in 1972. Key features: low-level memory access via pointers, efficient execution, portable across platforms, structured programming, rich operators, and it is the foundation for C++, Java, and many other languages.
Compiled languages (C, C++) translate source code to machine code before execution - faster runtime. Interpreted languages (Python, JavaScript) translate at runtime - slower but more flexible. C is compiled: gcc/clang converts .c files to optimized machine code.
printf("%zu\n", sizeof(int)); // 4\nprintf("%zu\n", sizeof(long)); // 4 or 8\nprintf("%zu\n", sizeof(char)); // 1A pointer is a variable that stores the memory address of another variable. Pointers enable dynamic memory allocation, efficient array handling, and passing variables by reference.
int x = 10;\nint *ptr = &x; // ptr holds address of x\nprintf("%d\n", *ptr); // 10 (dereference)\n*ptr = 20; // modifies x through pointer\nprintf("%d\n", x); // 20int x = 5;\nint *p = &x; // & gets address, * declares pointer\nprintf("%d", *p); // * dereferences to get value 5void byValue(int x) { x = 100; } // original unchanged\nvoid byRef(int *x) { *x = 100; } // original changed\nint n = 5;\nbyValue(n); // n still 5\nbyRef(&n); // n is now 100int arr[5] = {1,2,3,4,5};\nint *ptr = arr; // ptr points to arr[0]\nprintf("%d", *(ptr + 2)); // 3 (pointer arithmetic)\nprintf("%d", arr[2]); // 3 (same result)When you add 1 to a pointer, it advances by sizeof(type) bytes, not 1 byte. This allows traversing arrays efficiently.
int arr[] = {10, 20, 30, 40};\nint *p = arr;\np++; // advances by sizeof(int) = 4 bytes\nprintf("%d\n", *p); // 20\nprintf("%d\n", *(arr + 3)); // 40A null pointer does not point to any valid memory location. Represented by NULL (0 or (void*)0). Always initialize pointers to NULL and check before dereferencing to avoid undefined behavior.
int *ptr = NULL;\nif (ptr != NULL) {\n printf("%d", *ptr);\n} else {\n printf("Null pointer");\n}A dangling pointer points to memory that has been freed or gone out of scope. Dereferencing it causes undefined behavior. Always set pointers to NULL after freeing.
int *ptr = (int*)malloc(sizeof(int));\n*ptr = 10;\nfree(ptr);\nptr = NULL; // prevent dangling pointer\n\n// Also: returning address of local variable\nint* bad() { int x = 5; return &x; } // WRONGint *a = (int*)malloc(5 * sizeof(int)); // uninitialized\nint *b = (int*)calloc(5, sizeof(int)); // zero-initialized\na = (int*)realloc(a, 10 * sizeof(int)); // resize\nfree(a); a = NULL;A memory leak occurs when dynamically allocated memory is not freed after use. The memory remains allocated but inaccessible, gradually consuming available memory. Use Valgrind to detect leaks.
void leak() {\n int *p = (int*)malloc(100 * sizeof(int));\n // forgot free(p) - memory leak!\n}\nvoid noLeak() {\n int *p = (int*)malloc(100 * sizeof(int));\n free(p); p = NULL;\n}A structure (struct) groups variables of different types under a single name.
struct Student {\n char name[50];\n int age;\n float gpa;\n};\nstruct Student s1;\nstrcpy(s1.name, "Alice");\ns1.age = 20;\ns1.gpa = 3.8;\n\ntypedef struct { char name[50]; int age; } Student;union Data {\n int i; // 4 bytes\n float f; // 4 bytes\n char c; // 1 byte\n}; // sizeof = 4 (largest member)\nunion Data d;\nd.i = 10; // only d.i is valid now#define MAX 100 // no type, no memory\nconst int MAX = 100; // typed, has address\n\n// #define can cause bugs:\n#define SQUARE(x) x*x\nSQUARE(2+3) // expands to 2+3*2+3 = 11, not 25!int globalVar = 10; // global\nvoid func() {\n int localVar = 5; // local\n printf("%d %d", globalVar, localVar);\n}void counter() {\n static int count = 0; // persists between calls\n count++;\n printf("%d\n", count);\n}\ncounter(); // 1\ncounter(); // 2extern declares a variable or function defined in another file. It tells the compiler the definition exists elsewhere, allowing multi-file programs to share variables.
// file1.c\nint globalVar = 10;\n\n// file2.c\nextern int globalVar; // declaration only\nvoid func() { printf("%d", globalVar); }A function pointer stores the address of a function and can be used to call it indirectly. Used for callbacks, dispatch tables, and implementing polymorphism in C.
int add(int a, int b) { return a + b; }\nint sub(int a, int b) { return a - b; }\n\nint (*op)(int, int); // function pointer\nop = add;\nprintf("%d\n", op(3, 2)); // 5\nop = sub;\nprintf("%d\n", op(3, 2)); // 1Strings in C are null-terminated character arrays. The standard library (string.h) provides functions for string manipulation.
char str[50] = "Hello";\nstrlen(str); // 5\nstrcpy(dest, str); // copy\nstrcat(str, " World"); // concatenate\nstrcmp(s1, s2); // compare (0 if equal)\nstrncpy(dest, src, n); // safe copy with limitchar buf[100];\nfgets(buf, sizeof(buf), stdin); // safe\nbuf[strcspn(buf, "\n")] = 0; // remove trailing newlineC provides FILE* type and functions from stdio.h for file operations.
FILE *fp = fopen("data.txt", "r");\nif (fp == NULL) { perror("Error"); exit(1); }\nchar line[256];\nwhile (fgets(line, sizeof(line), fp)) {\n printf("%s", line);\n}\nfclose(fp);FILE *fp = fopen("data.bin", "wb");\nfwrite(&student, sizeof(Student), 1, fp);\nfclose(fp);\nfp = fopen("data.bin", "rb");\nfread(&student, sizeof(Student), 1, fp);typedef unsigned int uint; // proper type alias\ntypedef struct Node* NodePtr;\n\n#define UINT unsigned int\n// UINT *p1, p2; -> p2 is NOT a pointer!A linked list is a dynamic data structure where each node contains data and a pointer to the next node.
struct Node {\n int data;\n struct Node *next;\n};\nstruct Node* createNode(int data) {\n struct Node *n = (struct Node*)malloc(sizeof(struct Node));\n n->data = data;\n n->next = NULL;\n return n;\n}struct Point p = {3, 4};\nprintf("%d", p.x); // dot: direct access\nstruct Point *ptr = &p;\nprintf("%d", ptr->x); // arrow: pointer accessint i = 5;\nprintf("%d", ++i); // prints 6, i is 6\nprintf("%d", i++); // prints 6, i becomes 7\nprintf("%d", i); // prints 7unsigned int u = 4294967295; // max uint32\nint s = -1;\nprintf("%u", (unsigned int)s); // 4294967295 (same bits)int a = 5; // 0101\nint b = 3; // 0011\nprintf("%d", a & b); // 1 (0001)\nprintf("%d", a | b); // 7 (0111)\nprintf("%d", a ^ b); // 6 (0110)\nprintf("%d", a << 1); // 10 (1010)void *vp;\nint x = 10;\nvp = &x;\nprintf("%d", *(int*)vp); // must cast\nint *np = NULL;\n// *np = 5; // undefined behavior!int factR(int n) { return n <= 1 ? 1 : n * factR(n-1); }\nint factI(int n) {\n int r = 1;\n for (int i = 2; i <= n; i++) r *= i;\n return r;\n}enum Direction { NORTH, SOUTH, EAST, WEST }; // 0,1,2,3\nenum Status { OK=200, NOT_FOUND=404, ERROR=500 };\nenum Direction d = NORTH;char str[] = "Hello World";\nmemmove(str + 6, str, 5); // safe overlap\nchar dest[20];\nmemcpy(dest, str, strlen(str) + 1); // non-overlappingchar str[] = "Hello";\nprintf("%zu", sizeof(str)); // 6 (5 chars + null)\nprintf("%zu", strlen(str)); // 5 (without null)int n = atoi("42"); // 42, no error check\nchar *end;\nlong l = strtol("42abc", &end, 10);\nprintf("%s", end); // "abc" - where conversion stoppedint x = 5, y = 10;\nconst int *p1 = &x; // *p1 = 6 is error; p1 = &y is OK\nint * const p2 = &x; // p2 = &y is error; *p2 = 6 is OK#define MAX(a,b) ((a)>(b)?(a):(b)) // macro\nMAX(x++, y++); // x or y incremented twice!\nstatic inline int max(int a, int b) { return a > b ? a : b; }void infinite() { infinite(); } // stack overflow\nchar buf[10];\nstrcpy(buf, "This is way too long"); // buffer overflow!int i = 10;\nwhile (i < 5) { printf("never"); } // never executes\ndo { printf("once"); } while (i < 5); // executes oncefor (int i = 0; i < 10; i++) {\n if (i == 3) continue; // skip 3\n if (i == 7) break; // stop at 7\n printf("%d ", i); // 0 1 2 4 5 6\n}Arrays are always passed by reference in C - the function receives a pointer to the first element. Modifying the array inside the function modifies the original.
void modify(int arr[], int n) {\n arr[0] = 99; // modifies original\n}\nvoid readOnly(const int arr[], int n) {\n // arr[0] = 99; // compile error\n}int arr[10];\nmemset(arr, 0, sizeof(arr)); // zero all elements\nmemset(arr, -1, sizeof(arr)); // fill with 0xFF bytesstruct Padded { char c; int i; }; // sizeof = 8 (padding added)\nstruct __attribute__((packed)) Packed { char c; int i; }; // sizeof = 5Explore 500+ free tutorials across 20+ languages and frameworks.