数组
数组是一组具有相同类型元素组成的集合。
1.一维数组
1.1一维数组的创建和初始化
数组的创建方式:
type_t arr_name [const_n];
例: int arr[10] char ch[12] float date[30]
注: 在C99标准之前,数组的大小必须是常量或者常量表达式;在C99标准之后,数组大小可以是变量,是为了支持变长数组。( char ch[ n] 这种数组是不能初始化的)
1.2数组的初始化
数组的初始化,指在创建数组时给数组的内容一些合理的值。 例:
int arr[10] = {1, 2, 3};
int arr2[] = {1, 2, 3, 4, 5, 6};
char ch[4] = {'a', 'b', 'c', 'd'};
char ch2[] = {'a', 99, 'd'};
char ch3[] = "abcdef";
数组在创建的时候如果想不指明数组的确定大小就得初始化。数组的元素个数根据初始化的内容来确定。
但是对于下面的代码要区分,内存中如何分配。
char ch1[] = "abc";
char ch2[] = {'a','b','c'};
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
在内存中栈区找了一块连续的空间来存放1,2,3,4,5,6,7,8,9,10。 我们给这块空间取名为arr。 就像在酒店排了十个连续的房间,而每个房间都有一个编号,在C语言中,这个编号从0开始,这里的编号就是数组的下标。 通过数组的下标访问数组的元素,每个下标对应一个元素。
1.3一维数组的使用
#include <stdio.h>
int main()
{
int arr[10] = {0};
int sz = sizeof(arr)/sizeof(arr[0]);
int i = 0;
for(i=0; i<10; i++)
{
arr[i] = i;
}
for(i=0; i<10; ++i)
{
printf("%d ", arr[i]);
}
return 0;
}
sizeof(arr) ,计算的是整个数组的大小;sizeof(arr[0]) ,计算的是一个元素所占字节数。
例1.3.1:用数组实现Fibonacci数列问题。
#include<stdio.h>
int main()
{
int i = 0;
int f[20] = { 0 };
f[0] = f[1] = 1;
for (i = 2; i < 20; i++) {
f[i] = f[i - 2] + f[i - 1];
}
for (i = 0; i < 20; i++) {
printf("%d ", f[i]);
}
printf("\n");
return 0;
}
此题还可拓展到求第n个元素的值。
#include<stdio.h>
int main()
{
int n = 0;
int i = 0;
scanf("%d", &n);
int f[n] = { 0 };
f[0] = f[1] = 1;
for (i = 2; i < n; i++) {
f[i] = f[i - 2] + f[i - 1];
}
for (i = 0; i < n; i++) {
printf("%d ", f[i]);
}
printf("\n");
return 0;
}
例1.3.2:对数组元素进行排序。
#include<stdio.h>
int main(){
int arr[10] = {0};
int i = 0, j = 0;
printf("输入:");
for(i = 0; i < 10; i++){
scanf("%d",&arr[i]);
}
for(j = 0; j < 9; j++){
for(i = 0; i < 9 - j; i++){
if(arr[i] > arr[i+1]){
int tmp = arr[i];
arr[i] = arr[i+1];
arr[i+1] = tmp;
}
}
}
printf("输出:");
for(i = 0; i < 10; i++){
printf("%d ",arr[i]);
}
printf("\n");
return 0;
}
1.4 数组名
数组名确实能表示首元素的地址 但是,有两个例外:
- sizeof(数组名),这里的数组名表示的是整个数组,计算的是整个数组的大小,单位是字节
- &数组名,这里的数组名表示整个数组,取出的是整个数组的地址
1.5一位数组在内存中的存储
#include<stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int i = 0;
int sz = sizeof(arr) / sizeof(arr[0]);
for (i = 0; i < 10; i++)
{
printf("&arr[%d] = %p\n", i, &arr[i]);
}
return 0;
}
地址是用十六进制表示的,从结果中看出,每个整型数组元素占了四个字节。且随着数组下标的增长,元素的地址,也在有规律的递增。 由此可以得出:数组在内存中是连续存放的。
2.二维数组
二维数组通常叫矩阵。把二维数组写成行(row)和列(column)的排列形式。
2.1二维数组的创建
把多组数据都存储起来,用二维数组。
int arr[3][4];
char arr[2][5];
float arr[4][3];
double arr[3][3];
2.2二维数组的初始化
int arr1[3][4] = {1,2,3,4,2,3,4,5,3,4,5,6};
int arr2[3][4] = {1,2,3,4,5};
int arr3[3][4] = {{1,2},{3,4},{5}};
int arr4[][4] = {{1,2},{3}};
当数据不够时,自动补零。
2.3二维数组的使用
二维数组的使用也是通过下标的方式。
#include <stdio.h>
int main()
{
int arr[3][4] = {0};
int i = 0;
for(i=0; i<3; i++)
{
int j = 0;
for(j=0; j<4; j++)
{
scanf("%d",&arr[i][j]);
}
}
for(i=0; i<3; i++)
{
int j = 0;
for(j=0; j<4; j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");
}
return 0;
}
可以将二维数组看做是一维数组,即可理解为一维数组的数组
2.4二维数组在内存中的存储
二维数组在内存中也是连续存储的。
#include <stdio.h>
int main()
{
int arr[3][4];
int i = 0;
for(i=0; i<3; i++)
{
int j = 0;
for(j=0; j<4; j++)
{
printf("&arr[%d][%d] = %p\n", i, j,&arr[i][j]);
}
}
return 0;
}
2.5二维数组的数组名的理解
int main()
{
int arr[3][4];
printf("%p\n",arr);
return 0;
}
求数组一行或一列的大小
printf("%d\n",sizeof(arr)/sizeof(arr[0]));
printf("%d\n",sizeof(arr[0])/sizeof(arr[0][0]));
3.数组越界
数组的下标是有范围限制的。 数组的下标规定从0开始,如果有n个元素,那数组的最后一个元素的下标就是n-1。 故,数组的下标小于零,或大于n-1,就是数组越界访问,超出了数组合法空间的访问。 C语言本身是不做数组下标的越界检查,编译器也不一定报错,但是编译器不报错,并不意味着程序就是正确的,所以程序员写代码时,最好自己做越界的检查
#include<stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int i = 0;
for (i = 0; i <= 13; i++)
{
printf("%d\n", arr[i]);
}
return 0;
}
二维数组的行和列也可能存在越界。
4.字符数组和字符串
4.1字符数组的创建
第一个入门篇中介绍了,字符型数据是以ASCII码存储在内存单元中的,一个数组元素占一个字节单位。 一维字符数组:char ch[10]; 二维字符数组:char ch[5][5];
4.2字符数字的初始化及使用
4.2.1一维字符数组
char ch1[10] = { 'H','e','l','l','o','w','o','r','l','d'};
char ch2[] = { 'H','e','l','l','o','w','o','r','d' };
char ch3[15] = { 'H','e','l','l','o','w','o','r','l','d' };
char ch4[] = "Helloworld";
4.2.2二维字符数组
char arr[5][5] = { {' ',' ','*'},{' ','*','*','*'},{'*','*','*','*','*'},{' ','*','*','*'},{' ',' ','*'} };
#include<stdio.h>
int main()
{
char arr[5][5] = { {' ',' ','*'},{' ','*','*','*'},{'*','*','*','*','*'},{' ','*','*','*'},{' ',' ','*'} };
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
printf("%c", arr[i][j]);
}
printf("\n");
}
return 0;
}
4.3字符串
在C语言中,将字符串作为字符数组来处理。 字符串的有效长度并不是数组的长度。 字符串是以 ’ \0 ’ 作为结束标志的。字符串遇到 ’ \0 ’ 则结束。 C语言中,在字符数组存储字符串常量时会自动补上 ’ \0 ’ 作为结束符。
4.3.1字符串的创建和初始化
char d[] = { 'H','e','l','l','o',' ','W','o','r','l','d','!','\0' };/这样表示字符串过于繁杂。
char arr[] = {"Hello World!"};
char ch[] = "Hello World!";
4.3.2字符串函数
重点掌握!!!:
- 求字符串长度
strlen - 长度不受限的字符串长度
strcpy strcat strcmp - 长度受限的字符串长度
strncpy strncat strncmp - 字符串查找
strstr strtok - 错误信息报告
strerror
字符串函数的模拟实现如有错误,还望指出。仅做为参考实现代码 ,并不唯一。
1.gets()和puts()——输入和输出字符串
puts() 将字符串输出到终端。 用puts()函数输出的字符串中可以包含转义字符。 char str[] = {“Hello\nWorld”};
Hello
World
在用 puts 输出时将字符串结束标志 ’ \0 ’ 转换成 ’ \n ’ ,即输出完字符串后换行。
gets() 从终端输入字符串到字符数组。 一般利用 gets 函数的目的是向字符数组输入一个字符串,而不太关心起函数值。
注意: 用 puts 和 gets 函数只能输出或输入一个字符串。
#include <stdio.h>
int main(int argc, const char * argv[]) {
char a[100];
gets(a);
puts(a);
return 0;
}
2.strlen——求字符串长度
size_t strlen(const char *str);
- 字符串以\0作为结束标志,求字符串长度时,只求\0之前的所有字符数,不包含’ \0 ‘。
#include<stdio.h>
#include<string.h>
int main()
{
char arr[] = "abcdef";
int len = strlen(arr);
printf("len = %d\n", len);
return 0;
}
#include<stdio.h>
#include<string.h>
int main()
{
char arr[] = {'a','b','c','d','e','f'};
int len = strlen(arr);
printf("len = %d\n", len);
return 0;
}
这里为什么是输出19,而不是6呢?
在内存中,数组是连续存储的,而字符串以\0为结束标志,内存中不知道哪里放置了\0,故数组会越界查找,直到遇上\0才停止。
正确写法:
char arr[] = {'a','b','c','d','e','f','\0'};
- 注意函数的返回值为
size_t ,是无符号的整型unsigned int ( 易错 )
#include <stdio.h>
#include<string.h>
int main()
{
const char*str1 = "abcdef";
const char*str2 = "bbb";
if(strlen(str2)-strlen(str1)>0)
{
printf("str2>str1\n");
}
else
{
printf("srt1>str2\n");
}
return 0;
}
运行程序时,发生了错误,无法正常运行。
就是因为strlen返回类型是size_t,是一个无符号的,-3被当做是无符号数来处理时,就是一个非常大的正数。
#include<stdio.h>
#include<string.h>
#include<assert.h>
size_t my_strlen(const char* str) {
assert(*str);
int count = 0;
while (*str != '\0')
{
count++;
str++;
}
return count;
}
int main()
{
char arr[] = "abcdef";
size_t len = my_strlen(arr);
printf("%u\n", len);
return 0;
}
长度不受限制的字符串函数:
3.strcpy ——字符串拷贝
char* strcpy(char * destination, const char * source );
将字符串 str2 拷贝到 str1 中去。
#include <stdio.h>
#include<string.h>
int main()
{
char str1[20] = { 0 };
char str2[] = "zhangsan";
strcpy(str1, str2);
printf("%s\n", str1);
return 0;
}
注意: 切不可写成 arr1 = "zhangsan" ,arr1 数组名是地址,地址是一个常量值,不能被赋值。 而 “zhangsan” 要存放到空间里去。
#include <stdio.h>
#include<string.h>
int main()
{
char str1[20] = { 0 };
char str2[] = {'b','y','t','e'};
strcpy(str1, str2);
printf("%s\n", str1);
return 0;
}
由于不知何时会遇见\0,所以数组很有可能会进行越界访问。
#include<stdio.h>
#include<string.h>
int main()
{
char name[20] = {0};
strcpy(name,"zhang\0san");
printf("%s\n",name);
return 0;
}
那是否真的将\0拷贝到目标空间内了呢? 测试一下:
#include<stdio.h>
#include<string.h>
int main()
{
char name[20] = "xxxxxxx";
strcpy(name,"zhang\0san");
printf("%s\n",name);
return 0;
}
拷贝前:
拷贝后:
事实证明,确实将\0拷贝到了目标空间内。
#include <stdio.h>
#include<string.h>
int main()
{
char str1[2] = { 0 };
char str2[] = "abcdef";
strcpy(str1, str2);
printf("%s\n", str1);
return 0;
}
str1 放不下,但非要放进去,就形成了越界访问。
错误代码:
char *p = "abcdef";
char arr[] = "byte";
strcpy(p,arr);
版本1:
#include <stdio.h>
#include<string.h>
#include<assert.h>
char* my_strcpy(char* dest, char* src) {
assert(dest);
assert(src);
char* ret = dest;
while (*src)
{
*dest++ = *src++;
}
*dest = *src;
return ret;
}
int main()
{
char str1[20] = { 0 };
char str2[] = "abcdef";
my_strcpy(str1, str2);
printf("%s\n", str1);
return 0;
}
版本2:
#include <stdio.h>
#include<string.h>
#include<assert.h>
char* my_strcpy(char* dest, char* src) {
assert(dest && src);
char* ret = dest;
while (*dest++ = *src++)
;
return ret;
}
int main()
{
char str1[20] = { 0 };
char str2[] = "abcdef";
my_strcpy(str1, str2);
printf("%s\n", str1);
return 0;
}
4.strcat——字符串追加
char * strcat ( char * destination, const char * source );
例:在字符数组 arr1 后追加 “world” 。
#include <stdio.h>
#include<string.h>
int main()
{
char arr1[20] = "hello ";
strcat(arr1, "world");
printf("%s\n", arr1);
return 0;
}
strcat 与strcpy相似,同样有以下要求:
- 源字符串必须以 ‘\0’ 结束。
- 目标空间必须有足够的大,能容纳下源字符串的内容。
- 目标空间必须可修改。
- 找到目标字符串的结尾\0
- 拷贝 – strcpy
#include <stdio.h>
#include<string.h>
#include<assert.h>
char* my_strcat(char* dest, const char* src) {
assert(dest && src);
char* ret = dest;
while (*dest != '\0')
{
dest++;
}
while (*dest++ = *src++)
{
;
}
return ret;
}
int main()
{
char arr1[20] = "hello ";
my_strcat(arr1, "world");
printf("%s\n", arr1);
return 0;
}
思考:字符串自己给自己追加会如何?
程序崩溃,原因是在找尾时,第一次拷贝字符将\0给覆盖了,然后目标空间没有\0无法停下来,会陷入死循环。
5.strcmp——字符串内容比较
int strcmp ( const char * str1, const char * str2 );
错误代码:
#include <stdio.h>
#include<string.h>
int main()
{
char arr1[20] = "helloworld";
char arr2[] = "helloworld!!!";
if (arr1 == arr2)
{
printf("==\n");
}
else
{
printf("!=\n");
}
return 0;
}
可能编译器出来的结果是 != ,但这个代码依旧是错的,即使 arr1 和 arr2 的内容一模一样。
因为,arr1 和 arr2 是数组名,数组名是首元素的地址,两个数组名的地址肯定不相等啊,地址是一个常量值。
比较两个字符串相等应该使用strcmp函数。
- 第一个字符串大于第二个字符串,则返回大于0的数字
#include <stdio.h>
#include<string.h>
int main()
{
char arr1[20] = "helloworld!!!";
char arr2[] = "helloworld";
int ret = strcmp(arr1, arr2);
printf("%d\n", ret);
return 0;
}
- 第一个字符串等于第二个字符串,则返回0
#include <stdio.h>
#include<string.h>
int main()
{
char arr1[20] = "helloworld";
char arr2[] = "helloworld";
int ret = strcmp(arr1, arr2);
printf("%d\n", ret);
return 0;
}
- 第一个字符串小于第二个字符串,则返回小于0的数字
#include <stdio.h>
#include<string.h>
int main()
{
char arr1[20] = "helloworld";
char arr2[] = "helloworld!!!";
int ret = strcmp(arr1, arr2);
printf("%d\n", ret);
return 0;
}
注意以下代码:
#include <stdio.h>
#include<string.h>
int main()
{
cha
r arr1[20] = "abcdef";
char arr2[] = "abx";
int ret = strcmp(arr1, arr2);
if(ret < 0)
{
printf("<\n");
}
else if(ret == 0)
{
printf("==\n");
}
else
{
printf(">\n");
}
return 0;
}
#include <stdio.h>
#include<string.h>
int main()
{
cha
r arr1[20] = "abxdef";
char arr2[] = "abc";
int ret = strcmp(arr1, arr2);
if(ret < 0)
{
printf("<\n");
}
else if(ret == 0)
{
printf("==\n");
}
else
{
printf(">\n");
}
return 0;
}
两种代码产生差异的原因是:strcmp比较的是字符的ASCII码值。
#include <stdio.h>
#include<string.h>
#include<assert.h>
int my_strcmp(const char* str1, const char* str2)
{
assert(str1 && str2);
while (*str1 == *str2)
{
if (*str1 == '\0')
return 0;
str1++;
str2++;
}
if (*str1 > *str2)
return 1;
else
return -1;
}
int main()
{
char arr1[20] = "abcdef";
char arr2[] = "abc";
int ret = my_strcmp(arr1, arr2);
if (ret < 0)
{
printf("<\n");
}
else if (ret == 0)
{
printf("==\n");
}
else
{
printf(">\n");
}
return 0;
}
简化版:
#include <stdio.h>
#include<string.h>
#include<assert.h>
int my_strcmp(const char* str1, const char* str2)
{
assert(str1 && str2);
while (*str1 == *str2)
{
if (*str1 == '\0')
return 0;
str1++;
str2++;
}
return (*str1 - *str2);
}
int main()
{
char arr1[20] = "abcdef";
char arr2[] = "abc";
int ret = my_strcmp(arr1, arr2);
if (ret < 0)
{
printf("<\n");
}
else if (ret == 0)
{
printf("==\n");
}
else
{
printf(">\n");
}
return 0;
}
长度受限制的字符串长度:
6.strncpy——拷贝src中num个字符
char * strncpy ( char * destination, const char * source, size_t num );
#include <stdio.h>
#include<string.h>
int main()
{
char arr1[20] = "abcdef";
char arr2[] = "hello world";
strncpy(arr1, arr2, 5);
printf("%s\n", arr1);
return 0;
}
- 如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。
#include <stdio.h>
#include<string.h>
int main()
{
char arr1[20] = "abcdef";
char arr2[] = "xyz";
strncpy(arr1, arr2, 5);
printf("%s\n", arr1);
return 0;
}
#include <stdio.h>
#include<string.h>
#include<assert.h>
char* my_strncpy(char* dest, const char* src, size_t num)
{
assert(dest && src);
char* ret = dest;
int len = strlen(src);
if (len >= num)
{
int i = 0;
while (*src != '\0' && i < num)
{
*dest++ = *src++;
i++;
}
}
else
{
int j = 0;
while (*src != '\0')
{
*dest++ = *src++;
j++;
}
while (num - j != 0)
{
*dest++ = '\0';
j++;
}
}
return ret;
}
int main()
{
char arr1[20] = "abc";
char arr2[] = "xyzdef";
my_strncpy(arr1, arr2, 5);
printf("%s\n", arr1);
return 0;
}
7.strncat——追加src中num个字符
char * strncat ( char * destination, const char * source, size_t num );
#include <stdio.h>
#include <string.h>
int main ()
{
char str1[20] = "hello ";
char str2[20] = "world";
strncat (str1, str2, 3);
puts (str1);
return 0;
}
追加后末尾\0是否补上了呢?
#include <stdio.h>
#include <string.h>
int main()
{
char str1[20] = "hello \0xxxx";
char str2[20] = "world";
strncat(str1, str2, 3);
puts(str1);
return 0;
}
由此可知,在追加之后,补上了一个\0。
#include <stdio.h>
#include <string.h>
#include<assert.h>
char* my_strncat(char* dest, const char* src, size_t num)
{
assert(dest && src);
char* ret = dest;
while (*dest != '\0')
{
dest++;
}
int i = 0;
while (*src != '\0' && i < num)
{
*dest++ = *src++;
i++;
}
*dest = '\0';
return ret;
}
int main()
{
char arr1[20] = "hello ";
char arr2[20] = "world";
my_strncat(arr1, arr2, 6);
puts(arr1);
return 0;
}
8.strncmp——比较num个字符内容
int strncmp ( const char * str1, const char * str2, size_t num );
比较到出现另个字符不一样或者一个字符串结束或者num个字符全部比较完。
#include <stdio.h>
#include <string.h>
int main()
{
char arr1[] = "helloworld";
char arr2[] = "hellq";
int ret = strncmp(arr1, arr2, 5);
if (ret == 0)
printf("==\n");
else if (ret < 0)
printf("<\n");
else
printf(">\n");
return 0;
}
#include <stdio.h>
#include<string.h>
#include<assert.h>
int my_strncmp(const char* str1, const char* str2, size_t num)
{
assert(str1 && str2);
int ret = 0;
while (num != 0)
{
ret = *str1 - *str2;
if (ret != 0)
break;
str1++;
str2++;
num--;
}
return ret;
}
int main()
{
char arr1[] = "abcdef";
char arr2[] = "abc";
int ret = my_strncmp(arr1, arr2,3);
if (ret < 0)
{
printf("<\n");
}
else if (ret == 0)
{
printf("==\n");
}
else
{
printf(">\n");
}
return 0;
}
9.strstr——查找子串
char * strstr ( const char *str1, const char * str2);
返回一个指向str1中第一次出现的str2的指针,或者如果str2不是str1的子串,则返回一个空指针。
#include<stdio.h>
#include<string.h>
int main()
{
char arr1[] = "abcdefghijklmn";
char arr2[] = "defghi";
char* ret = strstr(arr1, arr2);
if (ret == NULL)
{
printf("子串不存在\n");
}
else
{
printf("%s\n", ret);
}
return 0;
}
#include<stdio.h>
#include<string.h>
#include<assert.h>
char* my_strstr(const char* str1, const char* str2)
{
assert(str1 && str2);
const char* s1 = str1;
const char* s2 = str2;
const char* p = str1;
while (*p)
{
s1 = p;
s2 = str2;
while (*s1 != '\0' && *s2 != '\0' && * s1 == *s2)
{
s1++;
s2++;
}
if (*s2 == '\0')
{
return (char*)p;
}
p++;
}
return NULL;
}
int main()
{
char arr1[] = "abcdefghijklmn";
char arr2[] = "defghi";
char* ret = my_strstr(arr1, arr2);
if (ret == NULL)
{
printf("子串不存在\n");
}
else
{
printf("%s\n", ret);
}
return 0;
}
10.strtok——切割字符串
char * strtok ( char * str, const char * sep );
以1234.asdf@csin.com 为例:
const char* sep = "@.";
- 第一个参数指定一个字符串,它包含了0个或者多个由sep字符串中一个或者多个分隔符分割的标记。
const char* sep = "@.";
char arr[] = "1234.asdf@csin.com";
char* ret = strtok(arr, sep);
- strtok函数找到str中的下一个标记,并将其用 \0 结尾,返回一个指向这个标记的指针。(注:strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改。)
const char* sep = "@.";
char arr[] = "1234.asdf@csin.com";
char cp[35] = { 0 };
strcpy(cp, arr);
char* ret = strtok(cp, sep);
- strtok函数的第一个参数不为 NULL ,函数将找到str中第一个标记,strtok函数将保存它在字符串中的位置。
#include<stdio.h>
#include<string.h>
int main()
{
const char* sep = "@.";
char arr[] = "1234.asdf@csin.com";
char cp[35] = { 0 };
strcpy(cp, arr);
char* ret = strtok(cp, sep);
printf("%s\n", ret);
return 0;
}
- strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
#include<stdio.h>
#include<string.h>
int main()
{
const char* sep = "@.";
char arr[] = "1234.asdf@csin.com";
char cp[35] = { 0 };
strcpy(cp, arr);
char* ret = strtok(cp, sep);
printf("%s\n", ret);
ret = strtok(NULL, sep);
printf("%s\n", ret);
ret = strtok(NULL, sep);
printf("%s\n", ret);
ret = strtok(NULL, sep);
printf("%s\n", ret);
return 0;
}
- 如果字符串中不存在更多的标记,则返回 NULL 指针。
#include<stdio.h>
#include<string.h>
int main()
{
const char* sep = "@.";
char arr[] = "1234.asdf@csin.com";
char cp[35] = { 0 };
strcpy(cp, arr);
char* ret = strtok(cp, sep);
printf("%s\n", ret);
ret = strtok(NULL, sep);
printf("%s\n", ret);
ret = strtok(NULL, sep);
printf("%s\n", ret);
ret = strtok(NULL, sep);
printf("%s\n", ret);
ret = strtok(NULL, sep);
printf("%s\n", ret);
return 0;
}
以上代码过于繁琐,可以用循环来简化代码:
#include<stdio.h>
#include<string.h>
int main()
{
const char* sep = "@.";
char arr[] = "1234.asdf@csin.com";
char cp[35] = { 0 };
strcpy(cp, arr);
char* ret = NULL;
for (ret = strtok(cp, sep); ret != NULL; ret = strtok(NULL, sep))
{
printf("%s\n", ret);
}
return 0;
}
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<assert.h>
char* my_strtok(char* str, const char* sep)
{
assert(sep);
static char* s1 = NULL;
char* s2 = sep;
while (s1 != NULL && *s1 != '\0')
{
int cnt = 0;
char* ret = (char*) sep;
while (*ret != '\0')
{
if (*s1 == *ret)
{
cnt = 1;
s1++;
}
ret++;
}
if (cnt == 0)
break;
}
if (str == NULL)
{
if (s1 == NULL)
{
return NULL;
}
str = s1;
}
char* ans = str;
while (*ans != '\0')
{
char* res = (char*)sep;
while (*res != '\0')
{
if (*ans == *res)
{
*ans = '\0';
s1 = ans + 1;
return str;
}
res++;
}
ans++;
}
static int num = 0;
num++;
if (num == 1)
{
return str;
}
else
{
return NULL;
}
}
int main()
{
const char* sep = "@.";
char arr[] = "1234.asdf@csin.com";
char cp[35] = { 0 };
strcpy(cp, arr);
char* ret = NULL;
for (ret = my_strtok(cp, sep); ret != NULL; ret = my_strtok(NULL, sep))
{
printf("%s\n", ret);
}
return 0;
}
11.strerror——返回错误码所对应的错误信息
C语言的库函数,在执行失败的时候,都会设置错误码,如:0 1 2 3 4 5 6 … 要将这些错误码转换为错误信息,就用到了 strerror 函数。
strerror 函数:返回错误码,所对应的错误信息。
char * strerror ( int errnum );
#include<stdio.h>
#include<string.h>
int main()
{
printf("%s\n", strerror(0));
printf("%s\n", strerror(1));
printf("%s\n", strerror(2));
printf("%s\n", strerror(3));
return 0;
}
一般用于文件操作中:
#include<stdio.h>
#include<string.h>
#include<errno.h>
int main()
{
FILE* pf = fopen("test.txt", "r");
if (pf == NULL)
{
printf("%s\n", strerror(errno));
return 1;
}
else
{
}
return 0;
}
如有多个错误,且在继续执行程序,那么记录的始终是最新错误,即新错误将前一个错误所覆盖掉。
文件操作,后期会详说。这里可做了解。
字符转换函数:
12.strlwr、tolower——大写字母转小写字母
char *strlwr(char *str);
#include<stdio.h>
#include<string.h>
#include<ctype.h>
int main()
{
char arr[] = "ASDFGHJKL";
char* a = strlwr(arr);
printf("%s\n", a);
return 0;
}
int tolower ( int c );
#include<stdio.h>
#include<string.h>
int main()
{
int a = tolower('W');
printf("%c\n", a);
return 0;
}
13.strupr、toupper——小写字母转大写字母
char *strupr(char *str);
#include<stdio.h>
#include<string.h>
int main()
{
char arr[] = "asdfghjkl";
char* a = strupr(arr);
printf("%s\n", a);
return 0;
}
int toupper (int c );
#include<stdio.h>
#include<string.h>
int main()
{
int a = toupper('b');
printf("%c\n", a);
return 0;
}
字符分类函数
函数 | 如果他的参数符合下列条件就返回真 |
---|
iscntrl | 任何控制字符 | isspace | 空白字符:空格‘ ’,换页‘\f’,换行’\n’,回车‘\r’,制表符’\t’或者垂直制表符’\v’ | isdigit | 十进制数字 0~9 | isxdigit | 十六进制数字,包括所有十进制数字,小写字母a~f,大写字母A ~ F | islower | 小写字母a~z | isupper | 大写字母A~Z | isalpha | 字母a ~ z或A~Z | isalnum | 字母或者数字,a ~ z,A ~ Z,0~9 | ispunct | 标点符号,任何不属于数字或者字母的图形字符(可打印) | isgraph | 任何图形字符 | isprint | 任何可打印字符,包括图形字符和空白字符 |
|