C 基础 - 字符串与字符串函数

目的: 本文档是对C基础语法中字符串与字符串函数进行总结

 

本文目录

1. 字符串的表示

2. 字符串输入函数

3. 字符串输出函数

4. 字符串函数

 

1. 字符串的表示

字符串定义:C语言中,字符串是以空字符(\0)结尾的char类型数组

 

有以下几种定义字符串的方法

* 字符串常量

* char 类型数组

* 指向char的指针

 

1.1 在程序中定义字符串

第一种: 字符串字面量或叫字符串常量,用双引号拓起来的内容,在结尾会自动加入‘\0’。

printf("This is a string\n");

字符串常量 属于 静态存储类别

 

1.2 Char类型数组 && Char类型指针

初始化数组把静态存储区的字符串拷贝到数组中,而初始化指针只把字符串的地址拷贝给指针 

const char *pt1  =  "Something is pointing at me”;   /* 字符串首地址赋值给p1 */
const char ar1[] =  "Something is pointing at me";   /* 将字符串首地址赋值给ar1 且 进行拷贝 */

 

问题:数组形式 && 指针形式有何不同?

区别:数组名ar1是常量,而指针名pt1是变量。

 

相同点:

(1) 两者都可以使用数组表示法:

for(i=0; i<6; i++)
    putchar(pt1[i]);

putchar(‘\n’);

for(i=0; i<6; i++)
    putchar(ar1[i]);

 

(2) 两者都能进行指针加法操作:

for(i=0; i<6; i++)
    putchar( *(pt1 + i) );

putchar(‘\n’);

for(i=0; i<6; i++)
    putchar( *(ar1 + i) );

 

字符串数组与指针概念

/* 假设有下面的初始化 */
char car[10] = “Tata”;

那么,以下表达式都为真:

car == &car[0];   // car 是地址常量
*car == “T”;       // 解引用第一个字符
*(car + 1) == car[1] == ‘a’;  

 

注意:关于指针考虑的问题?

1. 该指针在内存中的地址是什么?

2. 该指针中存储的地址是什么?

 

 

2. 字符串输入函数

字符串的读入步骤:

步骤一:分配空间

步骤二:用输入函数获取该字符串

* gets()

* fgets()

* gets_s()

* scanf()

 

2.1 scanf函数

// 易于出错代码
char *name;
scanf("%s", name);

 

2.2 gets(str)函数

gets(str) 函数读取整行输入,直至遇到换行符,然后丢弃换行符,存储其余字符,并在未尾添加一个空字符使其成为一个C字符串。

gets() 函数可能出现警告信息, 只接受唯一的参数名,数组名会被转换成该数组首元素的地址,因此,gets()函数只知道数组的开始处,并不知道数组中有多少个元素。

如果输入的字符串过长,会导致 缓冲区溢出,即多余的字符串超出了指定的目标空间。  segmentation fault

 

/* gets函数常见用法 */
#define MAX_INPUT 1000

char input[MAX_INPUT];

while( gets( input ) != NULL ) {...}

 

2.3 fgets(str, len, stdin)函数

fgets(str, len, stdin) 函数 与 gets_s() 函数 ,相比gets的区别:

* fgets()函数的第二个参数指明了读入字符串的最大数量,如果值是n, 最大读入n-1个字符串,或者读到第一个换行符为止。

* 如果fgets()读到一个换行符,会把它存储在字符串中。

* fgets()的第3个参数指明要读取的文件,如果是从键盘读入,用stdin作为参数。

fgets(str, len, stdin);   // 输入
fputs(str, stdout);    // 输出

 

2.4 gets_s(str, len)函数

char gets_s(str, len);

与fgets()的区别

gets_s()只从标准输入中读取数据,所以不需要第3个参数。

如果get_s() 函数读到换行符,会丢弃而不是存储

如果gets_s()读到最大字符数都没有读到换行符,执行以下步骤

   step 1. 把目标数组中的首字符设置为空字符

   step 2. 读取并丢弃随后的输入直至读到文件结尾

   step 3. 返回空指针

 

/* 
 * s_gets() 函数是替换gets()不安全而写的
 * 读取整行输入并用代替换行符,或者读取一部分输入,
 * 并丢弃其余部分。
 * 如果返回NULL , 说明读到文件结尾或出现错误
 * st 是要读入的字符串
 * n  是读取字符串的长度
 */

char *s_gets(char *st , int n)
{
    char * ret_val;    /* 定义指针数组变量 */
    int i = 0;          /* i为数组下标 */
    
    /*
    /** 从标准输入中获取n个字符存入到st中, 返回首地址 
    /** 并赋值给ret_val指针数组变量
     */
    ret_val = fgets(st , n, stdin);
    
    if(ret_val) {
         while(st[i] != '\n' && st[i] != '\0') 
              i++;
         
         if(st[i] == '\n')
            st[i] = '\0';
         else
             while(getchar() != '\n')
                 continue;
    }  
    
    /* 返回字符串数组的首地址 */  
    return ret_val;
}

 

3. 字符串输出函数

puts(): 将字符串地址作为参数,遇到空字符串停止。

fputs() 与 puts的区别

* fputs 的第2个参数指明要写入数据的文件。

* 不会在末尾添加换行符。

printf()

 

4. 字符串函数(string.h)

(1) strlen()  /* 获取字符串长度 */

(2) strcat()

(3) strcmp()

(4) strncmp()

(5) strcpy()

(6) strchr()

(7) strnchr()

(8) strrchr()

(9) sprintf()

(10) memcmp()

(11) isspace(str)

(12) atoi(str)

 

4.1 strlen(str) 实现

size_t strlen(const char * str)
{
  const char *s;
  
  for(s = str; *s; ++s)
;
return(s - str); }

 

或者:

size_t strlen_s(const char * str)
{
  const char *s;
  s = str;
  while(*s) {
    s++;
  }
  return(s - str);
}

 

或者

/*
** 计算字符串的长度.
*/

#include <stdlib.h>

size_t
strlen(char const *string)
{
    int    length = 0;

    /*
    ** 依次访问字符串的内容,
    ** 计数字符串,直到遇到NUL终止符
    */
    while( *string++ != '\0' )
        length += 1;

    return length;
}

 

思路: 先将首地址赋值给s, 判断s的值是否为空,如果为非空,移动s的指针到下一个。

返回值为最后一个元素减去首地址元素的长度。

 

4.2 strcmp()函数实现

strcmp(cs,ct)函数比较两个字符串

  如果cs > ct ,  返回1

  如果cs = ct,   返回0

  如果cs < ct,   返回-1

 

/**
 * strcmp - Compare two strings
 * @cs: One string
 * @ct: Another string
 */
int strcmp(const char *cs, const char *ct)
{
    signed char __res;

    while (1) {
        if ((__res = *cs - *ct++) != 0 || !*cs++)  
            break;
    }
    return __res;
}

 

表达式解析: (__res = *cs - *ct++) != 0 || !*cs++

step 1. 执行 __res = *cs - *ct

step 2. 执行  ct++

step 3. 执行 __res != 0

      如果成立,结束循环,返回__res

      如果不成立,执行 !*cs 是否为非空, cs++ 

 

4.3 strcpy()的实现 

man 3 strcpy 查看 UNIX 函数手册 <string.h> 头文件, lib/string.c 

char *strcpy(char *to, const char *from)
{
    assert( to != NULL && from != NULL);   // 判断to 与 NULL 是否为非空
    char *p = to;                          // 拷贝将要复制的的开始地址
   
    while((*p++ = *from++) != '\0')        // * 与 ++ 的优先级相同 先运行 *from 再指针自增
        ;

    return to;   // 返回字符串的首地址
}

 

4.4 strstr()的实现

思路: 遍历haystack中的值,与needle进行比较

如果没有,则返回haystack

如果有,返回第一个位置

char * strstr(const char *haystack, const char *needle)
{
    if(! *needle) return (char *) haystack;

    const char * p1;
    const char * p2;
    const char *p1_advance = haystack;

   for(p2 = &needle[1]; *p2; ++p2) {
       p1_advance++;
   }

   for(p1 = haystack; *p1_advance; p1_advance++) {
        char * p1_old = (char *) p1;
        p2 = needle;
        while( *p1 && *p2 && *p1 == *p2) {
            p1++;
            p2++;
         }
        if(! *p2) return p1_old;

        p1 = p1_old +1;
   }
  
    return NULL;
}

 

字符串搜索

/*
 * 编写一个函数,在一个字符串中进行搜索,
 * 查找所有在一个给定字符集合中出现的字符。
 *   查找source字符串中匹配chars字符串中任何字符
 *   的第1个字符,函数返回一个指向source中第1个匹配
 *   所找到的位置的指针。
 *   如果任何一个参数为NULL,或者任何一个参数指向的
 *   字符串为空,函数也返回一个NULL指针
 */
#include <stdio.h>

/*
 ** 假定:source 指向ABCDEF
 ** 如果chars 指向XYZ或JURY或QQQQ,返回NULL
 ** 如果chars 指向XRCQEF,返回C字符串的指针
 */
char *find_char(char const *source, char const *chars)
{
    char const *sc1, *sc2;
    for(sc1 = source; *sc1 != '\0'; sc1++)
    {
        for(sc2 = chars; *sc2 != '\0'; sc2++)
        {
            if(*sc1 == *sc2)
            {
                return (char *) sc1;
            }
        }
    }
    return NULL;
}

int main(void)
{
    char *source = "ABCDEF";
    char *chars = "XYZ";
    char *ch;

    ch = find_char(source, chars);
    if(ch)
        puchar(*ch);
    else 
        puts("Not Find!");
    return 0;
}

 

 

 

4.5 strchr()的实现

查找字符串s中是否存在字符c, 存在返回该字符在str中的位置,否则返回NULL

从字符串开始位置查找

/**
 * strchr - Find the first occurrence of a character in a string
 * @s: The string to be searched
 * @c: The character to search for
 */
char *strchr(const char *s, int c)
{
    for (; *s != (char)c; ++s)
        if (*s == '\0')
            return NULL;
    return (char *)s;
}

 

多列字符串进行查找

/*
** 给定一个指向以NULL结尾的指针列表的指针,
** 在列表中的字符串中查找一个特定的字符。
*/

#include <stdio.h>

#define    TRUE    1
#define    FALSE    0

int
find_char( char **strings, char value )
{
    char    *string;    /* 当前正在查找的字符串 */

    /*
    ** while循环处理的三件事
    **  1) 将*string当前字符串取出赋给string
    **  2) strings++ 移动到下一个字符串
    **  3)string 判断是否为空
    */
    while( ( string = *strings++ ) != NULL ){
        /*
        ** 观察字符串中的每个字符,
        ** 与value值进行比较
        */
        while( *string != '\0' ){
            if( *string++ == value )
                return TRUE;
        }
    }
    return FALSE;
}

 

 

或者

/*
** 给定一个指向以NULL结尾的指针列表的指针,
** 在列表中的字符串中查找一个特定的字符。
** 这个函数将破坏这些指针,所以它只适用于
** 这组字符串只使用一次的情况
*/

#include <stdio.h>
#include <assert.h>

#define    TRUE    1
#define    FALSE    0

int
find_char( char **strings, int value )
{
    assert( strings != NULL );

    /*
    ** 对于列表中的每个字符串
    */
    while( *strings != NULL ){
        /*
        ** 观察字符串中的每个字符
        **  1) *(*strings) 当前列中的字符
        **  2) 与value值进行比较
        **  3) (*strings)字符移动到下一个
        */
        while( **strings != '\0' ){
            if( *(*strings)++ == value )
                return TRUE;
        }
        strings++;
    }
    return FALSE;
}

 

 

4.6 strrchr()的实现

从末尾开始查找

/**
 * strrchr - Find the last occurrence of a character in a string
 * @s: The string to be searched
 * @c: The character to search for
 */
char *strrchr(const char *s, int c)
{
       const char *p = s + strlen(s);
       do {
           if (*p == (char)c)
               return (char *)p;
       } while (--p >= s);
       return NULL;
}

 

 

4.8 memcmp(cs, ct, count)函数

比较内存区域cs 与 ct两个字符串前count个字节

当cs > ct ,返回1

当cs == ct, 返回0

当 cs < ct, 返回 -1

int memcmp(const void *cs, const void *ct, size_t count)
{
    const unsigned char *su1, *su2;
    int res = 0;

    for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
        if ((res = *su1 - *su2) != 0)
            break;
    return res;
}

 

 

4.9 实现atoi(str)

将一个字符串转化为整数

// atoi.c
#include <stdio.h>
#include <string.h>
#include <limits.h>

int atoi(const char *str)
{
  int num = 0;
  int sign = 1;
  const int len = strlen(str);  // 获取字符串的长度
  int i = 0;

  while(str[i] == ' ' && i < len)  // 去除字符串中首空格
    i++;

  if(str[i] == '+')
    i++;

  if(str[i] == '-') {     // 如果是减号,为负数
    sign = -1;
    i++;
  }

  for(; i < len; i++) {
    if(str[i] < '0' || str[i] > '9') break;   // 结束循环

    if(num > INT_MAX / 10 || (num == INT_MAX / 10 && (str[i]- '0') > INT_MAX % 10))
      return sign == -1 ? INT_MIN : INT_MAX;

    num = num * 10 + str[i] - '0';
  }

  return num * sign;
}

int main(void)
{
  char str[] = "80923DDdd900";
  int  result  = atoi(str);
  printf("result = %d\n", result);
  return 0;
}

 

4.10 isspace()

编写一个函数,输入一个字符串,要求做一个新字符串,把其中

所有的一个或多个连续的空白字符都压缩为一个空格。 这里所说

的空白空格包括: \t , \n, \r

例如: 输入以下

this Content hoho     is OK

ok?

    file system 

uttered words ok     ok    ?

end.

 

输出以下:

this Content hoho is OK ok? file system uttered words ok ok? end.

#include <stdio.h>  
#include <ctype.h>  
#include <stdlib.h>  
#include <string.h>  

/*
 * 压缩字符串函数
 */
char *shrink_space(char *dest, const char *src, size_t n)
{
    int i = 0;
    char *tmp = dest;

    while(i < n && *src != '\0'){
        if(!isspace(*src))
            *tmp++ = *src++;
        else
        {
            src++;
            if(isspace(*src))
                continue;
            else 
                *tmp++ = ' ';
        }
        i++;
    }
    *tmp = '\0';
    return dest;
}


int main(void)  
{  
    char src[] = "This Content hoho     is ok\n    \
                ok?\n                              \
                                                   \
                                file system        \
                                uttered words ok ok    ?\n  \
                                end." ;  
    /* 为dest分配内存 */
    char *dest = (char *)malloc(sizeof(char)*(strlen(src)+1));  
  
    printf("origin:%s\n",src);  
    printf("shrink:%s\n",shrink_space(dest, src, strlen(src)));  
    
    /* 为dest释放内存 */
    free(dest);  
    dest = NULL;  
    return 0;  
}  

 

 

9. KMP算法

Boyer-Moore 算法

Rabin-Karp 算法

 

10. 写一个在一个字符串(n)中寻找一个子串(m)第一个位置的函数。

 

11. 字符串排序

 

 

 

 

 

 

 

 

 

posted @ 2017-10-12 20:44  elewei  阅读(340)  评论(0编辑  收藏  举报