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. 字符串排序