Skip to main content
Code Review

Return to Question

replaced http://codereview.stackexchange.com/ with https://codereview.stackexchange.com/
Source Link

A follow-up on this this. To quote by copy/paste:

A follow-up on this. To quote by copy/paste:

A follow-up on this. To quote by copy/paste:

Tweeted twitter.com/StackCodeReview/status/834255407115812865
Source Link
anon
anon

StringBuilder in C v2: Not a charged dance

A follow-up on this. To quote by copy/paste:

Lots of languages have something that lets you build up a dynamically-sized string with minimal overhead. C doesn't, and I found myself using code that did that manually in a couple of places, so I packaged it into a class. Note that I've only implemented functionality I'm using.

###stringbuilder.h

It's the same as last time.

#ifndef CONCATEN_STRINGBUILDER_H
#define CONCATEN_STRINGBUILDER_H
#include <stddef.h>
#include <stdbool.h>
struct StringBuilder;
typedef struct StringBuilder *StringBuilder;
StringBuilder sb_new(size_t);
bool sb_append(StringBuilder, char);
char *sb_as_string(StringBuilder);
char *sb_free_copy(StringBuilder);
size_t sb_size(StringBuilder);
void sb_free(StringBuilder);
#endif //CONCATEN_STRINGBUILDER_H

###stringbuilder.c

#include <stdlib.h>
#include <string.h>
#include "stringbuilder.h"
struct StringBuilder {
 char *mem;
 size_t count;
 size_t cap;
};
StringBuilder sb_new(size_t init_cap) {
 if (init_cap == 0) {
 return NULL;
 }
 StringBuilder ret = malloc(sizeof(struct StringBuilder));
 if (!ret) return NULL;
 ret->mem = calloc(init_cap, sizeof(char));
 if (!ret->mem) {
 free(ret);
 return NULL;
 }
 ret->cap = init_cap;
 ret->count = 0;
 return ret;
}
#define LOAD_FACTOR 2
bool sb_append(StringBuilder to, char c) {
 if (to->count + 1 == to->cap) {
 char *new_mem = realloc(to->mem, to->cap * LOAD_FACTOR);
 if (!new_mem) {
 return false;
 }
 memset(new_mem + to->cap, 0, to->cap);
 to->mem = new_mem;
 to->cap *= LOAD_FACTOR;
 }
 ++to->count;
 to->mem[to->count - 1] = c;
 return true;
}
char *sb_as_string(StringBuilder sb) {
 return sb->mem;
}
char *sb_free_copy(StringBuilder sb) {
 char *ret = malloc((sb->count + 1) * sizeof(char));
 if (!ret) {
 return NULL;
 }
 strcpy(ret, sb->mem);
 ret[sb->count] = 0;
 sb_free(sb);
 return ret;
}
size_t sb_size(StringBuilder sb) {
 return sb->count;
}
void sb_free(StringBuilder sb) {
 if (sb) {
 if (sb->mem) free(sb->mem);
 free(sb);
 }
}

This time around, I'm concerned most about... exactly the same things:

  • Performance. This code gets called a lot. I want it to be as fast as possible.
  • Memory safety. While I'm fairly sure that this doesn't leak memory (assuming it's used properly), I'm not confident, and I'm not sure how to check.
  • Edge cases. It works, as far as I can tell, but that doesn't mean that it's bug-free.

Also,

  • Portability. Will this code be compileable on any (C11-conforming and/or major) compiler? I want the code that uses this to be as simple to deploy on as many platforms as possible.

Note that I specifically am not asking for advice on functions that would be nice to have. I'm only spending the time to implementing things I'm going to use; this isn't part of a general-purpose utility library, so I really don't care about supporting all the features when I use a tiny fraction of them.

lang-c

AltStyle によって変換されたページ (->オリジナル) /