C语言数据结构之顺序结构,字符串(String)的基本功能
字符串(String)是最常用的顺序结构(序列sequence)
- string.h头文件中有很多常用的函数,包含进来随时调用!!!
- 自定义数据结构 struct String,成员包括:
- 字符指针char *elts,指向将要分配内存的字符数组
- int length 字符串长度
- int page 分配内存的页数,宏SPSIZE来指定每页的长度,为便于测试,这里定义值为8,测试无误后重定义为128来提高效率。
首先实现常用功能:创建new、释放free、尾部追加append。
代码如下:
/* filename: string.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* define string page size */
#define SPSIZE 8
/* define String datatype struct _String */
typedef struct _String String;
struct _String {
char *elts;
int length;
int page;
};
/* new string with SPSIZE bytes memory fill 0 */
String *
string_new0 (void)
{
String *str = (String*) malloc (sizeof(String));
str->elts = (char*) malloc (SPSIZE * sizeof(char));
memset (str->elts, 0, SPSIZE);
str->page = 1; str->length = 0;
return str;
}
/* new string from char* */
String *
string_new (char *c)
{
String *str = string_new0 ();
int len = strlen (c);
if (len > SPSIZE)
{
str->page = len/SPSIZE + 1;
str->elts = (char*) realloc (str->elts, str->page * SPSIZE);
memset (str->elts, 0, str->page * SPSIZE);
}
for (int i = 0; i < len; i++)
str->elts[i] = c[i];
str->length = len;
return str;
}
/* free the String */
void
string_free (String *str)
{
free (str->elts);
free (str);
}
/* append char* to string */
void
string_append (String *st, char *ca)
{
int len = st->length + strlen (ca);
if (len > st->page * SPSIZE)
{
st->page = len/SPSIZE + 1;
st->elts = (char*) realloc (st->elts, st->page * SPSIZE);
}
for (int i = st->length, j = 0; i < len; i++, j++)
st->elts[i] = ca[j];
st->elts[len] = 0;
st->length = len;
}
/* ------------------------------ */
/* output string infomation for test */
void
string_info (String *st)
{
printf ("%s\n", st->elts);
printf ("Page : %d, Length : %d\n", st->page, st->length);
}
/**/
void
test_string_new (void)
{
String *sta = string_new ("");
String *stb = string_new ("Not only a test!");
string_info (sta);
string_info (stb);
string_free (sta);
string_free (stb);
}
/**/
void
test_string_append (void)
{
String *st = string_new ("Not");
string_info (st);
string_append (st, " only");
string_info (st);
string_append (st, " a");
string_info (st);
string_append (st, " test");
string_info (st);
string_append (st, " here!");\
string_info (st);
string_free (st);
}
/**/
#define outline() printf ("------------------------------\n")
/**/
int
main (int argc, char *argv[])
{
test_string_new (); outline ();
test_string_append (); outline ();
return 0;
}
/* --):-o-:(-- */
编译运行,测试结果如下:
songvm@ubuntu:~/works/xdn/soo$ gcc string.c -o string
songvm@ubuntu:~/works/xdn/soo$ ./string
Page : 1, Length : 0
Not only a test!
Page : 3, Length : 16
------------------------------
Not
Page : 1, Length : 3
Not only
Page : 1, Length : 8
Not only a
Page : 2, Length : 10
Not only a test
Page : 2, Length : 15
Not only a test here!
Page : 3, Length : 21
------------------------------
字符串前追加功能 prepend
- string_prepend 函数,代码如下:
/* pre append char* to string */
void
string_prepend (String *st, char *ca)
{
char *buf, *tmp;
int len = strlen (ca);
int lx = st->length + len;
if (lx >= st->page * SPSIZE)
st->page = lx / SPSIZE + 1;
buf = (char*) malloc (st->page * SPSIZE * sizeof(char));
memset (buf, 0, st->page * SPSIZE);
for (int i = 0; i < len; i++)
buf[i] = ca[i];
for (int i = len, j = 0; i < lx; i++, j++)
buf[i] = st->elts[j];
tmp = st->elts;
st->length = lx;
st->elts = buf;
free (tmp);
}
- 测试函数test_string_prepend代码如下:
/**/
void
test_string_prepend (void)
{
String *st = string_new ("AAA");
string_info (st);
string_prepend (st, "BBB ");
string_info (st);
string_prepend (st, "CCC ");
string_info (st);
string_prepend (st, "DDD ");
string_info (st);
string_prepend (st, "EEE ");
string_info (st);
string_free (st);
}
编译运行,结果如下:
songvm@ubuntu:~/works/xdn/soo$ gcc string.c -o string
songvm@ubuntu:~/works/xdn/soo$ ./string
AAA
Page : 1, Length : 3
BBB AAA
Page : 1, Length : 7
CCC BBB AAA
Page : 2, Length : 11
DDD CCC BBB AAA
Page : 2, Length : 15
EEE DDD CCC BBB AAA
Page : 3, Length : 19
------------------------------
songvm@ubuntu:~/works/xdn/soo$
字符串插入功能 INSERT
- string_insert 函数,代码如下:
/* insert char* to string at idx */
void
string_insert (String *st, int idx, char *ca)
{
char *buf, *tmp;
int len = strlen (ca);
int lx = len + st->length;
if (lx >= st->page * SPSIZE)
st->page = lx / SPSIZE + 1;
buf = (char*) malloc (st->page * SPSIZE * sizeof(char));
memset (buf, 0, st->page * SPSIZE);
for (int i = 0; i < idx; i++)
buf[i] = st->elts[i];
for (int j = idx, k = 0; j < len + idx; j++, k++)
buf[j] = ca[k];
for (int i = len + idx, j = idx; i < lx; i++, j++)
buf[i] = st->elts[j];
st->length = lx;
tmp = st->elts;
st->elts = buf;
free (tmp);
}
- 测试函数test_string_insert代码如下:
/**/
void
test_string_insert (void)
{
String *st = string_new ("AA AA");
string_info (st);
string_insert (st, 3, "BB BB");
string_info (st);
string_insert (st, 6, "CC CC");
string_info (st);
string_insert (st, 9, "DD DD");
string_info (st);
string_insert (st, 12, "EE EE");
string_info (st);
string_free (st);
}
编译运行,结果如下:
songvm@ubuntu:~/works/xdn/soo$ gcc string.c -o string
songvm@ubuntu:~/works/xdn/soo$ ./string
AA AA
Page : 1, Length : 6
AA BB BB AA
Page : 2, Length : 12
AA BB CC CC BB AA
Page : 3, Length : 18
AA BB CC DD DD CC BB AA
Page : 4, Length : 24
AA BB CC DD EE EE DD CC BB AA
Page : 4, Length : 30
------------------------------
songvm@ubuntu:~/works/xdn/soo$
字符串删除功能 ERASE
- 删除全部函数 string_erase_all
- 删除部分函数 string_erase_section
代码如下:
/* erase all at pos to end */
void
string_erase_all (String *st, int pos)
{
if (pos >= st->length) return; //do nothing
for (int i = pos; i < st->length; i++)
st->elts[i] = 0;
st->length = pos;
}
/* erase section at pos length eq len */
void
string_erase_section (String *st, int pos, int len)
{
if (pos >= st->length) return; //do nothing
for (int i = pos; i < pos + len; i++)
st->elts[i] = 0;
for (int i = pos + len, j = pos; i < st->length; i++, j++)
st->elts[j] = st->elts[i];
for (int i = st->length - len; i < st->length; i++)
st->elts[i] = 0;
st->length = st->length - len;
}
- 测试函数test_string_erase代码如下:
/**/
void
test_string_erase (void)
{
String *st = string_new ("AAABBBCCCXXXYYYZZZ");
string_info (st);
string_erase_all (st, 8);
string_info (st);
string_free (st);
st = string_new ("AAABBBCCCXXXYYYZZZ");
string_erase_section (st, 8, 7);
string_info (st);
string_free (st);
}
编译运行,结果如下:
songvm@ubuntu:~/works/xdn/soo$ gcc string.c -o string
songvm@ubuntu:~/works/xdn/soo$ ./string
AAABBBCCCXXXYYYZZZ
Page : 3, Length : 18
AAABBBCC
Page : 3, Length : 8
AAABBBCCZZZ
Page : 3, Length : 11
------------------------------
songvm@ubuntu:~/works/xdn/soo$
去掉字符串前后的空格功能 TRIM
- string_trim 函数,代码如下:
/* string trim space tab newline at head and tail */
void
string_trim (String *st)
{
int start, end;
char *tmp, *buf;
buf = (char*) malloc (st->page * SPSIZE * sizeof(char));
for (int i = 0; i < st->length; i++)
if (st->elts[i] != ' ' && st->elts[i] != '\t' && st->elts[i] != '\n')
{ start = i; break; }
for (int i = st->length - 1; i >=0; i--)
if (st->elts[i] != ' ' && st->elts[i] != '\t' && st->elts[i] != '\n')
{ end = i; break; }
for (int i = start, j = 0; i <= end; i++, j++)
buf[j] = st->elts[i];
st->length = end - start + 1;
tmp = st->elts;
st->elts = buf;
free (tmp);
}
- 测试函数test_string_trim代码如下:
/**/
void
test_string_trim (void)
{
String *sta = string_new ("www.baidu.com");
String *stb = string_new (" www.baidu.com");
String *stc = string_new ("www.baidu.com ");
String *std = string_new (" www.baidu.com ");
string_trim (sta);
string_info (sta);
string_trim (stb);
string_info (stb);
string_trim (stc);
string_info (stc);
string_trim (std);
string_info (std);
string_free (sta);
string_free (stb);
string_free (stc);
string_free (std);
}
编译运行,结果如下:
songvm@ubuntu:~/works/xdn/soo$ gcc string.c -o string
songvm@ubuntu:~/works/xdn/soo$ ./string
www.baidu.com
Page : 2, Length : 13
www.baidu.com
Page : 2, Length : 13
www.baidu.com
Page : 3, Length : 13
www.baidu.com
Page : 3, Length : 13
------------------------------
songvm@ubuntu:~/works/xdn/soo$
字符串倒序功能 REVERSE
- string_reverse 函数,代码如下:
/* reverse string */
void
string_reverse (String *st)
{
for (int i = 0, n = st->length - 1; i < st->length / 2; i++, n--)
{
char t = st->elts[i];
st->elts[i] = st->elts[n];
st->elts[n] = t;
}
}
- 测试函数test_string_reverse代码如下:
/**/
void
test_string_reverse (void)
{
String *st = string_new ("ABCDEFGHIJKLMNOPQRSTUVWXYZ0");
string_info (st);
string_reverse (st);
string_info (st);
string_free (st);
}
编译运行,结果如下:
songvm@ubuntu:~/works/xdn/soo$ gcc string.c -o string
songvm@ubuntu:~/works/xdn/soo$ ./string
ABCDEFGHIJKLMNOPQRSTUVWXYZ0
Page : 4, Length : 27
0ZYXWVUTSRQPONMLKJIHGFEDCBA
Page : 4, Length : 27
------------------------------
songvm@ubuntu:~/works/xdn/soo$
取子字符串功能 SUBSTRING
- string_sub 函数,代码如下:
/* get substring from a string */
String*
string_sub (String *st, int pos, int len)
{
String *tmp = NULL;
int ln = 0;
if (pos >= st->length) return tmp;
if ((pos + len) > st->length)
ln = st->length;
else
ln = pos + len;
tmp= string_new ("");
for (int i = pos, j = 0; i < ln; i++, j++)
tmp->elts[j] = st->elts[i];
tmp->length = len;
return tmp;
}
- 测试函数test_string_sub代码如下:
/**/
void
test_string_sub (void)
{
String *tmp;
String *st = string_new ("Another string object test!");
string_info (st);
tmp = string_sub (st, 8, 6);
if (tmp == NULL)
printf ("Get substring is NULL!\n");
else
{
string_info (tmp);
string_free (tmp);
}
string_free (st);
}
编译运行,结果如下:
songvm@ubuntu:~/works/xdn/soo$ gcc string.c -o string
songvm@ubuntu:~/works/xdn/soo$ ./string
Another string object test!
Page : 4, Length : 27
string
Page : 1, Length : 6
------------------------------
songvm@ubuntu:~/works/xdn/soo$
字符串替换功能 REPLACE
- string_replace 函数,代码如下:
/* test src eq dst if true return 1 else return 0 */
static int
streq (char *src, char *dst)
{
for (int i = 0; i < strlen (dst); i++)
if (src[i] != dst[i]) return 0;
return 1;
}
/* replace src in string to dst */
void
string_replace (String *st, char *src, char *dst)
{
int i, j, k = -1;
int ls = strlen (src);
int ld = strlen (dst);
char *buf, *tmp = st->elts;
if (ls > st->length)
{ printf ("Info: String no change!\n"); return; }
for (i = 0; i < st->length - ls + 1; i++)
if (1 == streq (&tmp[i], src))
{ k = i; break; }
if (k == -1) { printf ("Info: String not found!\n"); return; }
if (ls == ld)
{
for (i = 0, j = k; j < k + ls; j++, i++)
st->elts[j] = dst[i];
}
else
{
int ln = st->length;
ln = ln + ld - ls;
if (ls < ld)
st->page = ln / SPSIZE + 1;
buf = (char*) malloc (st->page * SPSIZE * sizeof(char));
for (i = 0; i < k; i++)
buf[i] = st->elts[i];
for (int n = 0; n < ld; n++, i++)
buf[i] = dst[n];
for (int n = k + ls; n < st->length; n++, i++)
buf[i] = st->elts[n];
st->length = ln;
tmp = st->elts;
st->elts = buf;
free (tmp);
}
}
- 测试函数test_string_replace代码如下:
/**/
void
test_string_replace (void)
{
String *sa, *st;
st = string_new ("Not only a test here!");
string_info (st);
printf ("--------------\nreplace a to XXXX\n");
string_replace (st, "a", "XXXX");
string_info (st);
printf ("--------------\nreplace XXXX to a\n");
string_replace (st, "XXXX", "a");
string_info (st);
printf ("--------------\n");
sa = string_new ("Hello [name], good lucky!");
string_info (sa);
string_replace (sa, "[name]", "Jack Tomson");
string_info (sa);
string_free (sa);
string_free (st);
}
编译运行,结果如下:
songvm@ubuntu:~/works/xdn/soo$ gcc string.c -o string
songvm@ubuntu:~/works/xdn/soo$ ./string
Not only a test here!
Page : 3, Length : 21
--------------
replace a to XXXX
Not only XXXX test here!
Page : 4, Length : 24
--------------
replace XXXX to a
Not only a test here!
Page : 4, Length : 21
--------------
Hello [name], good lucky!
Page : 4, Length : 25
Hello Jack Tomson, good lucky!
Page : 4, Length : 30
------------------------------
songvm@ubuntu:~/works/xdn/soo$
以上字符串功能函数基本实现,测试通过
下一步,再研究一下关于字符串的HASHCODE和其他操作!!!