As C does not have a native string
type, I decided to try making a similar type. It's not perfect by any means, so I was coming here to see what I could do to improve it.
I have tested my code and it works; if I were to write 'User', the output would then be 'Hello User'
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct string_t; //predeclare for access in str_node
typedef struct str_node {
struct str_node* next; //next node in list
struct string_t* mystr;//string associated
} s_node;
s_node* mhead = NULL;//head of node list
typedef struct string_t {
char* mybuf; //buffer
size_t mycap; //capacity of string
} string; //definition of string
string* new_string()
{
string* str = malloc(sizeof(string));//allocate a new string
str->mybuf = NULL;//set the pointer to null so that it will not be deallocated if string is not used
str->mycap = 0;//set the capacity to 0
//add string to list of strings so that it can be deallocated in free_strings()
s_node** nptr = &mhead;
while ((*nptr) != NULL) {
nptr = &((*nptr)->next);//point to the next node before free
} //find the last node in the list
(*nptr) = malloc(sizeof(s_node));//allocate a node
(*nptr)->mystr = str;//set the string associated
(*nptr)->next = NULL;//set the next node as null
return (str);//return the new object
}
void fstr(string* str)
{
//free a specific string
if (str->mybuf != NULL) {
free(str->mybuf);//free pointer if not null
}
if (str != NULL) {
free(str);//free string object if not null
}
}
void free_strings()
{
//free all allocated strings and remove node list
s_node* nptr = mhead;
while (nptr != NULL) {
//free the string
fstr(nptr->mystr);
s_node* next = nptr->next;//point to the next node before free
free(nptr);//free the node
nptr = next;//now point to the next
}
}
size_t length(string* str)
{
//if str->mybuf is null, return 0, otherwise strlen(str->mybuf)
return ((str->mybuf == NULL) ? (0)
: (strlen(str->mybuf)));
}
void ensure_capacity(string* str,
size_t cap)
{
if (str->mybuf == NULL) {
//allocate memory
str->mybuf = malloc(cap);
str->mycap = cap;
}
else if (str->mycap < cap) {
//reallocate
str->mybuf = realloc(str->mybuf, cap);
str->mycap = cap;
}
}
void trim(string* str,
size_t len)
{
//set null terminator at str->mybuf + len if necessary
if (length(str) > len) {
memset(str->mybuf + len, 0, 1);
}//set null character at len
}
void set_length(string* str,
size_t len)
{
ensure_capacity(str, len + 1);//ensure capacity for len and null '\0'
trim(str, len);//trim str to len characters if necessary
}
string* set(string* str,
const char* value)
{
//set the length, reallocates if appropriate
set_length(str, strlen(value));
strcpy(str->mybuf, value);//copy the string value
return (str);//return str
}
string* append(string* str,
const char* value)
{
//set length, reallocate if appropriate
set_length(str, strlen(value) + length(str));
strcat(str->mybuf, value);//concatenate
return (str);//return str
}
string* substring(string* str,
size_t idx,
size_t len)
{
string* substr = new_string();//create a new string
set(substr, str->mybuf + idx);//set the value of the string to the begin of the substring
trim(substr, len);//trim the substring to len characters
return (substr);//return the substring
}
void shrink_to_fit(string* str)
{
//return unused memory to system
size_t len = length(str) + 1;//ensure space for null character
if (len < str->mycap) {
//unused memory to return
str->mybuf = realloc(str->mybuf, len);//reallocate to a smaller buffer
str->mycap = len;//set capacity to smaller size
}
}
string* read_from_n(FILE* stream,
size_t bufsize)
{
string* buf = new_string();//allocate a new string to hold buffer
ensure_capacity(buf, bufsize);//set a capacity of bufsize to hold input
fgets(buf->mybuf, bufsize, stream);//get from stream into buffer
shrink_to_fit(buf);//return spare memory, if any, to system
}
#define DEFAULT_READ_BUFFER_SIZE 1024
string* read_from(FILE* stream)
{
//read_from_n using a defined buffer size
return (read_from_n(stream, DEFAULT_READ_BUFFER_SIZE));
}
int main(void)
{
string* s = new_string();
set(s, "Hello World");
string* sub = substring(s, 0, 6);
append(sub, read_from(stdin)->mybuf);
printf(sub->mybuf);
getchar();
free_strings();
}