Implementacje funkcji ze string.h

Autor: Wojciech Muła
Dodany:21.11.2001
Aktualizacja:13.10.2005

Treść

Wprowadzenie

Ot tak, dla rozrywki, postanowiłem samodzielnie zakodować większość funkcji dostępnych w string.h. Może się przydać do szkoły lub na uczelnie. Dokładne opisy funkcji są dostępne pod adresem http://www.delorie.com/djgpp/doc/libc/.

Przedstawię również kilka dodatkowych, niestandardowych funkcji, które mogą się przydać.

Funkcje standardowe (string.h)

strcpy

Funkcja kopiuje łańcuch znaków.

char *strcpy(char *dest, const char *src)
{
 char* p=dest;
 while (*dest++ = *src++);
 return p;
}

strcat

Funkcja dołącza łańcuch.

char *strcat(char *dest, const char *src)
{
 char* p=dest;

 while (*dest) dest++;      /* przejdź na koniec łańcucha docelowego */
 while (*dest++ = *src++);  /* dołącz łańcuch źródłowy */

 return p;
}

Jest to równoważne:

strcpy(dest[strlen(dest)+1], src);

strchr

Funkcja zwraca wskaźnik do pierwszego wystąpienia znaku c, jeśli nie zostanie on znaleziony wynikiem funkcji jest NULL.

char *strchr(const char *s, int c)
{
 char* temp = (char*)s;

 while (*temp && *temp != c) temp++;

 if (*temp == '\0')
        return NULL;

 return temp;
}

strcmp

Funkcja zwraca różnicę kodów ASCII pierwszego różniącego się znaku. Jeśli porównywane łańcuchy są identyczne zwraca 0.

int strcmp(const char *s1, const char*s2)
{
 while ((*s1) && (*s2) && (*s1==*s2)) s1++, s2++;

 return (int)*s1-(int)*s2;
}

Aby wszystko było w porządku należałoby zrzutować s1 i s2 na char*, gdyż obie zmienne są stałymi wskaźnikami. Nie chcę zaciemniać kodu zbędnymi zmiennymi, poza tym kompilator może rzucić co najwyżej ostrzeżeniem.

strcspn

Funkcja zwraca indeks pierwszego znaku z s1 należącego do zbioru znaków set.

size_t strcspn(const char *s, const char *set)
{
 size_t pos = 0;
 char *temp;

 while (*s)          /* przetwarzaj wszystkie znaki łańcucha */
  {

   temp = (char*)set;
   while (*temp)                  /* porównaj każdy znak ze zbioru z bieżącym znakiem */
     if (*s == *temp) return pos; /* zwróć indeks bieżącego znaku gdy należy on do zbioru */
                 else temp++;

   s++;
   pos++;
  }
 return pos;
}

strlen

Funkcja zwraca długość łańcucha, nie uwzględnia kończącego zera.

size_t strlen(const char* string)
{
 size_t len = 0;
 while (*string++) len++;
 return len;
}

strncat

Funkcja dołącza maksymalnie n znaków.

char* strncat(char *s1, const char *s2, size_t n)
{
 size_t num    = 0;
 char*  result = s1;

 while (*s1) s1++;

 while ((*s1++ = *s2++) && (++num < n));

 *s1 = 0;
 return result;
}

strncmp

Funkcja porównuje maksymalnie n znaków.

int strncmp(const char *s1, const char *s2, size_t n)
{
 size_t num = 0;
 while ((*s1) && (*s2) && (*s1==*s2) && (++num < n)) s1++, s2++;

 return (int)*s1-(int)*s2;
}

strncpy

Funkcja kopiuje maksymalnie n znaków.

char* strncpy(char *s1, const char *s2, size_t n)
{
 char*  result = s1;
 size_t num    = 0;

 while ((*s1++ = *s2++) && (++num < n));
 *s1 = 0;  /* dopisz kończące zero - w standardzie tego nie ma! */
 return result;
}

strpbrk

Funkcja zwraca adres pierwszego znaku z s1 należącego do zbioru set.

char* strpbrk(const char *s, const char *set)
{
 char *temp;

 while (*s)
  {
   temp = (char*)set;
   while (*temp)      /* process set */
     if (*s == *temp) return (char*)s;
                  else temp++;
   s++;
  }
 return NULL;
}

strrchr

Zwraca adres ostatniego wystąpienia znaku c, lub NULL gdy w łańcuchu s1 nie ma tego znaku.

char *strrchr(const char *s, int c)
{
 char* result = NULL;

 while (*s)
  {
   if (*s == c)
        result = (char*)s;
   s++;
  }

 return result;
}

strspn

Funkcja zwraca indeks pierwszego znaku z s1 nie należącego do zbioru znaków set.

size_t strspn(const char *s, const char *set)
{
 size_t pos = 0;
 char *temp;

 while (*s)
  {
   temp = (char*)set;
   while (*temp) {
     if (*s == *temp) break;
     temp++;
   }

   if (*temp == '\0')
     break;

   s++;
   pos++;
  }

 return pos;
}

strstr

Funkcja zwraca adres początku łańcucha s2 występującego w s1.

char* my_strstr(char* s, char* s1)
{
 if ((*s1 == '\0') || (*s == '\0'))
        return NULL;

 while (*s)
   {
    char* temp1 = s;
    char* temp2 = s1;

    while (*temp1 == *temp2 && *temp1 && *temp2)
        temp1++, temp2++;

    if (*temp2 == '\0')
        return s;
    else
       if (*temp1 == '\0')
         return NULL;
    s++;
   }
}

strtok

Funkcja zwraca kolejne słowa (ang. tokens), oddzielone znakami z s2.

char *strtok(char *s1, const char *s2)
{
 static char* result;
 char* temp;

 if (s1) result=s1;
    else while (*result++);

 temp = (char*)s2;
 while (*temp)
  {
   if (*result == *temp)
     {
      temp = (char*)s2;
      result++;
      continue;
     }
   temp++;
  }

 s1 = result;
 while (*s1)
  {
   temp = (char*)s2;
   while ((*s1 != *temp) && (*temp)) temp++;
   if (*temp == 0) s1++;
   else break;
  }
 *s1 = 0;
 return result;
}

Można zgrabnie zapisać tę funkcję przy użyciu funkcji strcspn i strspn.

Funkcje niestandardowe

strrev

Funkcja odwraca kolejność znaków w łańcuchu.

/* 21.11.2001

   char e[256] = "Kajak";
   strrev(e);

   e=="kajaK"
*/
void strrev(char* e)
{
 char* s=e;
 char  t;

 if (!*e) return;

 while (*e) e++;
 e--;

 while (s <= e)
  {
   t = *s;
  *s = *e;
  *e =  t;
   s++;
   e--;
  }
}

strtrim

Funkcja „ucina” znaki kończące łańcuch.

/* 12.12.2001, 15.11.2002

   char s[256] = "jakiś tekst----------------";
   strtim(s, '-');

   s == "jakiś tekst"
*/
char* strtrim(const char *s, char c)
{
 char* l = s;

 s--;
 while (*(++s))
       if (*s != c) l = s;
 *l = '\0';
 return (char*)s;
}

strrepchar

Funkcja zamienia znaki.

/* 13.12.2001

  char *s = "long file name.mp3";
  strreplchar(s, ' ', '_');

  s=="long_file_name.mp3"
*/
char* strreplchar(char *str, char from, char to)
{
 char *c = str;

 while (*c)
   {
    if (*c == from) *c = to;
    c++;
   }

 return str;
}

strignore

Funkcja kopiuje łańcuchy pomijając wskazany znak.

/* 12.12.2001

   char *s = "  te sp  a  cje          s ą zupe     łnie zbęd  n  e";
   char  d[256];
   strigniore(d,s, ' ');

   d=="tespacjesązupełniezbędne"
*/
char* strignore(char* dst, const char* src, char c)
{
 char *s = (char*)src;
 char *d = dst;

 while (*s)
  {
   if (*s != c) *d++ = *s;
   s++;
  }
 *d = 0;
 return dst;
}

strremdup

Funkcja kopiuje łańcuch pomijając powtarzające się znaki.

/* 12.12.2001

   char *s = "1111122233344445555555666666677777778888888";
   char  d[256];
   strremdup(d, s);

   d=="12345678"
*/
char* strremdup(char* dst, const char* src)
{
 char *s = (char*)src;
 char *d = dst;

 char last = 0;
 while (*s)
  {
   if (*s != last) *d++ = last = *s;
   s++;
  }
 *d = 0;
 return dst;
}

compresspaces

Funkcja usuwa nadmiarowe spacje.

/* 13.08.2002

   char *s = "  Linux    does    it    better       ";
   compresspaces(s);

   s = " Linux does it better "
*/
char* compresspaces(const char* S)
{
 char *s   = (char*)S;
 char prev = '1';

 while (*S)
  {
   if ((prev != ' ') || (*S != ' '))
         *s++ = *S;

   prev = *S++;
  }
 *s = '\0';
 return S;
}

strremove

Funkcja usuwa wskazany fragment łańcucha.

/* 7.12.2001

   char *s = "to słowo jest zbędne";
   strremove(s, 3, 6);

   s=="to jest zbędne"
*/
char* strremove(char* str, int pos, int length)
{
 char* p = str+pos;
 char* t = str+pos+length;

 if (p < str+strlen(str))
 if (t > str+strlen(str)) str[pos]=0; else
  {
   while (*t) *p++ = *t++;
   *p=0;
  }

 return str;
}

strinsert

/* 13.12.2001

   char s[256] = "http://.republika.pl";
   strinsert(s, "asmcorner", 6);

   s=="http://asmcorner.republika.pl"
*/
char* strinsert(char* str, const char* new_str, int pos)
{
 int str_len = strlen(str);
 int new_len = strlen(new_str);

 int tocopy = str_len - pos;       /* 14 znaków do skopiowania */

 char* s = str + str_len-1;
 char* e = s   + new_len;

 while (tocopy--) *e-- = *s--;     /* str == "http://.republik.republika.pl"  */
 s = str+pos;                      /* po czym skopiuje                        */
 e = (char*)new_str;               /* łańcuch na właściwą pozycję             */
 while (*e) *s++ = *e++;           /* str == "http://asmcorner.republika.pl"  */

 return str;
}

strcharc

Funkcja oblicza ilość wystąpień znaku.

/* 7.12.2001

   char *s = "xx001x011"
   if (strchrc(s, 'x') == 3)
        puts("3 razy X")
*/
size_t strchrc(const char* str, char c)
{
 size_t num = 0;
 char   *n = (char*)str;
 while (*n)
  {
   if ( (n=(char*)strchr(n, c))==NULL) break;
   num++;
   n+=1;
  }
 return num;
}

match_parentcheses

/* 7.12.2001

   char *s = "być może (albo na pewno) tak nie jest";
   char  d[256];
   match_parentcheses(d, s, '(', ')');

   d == "(albo na pewno)"
*/
char* match_parentcheses(char* dst, const char* src, char left, char right)
{
 char *A = (char*)strchr(src, left);
 char *B = (char*)strchr(src, right);

 if ((A) && (B) && (A < B))
  {
   strncpy(dst, A, B-A+1);
   dst[B-A+1] = 0;
  }
 else
  dst[0] = 0;

 return dst;
}

match_parentcheses2

/* 7.12.2001

   char *s = "być może (albo na pewno) tak nie jest";
   char  d[256];
   match_parentcheses(d, s, '(', ')');

   d == "albo na pewno"
*/
char* match_parentcheses2(char* dst, const char* src, char left, char right)
{
 char *A = (char*)strchr(src, left);
 char *B = (char*)strchr(src, right);

 if ((A) && (B) && (A < B))
  {
   strncpy(dst, A+1, B-A-1);
   dst[B-A-1] = 0;
  }
 else
  dst[0] = 0;

 return dst;
}

match_pair

/* 7.12.2001

   char *s = "niemniej jednak *istotą* sprawy..."
   char  d[256];
   match_pair(d, s, '*');

   d=="*istotą*"
*/
char* match_pair(char* dst, const char* src, char c)
{
 char *A = (char*)strchr(src, c);
 char *B = (char*)strchr(A+1, c);

 if ((A) && (B))
  {
   strncpy(dst, A, B-A+1);
   dst[B-A+1] = 0;
  }
 else
  dst[0] = 0;

 return dst;
}

match_pair2

/* 7.12.2001

   char *s = "niemniej jednak *istotą* sprawy..."
   char  d[256];
   match_pair(d, s, '*');

   d=="istotą"
*/
char* match_pair2(char* dst, const char* src, char c)
{
 char *A = (char*)strchr(src, c);
 char *B = (char*)strchr(A+1, c);

 if ((A) && (B))
  {
   strncpy(dst, A+1, B-A-1);
   dst[B-A-1] = 0;
  }
 else
  dst[0] = 0;

 return dst;
}