Pointers, Arrays & Strings - Part 2
This section covers more advanced string manipulation functions including concatenation, copying with limits, string comparison, and array operations.
Function Prototypes
char *_strcat(char *dest, char *src);
char *_strncat(char *dest, char *src, int n);
char *_strncpy(char *dest, char *src, int n);
int _strcmp(char *s1, char *s2);
void reverse_array(int *a, int n);
char *string_toupper(char *);
char *cap_string(char *);
char *leet(char *);
String Concatenation
_strcat()
Concatenates (appends) one string to another.
char *_strcat(char *dest, char *src)
{
int a;
int i;
a = -1;
for (i = 0; dest[i] != '\0'; i++)
;
while (src[++a] != '\0')
{
dest[i] = src[a];
i++;
}
return (dest);
}
How it works:
- Find the end of
dest string (first \0)
- Copy characters from
src to dest starting at that position
- The null terminator from
src automatically terminates the result
Example:
char dest[20] = "Hello";
char src[] = " World";
_strcat(dest, src);
// Result: dest = "Hello World"
The destination buffer must be large enough to hold both strings plus the null terminator. If dest is too small, buffer overflow occurs!char dest[6] = "Hello"; // Only room for 6 chars total
char src[] = " World"; // 6 chars + \0
_strcat(dest, src); // ⚠️ BUFFER OVERFLOW!
_strncat()
Concatenates up to n bytes from source string.
char *_strncat(char *dest, char *src, int n)
{
int legnth_dest, legnth_src, i;
for (legnth_dest = 0; dest[legnth_dest] != '\0'; legnth_dest++)
;
for (legnth_src = 0; src[legnth_src] != '\0'; legnth_src++)
;
for (i = 0; i < n && i < legnth_src; i++)
dest[legnth_dest + i] = src[i];
dest[legnth_dest + i] = '\0';
return (dest);
}
Key features:
- Copies at most
n characters
- Stops early if
src is shorter than n
- Always adds null terminator
Example:
char dest[20] = "Hello";
char src[] = " World";
_strncat(dest, src, 3);
// Result: dest = "Hello Wo"
Unlike strcat, strncat provides protection against copying too much data, but you still need to ensure the destination has enough space.
String Copying with Limits
_strncpy()
Copies up to n characters from source to destination.
char *_strncpy(char *dest, char *src, int n)
{
int i;
for (i = 0; i < n && src[i] != '\0'; i++)
dest[i] = src[i];
for (; i < n; i++)
dest[i] = '\0';
return (dest);
}
Important behavior:
- Copies characters until
n is reached OR null terminator is found
- If
src is shorter than n, fills remaining space with \0
- If
src is longer than n, does not add null terminator
Examples:
char dest[10];
char src1[] = "Hi";
char src2[] = "HelloWorld";
_strncpy(dest, src1, 5);
// dest = "Hi\0\0\0" (padded with nulls)
_strncpy(dest, src2, 5);
// dest = "Hello" (NO null terminator!)
If the source string is longer than n, strncpy does NOT null-terminate the destination. Always manually add a null terminator if needed:_strncpy(dest, src, n);
dest[n - 1] = '\0'; // Ensure null termination
String Comparison
_strcmp()
Compares two strings lexicographically.
int _strcmp(char *s1, char *s2)
{
int i;
for (i = 0; s1[i] != '\0' && s2[i] != '\0'; i++)
{
if (s1[i] != s2[i])
{
return (s1[i] - s2[i]);
}
}
return (0);
}
Return values:
0 if strings are equal
- Positive value if
s1 > s2
- Negative value if
s1 < s2
Examples:
_strcmp("abc", "abc"); // Returns 0 (equal)
_strcmp("abc", "abd"); // Returns negative (c < d)
_strcmp("abd", "abc"); // Returns positive (d > c)
_strcmp("ab", "abc"); // Returns negative (shorter)
Comparison is based on ASCII values:
'A' = 65, 'a' = 97
'B' = 66, 'b' = 98
'0' = 48, '9' = 57
Array Operations
reverse_array()
Reverses an array of integers in place.
void reverse_array(int *a, int n)
{
int i, j, temp;
i = 0;
j = n - 1;
while (i < j)
{
temp = a[i];
a[i] = a[j];
a[j] = temp;
i++;
j--;
}
}
Algorithm:
- Use two pointers: one at start, one at end
- Swap elements and move pointers toward center
- Stop when pointers meet
Example:
int arr[] = {1, 2, 3, 4, 5};
reverse_array(arr, 5);
// Result: {5, 4, 3, 2, 1}
Visualization:
[1, 2, 3, 4, 5]
i j → Swap: [5, 2, 3, 4, 1]
i j → Swap: [5, 4, 3, 2, 1]
i,j → Stop (i >= j)
string_toupper()
Converts all lowercase letters to uppercase.
char *string_toupper(char *s)
{
int i;
for (i = 0; s[i] != '\0'; i++)
{
if (s[i] >= 'a' && s[i] <= 'z')
{
s[i] = s[i] - 32;
}
}
return (s);
}
How it works:
- ASCII value of ‘a’ is 97, ‘A’ is 65
- Difference is 32
- Subtracting 32 converts lowercase to uppercase
Example:
char str[] = "Hello World!";
string_toupper(str);
// Result: "HELLO WORLD!"
ASCII conversion table:
'a' (97) - 32 = 'A' (65)
'b' (98) - 32 = 'B' (66)
'z' (122) - 32 = 'Z' (90)
This function modifies the string in place and returns the pointer, allowing for function chaining or immediate use of the result.
Practical Examples
Building a Full Name
char first[50] = "John";
char last[] = " Doe";
_strcat(first, last);
// first = "John Doe"
Safe String Copying
char buffer[10];
char input[] = "This is a very long string";
_strncpy(buffer, input, 9);
buffer[9] = '\0'; // Ensure null termination
// buffer = "This is a"
Case-Insensitive Comparison
char s1[] = "Hello";
char s2[] = "hello";
string_toupper(s1);
string_toupper(s2);
if (_strcmp(s1, s2) == 0)
printf("Strings are equal (case-insensitive)\n");
Common Pitfalls
1. Buffer Overflow in Concatenation
// ❌ BAD
char dest[10] = "Hello";
char src[] = " World!";
_strcat(dest, src); // Overflow! Needs 13 bytes, has 10
// ✅ GOOD
char dest[20] = "Hello";
char src[] = " World!";
_strcat(dest, src); // OK, enough space
2. Forgetting Null Terminator with strncpy
// ❌ BAD
char dest[5];
_strncpy(dest, "HelloWorld", 5);
printf("%s", dest); // May print garbage
// ✅ GOOD
char dest[5];
_strncpy(dest, "HelloWorld", 4);
dest[4] = '\0';
printf("%s", dest); // Prints "Hell"
3. Comparing Strings with ==
// ❌ BAD
char *s1 = "Hello";
char *s2 = "Hello";
if (s1 == s2) // Compares pointers, not strings!
// ✅ GOOD
if (_strcmp(s1, s2) == 0) // Compares string contents
String Length Caching
// Less efficient - recalculates length each iteration
for (int i = 0; i < _strlen(str); i++)
process(str[i]);
// More efficient - calculates once
int len = _strlen(str);
for (int i = 0; i < len; i++)
process(str[i]);
Key Takeaways
strcat appends strings but requires sufficient buffer space
strncat and strncpy limit bytes copied for safety
strncpy may not null-terminate if source is too long
strcmp returns difference in ASCII values, not just -1/0/1
- Always allocate enough space for concatenated strings
- In-place string modifications are efficient but destructive
- ASCII math enables easy case conversion (±32)