String Length Functions
strlen
Unbounded String Functions
strcpy
strcat
strcmp
Bounded String Funcsions
strncpy
strncat
strncmp
String Search Functions
strstr
strtok
Error Reporting Functions
strerror
Character Classification Functions
Character Case Conversion
Memory Operation Functions
memcpy
memmove
memcmp
memset
String Length Functions
strlen
Function Overview
size_t strlen(const char *str);
The strlen function measures string length according to several important principles. First, strings in C are terminated by the null character '\0', and strlen returns the count of characters that appear before this terminating null character, not including the null character itself. Second, the string parameter must point to a null-terminated character sequence for accurate results. Third, the return type is size_t, which is an unsigned integer type, meaning the result is always non-negative and arithmetic operations on the return value follow unsigned integer rules.
Practical Implementations
There are multiple approaches to implementing a custom strlen function, each demonstrating different programming concepts in C.
The first method uses a counter to iterate through the string until it encounters the null terminator:
size_t custom_strlen(const char* input)
{
assert(input != NULL);
size_t length = 0;
while (input[length] != '\0')
{
length++;
}
return length;
}
The second method leverages pointer arithmetic to achieve the same result:
size_t custom_strlen(const char* input)
{
const char* end = input;
while (*end != '\0')
{
end++;
}
return end - input;
}
The third approach demonstrates recursion to calculate string length:
size_t custom_strlen(const char* input)
{
if (*input == '\0')
{
return 0;
}
return 1 + custom_strlen(input + 1);
}
int main(void)
{
const char* message = "Hello, World!";
printf("Length: %zu\n", custom_strlen(message));
return 0;
}
Unbounded String Functions
strcpy
Function Overview
char* strcpy(char* destination, const char* source);
The strcpy function copies an entire string from a source location to a destination buffer. The function includes the null terminator in the copy operation, ensuring the destination becomes a complete, valid string. Proper usage requires that the source string is null-terminated, the destination buffer has sufficient capacity to hold the entire source string including the null terminator, and the destination memory is writable. The function returns a pointer to the destination buffer, allowing for function chaining in expressions.
Practical Implementation
char* custom_strcpy(char* dest, const char* src)
{
assert(dest != NULL && src != NULL);
char* result = dest;
while ((*dest++ = *src++) != '\0')
{
/* Loop continues until null terminator is copied */
}
return result;
}
int main(void)
{
char buffer[50] = "XXXXXXXXXXXXXXXXXXXXXXXXXXXX";
const char* text = "Programming in C";
custom_strcpy(buffer, text);
printf("Copied string: %s\n", buffer);
return 0;
}
strcat
Function Overview
char* strcat(char* destination, const char* source);
The strcat function appends one string to the end of another. It locates the null terminator of the destination string and then copies characters from the source string beginning at that position, including the source's null terminator. The destination buffer must have enough remaining space to accommodate the appended content plus the null terminator, and the destination must be modifiable memory. A critical limitation is that a string cannot be concatenated to itself using strcat, because the function begins by searching for the null terminator and would never find it when the source and destination overlap in memory.
Practical Implementation
char* custom_strcat(char* dest, const char* src)
{
assert(dest != NULL && src != NULL);
char* start = dest;
/* Find the end of destination string */
while (*dest != '\0')
{
dest++;
}
/* Append source string */
while ((*dest++ = *src++) != '\0')
{
/* Continue copying until null terminator */
}
return start;
}
int main(void)
{
char sentence[100] = "The quick brown ";
const char* fox = "fox jumps over the lazy dog";
printf("Result: %s\n", custom_strcat(sentence, fox));
return 0;
}
strcmp
Function Overview
int strcmp(const char* str1, const char* str2);
The strcmp function performs lexicographical comparison between two strings by examining their characters sequentially. It returns a positive integer when the first string is greater than the second, zero when the two strings are identical, and a negative integer when the first string is less than the second. The comparison operates on ASCII values: characters are compared one by one from the beginning of both strings, and the comparison stops as soon as differing characters are found or when the null terminator is reached in both strings.
Practical Implementation
int custom_strcmp(const char* first, const char* second)
{
while (*first == *second)
{
if (*first == '\0')
{
return 0; /* Both strings are identical */
}
first++;
second++;
}
return *(unsigned char*)first - *(unsigned char*)second;
}
int main(void)
{
const char* word1 = "Apple";
const char* word2 = "Banana";
int result = custom_strcmp(word1, word2);
printf("Comparison result: %d\n", result);
return 0;
}
Bounded String Functions
strncpy
Function Overview
char* strncpy(char* destination, const char* source, size_t num);
The strncpy function provides a safer alternative to strcpy by limiting the number of characters copied. It transfers exactly num characters from the source to the destination, or fewer if the source string is shorter than num. When the source string is shorter than the specified count, the function pads the remaining positions in the destination with null characters to ensure the total written equals num. This behavior differs from naive string copying and ensures consistent memory behavior regardless of source string length.
strncat
Function Overview
char* strncat(char* destination, const char* source, size_t num);
The strncat function appends at most num characters from the source string to the destination. Unlike strncpy, strncat always appends a null terminator after the copied characters, regardless of whether the source string was fully consumed. If the num parameter exceeds the length of the source string, the entire source is appended followed by the null terminator, effectively making strncat behave like strcat in such cases while maintaining safe behavior when num is smaller than the source length.
strncmp
Function Overview
int strncmp(const char* str1, const char* str2, size_t num);
The strncmp function compares strings up to a maximum of num characters, providing a bounded comparison that prevents reading beyond string boundaries. The comparison proceeds character by character up to num positions or until a difference is found, whichever comes first. This function is particularly useful when comparing fixed-length fields or when only a prefix of strings needs evaluation for ordering purposes.
String Search Functions
strstr
Function Overview
char* strstr(const char* str1, const char* str2);
The strstr function locates the first occurrence of a substring within a larger string. It returns a pointer to the beginning of the first match of the search pattern within the text, or NULL if no match exists. The function treats the search pattern as a complete substring, not as a set of individual characters to be found anywhere in the text.
Practical Implementation
char* custom_strstr(const char* text, const char* pattern)
{
if (*pattern == '\0')
{
return (char*)text; /* Empty pattern matches at beginning */
}
const char* pattern_start = pattern;
while (*text != '\0')
{
/* Find potential starting position */
while (*text != *pattern && *text != '\0')
{
text++;
}
if (*text == '\0')
{
break; /* No more possible matches */
}
const char* text_ptr = text;
const char* pattern_ptr = pattern;
/* Verify full pattern match */
while (*text_ptr == *pattern_ptr)
{
text_ptr++;
pattern_ptr++;
if (*pattern_ptr == '\0')
{
return (char*)text; /* Complete match found */
}
}
/* Move to next position and reset pattern */
text++;
pattern = pattern_start;
}
return NULL; /* Pattern not found */
}
int main(void)
{
const char* haystack = "The quick brown fox jumps over the lazy dog";
const char* needle = "fox";
char* position = custom_strstr(haystack, needle);
if (position != NULL)
{
printf("Found at position: %ld\n", position - haystack);
}
else
{
printf("Pattern not found\n");
}
return 0;
}
strtok
Function Overview
char* strtok(char* str, const char* sep);
The strtok function parses strings into tokens based on a set of delimiter characters. The sep parameter defines the characters that serve as separators between tokens. When str is not NULL, the function finds the first token in the string, replaces the delimiter that terminates it with a null character, and returns a pointer to the beginning of that token. The function maintains internal state, so subsequent calls with NULL as the first argument continue parsing from where the previous call left off. Important constraints include: the function modifies the original string, so work with a copy; delimiters are replaced with null characters during tokenization; and the function returns NULL when no more tokens can be found.
Error Reporting Functions
strerror
Function Overveiw
char* strerror(int errnum);
The strerror function translates error codes into human-readable error messages. When standard library functions encounter errors during execution, they store an error code in the global errno variable. The strerror function takes this error number as input and returns a pointer to a statically allocated string describing the corresponding error. This mechanism provides a standard way to retrieve diagnostic information when library operations fail, enabling proper error handling and debugging in C programs.
Character Classification Functions
Character Case Conversion
int tolower(int c);<br></br>int toupper(int c);
These functions convert individual characters between uppercase and lowercase representations. The tolower functon converts uppercase letters to their lowercase equivalents, leaving non-uppercase characters unchanged. Similarly, toupper converts lowercase letters to uppercase while preserving other characters. These functions are essential for case-insensitive string processing operations.
A practical example transforms an entire string to lowercase:
void convert_to_lowercase(char* text)
{
for (size_t i = 0; text[i] != '\0'; i++)
{
if (isupper((unsigned char)text[i]))
{
text[i] = tolower((unsigned char)text[i]);
}
}
}
int main(void)
{
char message[] = "HELLO WORLD";
convert_to_lowercase(message);
printf("Lowercase: %s\n", message);
return 0;
}
Memory Operation Functions
memcpy
Function Overview
void* memcpy(void* destination, const void* source, size_t num);
The memcpy function copies a specified number of bytes from a source memory location to a destination, operating at the byte level rather than the string level. Unlike strcpy, memcpy does not stop at null characters and will copy exactly the requested number of bytes regardless of content. This makes it suitable for copying binary data or structured memory blocks. The function returns a pointer to the destination for convenient chaining. A critical limitation is that memcpy cannot handle overlapping memory regions safely; for such cases, memmove must be used instead.
Practical Implementation
void* custom_memcpy(void* dest, const void* src, size_t bytes)
{
assert(dest != NULL && src != NULL);
unsigned char* destination = (unsigned char*)dest;
const unsigned char* source = (const unsigned char*)src;
for (size_t i = 0; i < bytes; i++)
{
destination[i] = source[i];
}
return dest;
}
int main(void)
{
int source_data[] = {100, 200, 300, 400, 500};
int destination[5] = {0};
custom_memcpy(destination, source_data, sizeof(source_data));
printf("First element: %d\n", destination[0]);
return 0;
}
memmove
Function Overview
void* memmove(void* destination, const void* source, size_t num);
The memmove function provides the same byte-copying capability as memcpy but with support for overlapping memory regions. When the source and destination buffers overlap, memmove handles the copy correctly by determining the optimal direction based on memory addresses. If the destination address is lower than the source, copying proceeds from low to high addresses; otherwise, it copies from high to low addresses to prevent data corruption during the copy operation.
Practical Implementation
void* custom_memmove(void* dest, const void* src, size_t bytes)
{
assert(dest != NULL && src != NULL);
unsigned char* destination = (unsigned char*)dest;
const unsigned char* source = (const unsigned char*)src;
/* Determine copy direction based on memory layout */
if (destination < source)
{
/* Copy forward from low addresses */
for (size_t i = 0; i < bytes; i++)
{
destination[i] = source[i];
}
}
else
{
/* Copy backward from high addresses */
for (size_t i = bytes; i > 0; i--)
{
destination[i - 1] = source[i - 1];
}
}
return dest;
}
int main(void)
{
int data[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
size_t data_size = sizeof(data);
/* Shift elements two positions to the right, overlapping region */
custom_memmove(data + 2, data, 20);
printf("Modified array:\n");
for (int i = 0; i < 10; i++)
{
printf("%d ", data[i]);
}
printf("\n");
return 0;
}
memcmp
Function Overview
int memcmp(const void* ptr1, const void* ptr2, size_t num);
The memcmp function compares byte sequences in memory, returning the relationship between the two blocks. It compares the first num bytes of both memory regions and returns zero if they are identical, a negative value if the first differing byte in ptr1 is less than that in ptr2, and a positive value if the byte in ptr1 is greater. This function operates on raw bytes and does not treat any byte as a special terminator, making it suitable for comparing binary data structures or fixed-length records.
memset
Function Overview
void* memset(void* ptr, int value, size_t num);
The memset function initializes a block of memory with a specified byte value. It sets the first num bytes of the memory region pointed to by ptr to the given value, which is interpreted as an unsigned char. This function is commonly used for zero-initializing memory or setting memory regions to known patterns for security purposes or initialization before use.