char vs String โ What's Actually Different?
A char holds exactly one character โ one letter, one digit, one symbol. It's a single mailbox, one slot, nothing more:
A string is what happens when you line up several char boxes in a row โ an array of characters. But there's a catch: C needs some way to know where the string ends, since the array itself might be bigger than the word stored in it. The solution is a hidden, invisible character called the null terminator, written '\0', silently placed right after the last real letter.
puts(), strlen(), strcpy() โ works by walking forward through the char array one box at a time and stopping the instant it sees '\0'. Box [5] still has garbage in it, and nothing cares, because nothing reads past the terminator.Reading & Printing with gets() and puts()
scanf("%s", ...) stops reading at the first space โ useless for names like "John Smith." gets() reads an entire line, spaces and all, until Enter is pressed. puts() is its printing partner โ it prints a string and automatically adds a newline, so you don't need \n yourself.
#include <stdio.h> int main() { char name[50]; puts("Enter your full name:"); gets(name); // reads the WHOLE line, including spaces puts("Hello, welcome!"); puts(name); // prints the string + a newline automatically return 0; }
Enter your full name: Ravi Kumar Sharma Hello, welcome! Ravi Kumar Sharma
| Function | Stops reading/printing at | Adds newline? |
|---|---|---|
scanf("%s", ...) | First space or Enter | No |
gets(name) | Enter only (spaces are kept) | No (but stores '\0' at the end) |
puts(name) | The string's '\0' | Yes โ automatically |
printf("%s", name) | The string's '\0' | No โ you must add \n |
Why gets() Is Dangerous โ And the Safer Fix
Here's the problem hiding inside Example 1: gets() never checks how big the char array actually is. If the user types more characters than the array can hold, gets() keeps writing anyway โ straight past the end of the array, into memory that belongs to something else. This is called a buffer overflow, and it's exactly why modern C compilers refuse to even compile gets() without a warning (or at all).
#include <stdio.h> #include <string.h> int main() { char name[6]; // deliberately small, to see the fix in action puts("Enter your name:"); fgets(name, sizeof(name), stdin); // NEVER writes past 6 bytes // fgets keeps the newline character โ strip it off name[strcspn(name, "\n")] = '\0'; printf("Stored safely as: %s\n", name); return 0; }
Enter your name: RAVIKUMAR Stored safely as: RAVIK
toupper() and tolower() โ One Char at a Time
Here's something that surprises beginners: toupper() and tolower() don't work on strings at all โ they only work on a single char. To change a whole word's case, you loop through the char array box by box, applying the function to one letter at a time.
#include <stdio.h> #include <ctype.h> #include <string.h> int main() { char word[50]; puts("Enter a word:"); fgets(word, sizeof(word), stdin); word[strcspn(word, "\n")] = '\0'; printf("Single char: toupper('a') = %c\n", toupper('a')); printf("Single char: tolower('Z') = %c\n\n", tolower('Z')); // To convert a WHOLE word, loop over every char for (int i = 0; word[i] != '\0'; i++) { word[i] = toupper(word[i]); // one box at a time } printf("UPPERCASE: %s\n", word); for (int i = 0; word[i] != '\0'; i++) { word[i] = tolower(word[i]); } printf("lowercase: %s\n", word); return 0; }
Enter a word:
Hello
Single char: toupper('a') = A
Single char: tolower('Z') = z
UPPERCASE: HELLO
lowercase: hello
Proving It: Build Your Own strlen() and Reverse
If a string really is just a char array, you should be able to write your own length-finder and reverser using nothing but array indexing โ no string library required. This is the clearest possible proof that "string functions" are just ordinary array loops with a special stopping condition.
#include <stdio.h> int myStrlen(char str[]) { int count = 0; while (str[count] != '\0') { // keep counting until the terminator count++; } return count; } void myReverse(char str[]) { int len = myStrlen(str); for (int i = 0; i < len / 2; i++) { char temp = str[i]; str[i] = str[len - 1 - i]; str[len - 1 - i] = temp; } } int main() { char text[] = "CODE"; printf("Original : %s\n", text); printf("Length : %d (built with myStrlen, not strlen)\n", myStrlen(text)); myReverse(text); printf("Reversed : %s\n", text); return 0; }
Original : CODE Length : 4 (built with myStrlen, not strlen) Reversed : EDOC
Bonus: Case-Insensitive Vowel Counter
One last program that uses everything from this lesson together: read a full line safely with fgets(), walk it char by char, normalize each character with tolower() so "A" and "a" count the same way, and stop naturally at the null terminator.
#include <stdio.h> #include <ctype.h> #include <string.h> int main() { char sentence[100]; int vowels = 0, consonants = 0; puts("Enter a sentence:"); fgets(sentence, sizeof(sentence), stdin); sentence[strcspn(sentence, "\n")] = '\0'; for (int i = 0; sentence[i] != '\0'; i++) { char c = tolower(sentence[i]); // normalize case first if (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u') { vowels++; } else if (c >= 'a' && c <= 'z') { consonants++; } // spaces and punctuation are simply skipped } printf("Vowels : %d\n", vowels); printf("Consonants : %d\n", consonants); return 0; }
Enter a sentence: Hello World Vowels : 3 Consonants : 7
| Function | Header | Works on | Purpose |
|---|---|---|---|
| gets() | stdio.h | Whole string | Unsafe line input โ avoid |
| fgets() | stdio.h | Whole string | Safe, size-limited line input |
| puts() | stdio.h | Whole string | Print + auto newline |
| toupper() | ctype.h | One char | Convert to uppercase |
| tolower() | ctype.h | One char | Convert to lowercase |
Quick Quiz
What marks the end of a string stored in a char array?
Why is scanf("%s", name) a poor choice for reading a full name like "John Smith"?
Why is gets() considered dangerous?
Why can't toupper() convert a whole string in one call?
In a custom loop like while (str[count] != '\0'), what determines when the loop stops?
Lesson Checklist
- I understand a string is a char array ending in '\0'
- I can use gets() and puts() and explain what each does
- I understand why gets() can overflow a buffer
- I can use fgets() as a safer alternative
- I know toupper()/tolower() work on a single char, not a whole string
- I can loop through a string to convert its whole case
- I can write my own strlen() using array indexing
- I can reverse a string manually using a char array
- I completed the quiz