The following code implements a simple interface to operate on mutable* Strings in C. It is composed of two files: one for the structure definition and the available operations, and the other with the actual implementation.
*This can be inexact, as only adding characters to the end is implemented.
Any comments on coding style and improvements are greatly appreciated.
String.h
#ifndef __STRING_H__
#define __STRING_H__
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#define BLOCK_SIZE 256
typedef struct {
char *data;
int length;
int blocks;
} String;
String * string_create();
void string_dispose(String *str);
bool string_empty(String *str);
void string_append_char(String *str, char c);
char * string_get_all(String *str);
char string_get(String *str, int pos);
int string_find(String *str, char c);
#endif /* __STRING_H__ */
String.c
#include "String.h"
/** Create a String */
String * string_create() {
String *ans = calloc(1, sizeof *ans);
if (ans != NULL) {
ans->data = malloc( BLOCK_SIZE * sizeof *(ans->data) );
ans->length = 0;
ans->blocks = (ans->data == NULL) ? 0 : 1;
}
return ans;
}
/** Free the memory associated with a String */
void string_dispose(String *str) {
if (str != NULL) {
free(str->data);
free(str);
}
}
/** Is the String empty? */
bool string_empty(String *str) {
if (str == NULL) return true;
if (str->length == 0) return true;
return false;
}
/** Add a character to the end of the String */
void string_append_char(String *str, char c) {
if (str != NULL) {
if (str->length == str->blocks * BLOCK_SIZE) {
char *new_str = realloc( str->data, BLOCK_SIZE * (str->blocks + 1) * sizeof *(str->data));
if (new_str != NULL) {
str->data = new_str;
++(str->blocks);
}
}
if (str->length < str->blocks * BLOCK_SIZE) {
str->data[str->length] = c;
++(str->length);
}
}
}
/** Get a C-String with the proper null-terminator */
char * string_get_all(String *str) {
char *res = NULL;
if (str != NULL) {
res = malloc((str->length + 1) * sizeof *str->data);
if (res != NULL) {
memcpy(res, str->data, str->length);
res[str->length] = '\0';
}
}
return res;
}
/** Get a character at a given position in the String */
char string_get(String *str, int pos) {
char res = '\0';
if (str != NULL) {
if (pos >= 0 && pos < str->length) {
res = str->data[pos];
}
}
return res;
}
/** Get where the first occurrence of a character in the String is */
int string_find(String *str, char c) {
int pos = -1;
if (str != NULL) {
pos = 0;
while (str->data[pos] != c) ++pos;
if (pos == str->length) pos = -1;
}
return pos;
}
This is a test file that uses some of the core methods implemented in a String. This file is called test_string.c.
#include <stdio.h>
#include "String.h"
int main() {
String *str = string_create();
char i;
for (i = 'a'; i <= 'z'; i++)
string_append_char(str, i);
char *cstr = string_get_all(str);
printf("%s\n", cstr);
int pos = string_find(str, 'f');
printf("Character 'f' occurs at position %d.\n", pos);
printf("Reading from the String, we get \"%c\".\n", string_get(str, pos));
free(cstr);
string_dispose(str);
return 0;
}