9.字符串和文件操作

字符串和文件操作

1.字符串

1.1C/C++字符串概述

1.1.1字符串常量

字符串常量

格式要求:采用英文双引号包含的所有内容,C/C++语言规定,字符串常量都存在一个 ‘\0’ 结尾

在内存的【数据区】,而且字符串本身在程序中是对应当前字符串所处内存的空间首地址,可以采用 char *存储对应首地址

"ABCDEFG" 占用的字节为 8 个字节!!!包括'\0'
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc,char*argv[])
{
    printf("字符串占用字节数:%ld\n",sizeof("ABCDEFG"));
    
    /*
    str 可以存储字符串常量在内存【数据区】的空间首地址
    同时也是当前字符串下标为 0 的元素空间首地址
    */
    char *str = "1234567890";
    // str(%p)空间首地址 ==> 当前字符串下标为 0 的元素 1 的首地址
    printf("str: %s\n",str);
    printf("%p\n","1234567890");
    
    // str 下标为 5 的元素的首地址 %s ==> 6
    printf("&str[5] : %s\n", &str[5]);
    
    // 通过访问字符串 str 的地址 * 取值str 字符串
    printf("*str : %c\n", *str);
    // 通过访问字符串 str 下标为 5 的首地址 取值str[5]的元素
    printf("str[5] : %c\n", str[5]);
    printf("\"1234567890\"[5] : %c\n", "1234567890"[5]);
    
    return 0;
}
1.2.1 字符数组

存储字符串的是一个数组,可以理解为字符串【变量】,其中的数据可以通过操作指定下标,修改

存储字符串的如果是一个指针【常量】 不可以通过访问地址操作其中的内容,会报段错误

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

int main(int argc, char const *argv[])
{
    char arr1[4] = {'a', 'b', 'c', '\0'};
    /*
    arr1 数组名为数据类型为 char * 是当前字符数据空间首地址,同时也是数组
    下标为 0 的元素空间首地址

    可以将一个符合 C/C++ 规范的字符数组当作一个字符串【变量】操作。
    C/C++ 规范要求末尾必须有 \0
    */
    // 通过访问 arr1 的首地址 打印出 字符串 abc
    printf("arr1 = %s\n", arr1);
    // 通过访问 arr1 的首地址 打印出 arr1 的地址
    printf("arr1 = %p\n", arr1);
    // 通过访问 arr1 下标为 1 的空间地址 打印出 arr1[1] 的元素
    printf("arr1[1] = %c\n", arr1[1]);

    // arr1 是一个数组存储字符串,可以认为是一个字符串变量
    // 其中的元素可以通过下标访问地址修改
    arr1[1] = 'p';
    printf("arr1 = %s\n",arr1);

    // 此时存储字符串的是一个指针常量
    // 常量其中的数据不能随意修改会报错【段错误】
    char *str = "ABC";
    str[1] = 'p';
    printf("str = %s\n",str);

    return 0;
}

1.2 字符串函数

【重要提示】

  • 字符串是一个常量,数据内容无法修改,地址内容无法修改
  • 字符串函数操作请注意【内存空间问题】
  • 字符串函数操作,注意返回值类型和返回值情况
1.2.1 strcpy 和 strncpy 函数

复制

char *strcpy(char *dest,const char *src,size_t n);
	将 scr 指向的字符串内容,拷贝到 dest 字符数据空间中
要求:
	1.src 可以是字符串常量,也可以是字符数组
	2.dest 必须是可以存储字符数据的内存空间,一般是字符数组或者动态申请内存字符空间,而且空间要求足够使用
	【如果 dest 中有数据 全覆盖 直到 src 中 \0 结束 ==> 默认 dest 中无元素】
	
char *strncpy(char *dest,const char *src,size_t n);
	将 scr 指向的字符串内容,拷贝到 dest 字符数据空间中,最多复制 n 个字符
要求:
	1.src 可以是字符串常量,也可以是字符数组
	2. dest 必须是可以存储字符数据的内存空间,一般是字符数组或者动态申请的内存字符空间,而且龙剑要求足够使用。
	【如果 dest 中有数据,src > dest 中有效元素 全覆盖;
	src < dest 中有效元素个数 复制 n 个之后 如果有\0 不保留,没有\0 保留 dest 中内容】
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char const *argv[])
{
    /*
    【重要提示】
        - 字符串是一个常量,数据内容无法修改,地址内容无法修改
        - 字符串函数操作请注意【内存空间问题】
        - 字符串函数操作,注意返回值类型和返回值情况
    */

    char dest[20] = {'0','1','2','3','4','5','6','7','8','9',
                    '0','1','2','3','4','5','6','7','8','9'};
        // 【不默认结尾有\0】 必须 结尾空出一个 \0 的位置或者直接在里面定义
        /*
        两种正确定义方式
        char dest[21] = {'0','1','2','3','4','5','6','7','8','9',
                 '0','1','2','3','4','5','6','7','8','9', '\0'};
        char dest[21] = "01234567890123456789";

        */
     char *src = "0123456789";

    printf("dest : %s\n",dest);
    printf("src : %s\n",src);

    printf("_______________________\n");
    // 将 src 中的内容 "0123456789" 拷贝到 dest 中
    // 如果 dest 中有数据 全覆盖 直到 src 中 \0 结束 ==> 默认 dest 中无元素
    strcpy(dest,src);
    printf("dest : %s\n",dest);
    printf("src : %s\n",src);

    char dest2[21] = {'0','1','2','3','4','5','6','7','8','9',
                    '0','1','2','3','4','5','6','7','8','9'};

    char dest1[4] = {'\0'};
    char *src1 = "2345";
    printf("_______________________\n");
    // 将 src 中的内容 "2345" 拷贝到 dest 中 最多复制 n 个
    // 如果 dest 中有数据,src > dest 中有效元素 全覆盖
    // src < dest 中有效元素个数 复制 n 个之后 如果有\0 不保留,没有\0 保留 dest 中内容
    strncpy(dest2,src1,4);

    printf("dest2 : %s\n", dest2);
    printf("src1 : %s\n", src1);

    return 0;
}
1.2.2 strcat 和 strncat

末尾添加

char *strcat(char *dest,const char *src)
    把 src 所指向的字符串追加到 dest 所指向的字符串结尾。
注意:
	1.末尾标记 \0
	2.返回值数据类型必须是 char *,返回内容是 deat 对应的空间地址
	3.dest 必须有对应的内存空间

char *strncat(char *dest,const char *src,size_t n)
    把 src 所指向的字符串追加到 dest 所指向的字符串的结尾,直到 n 字符长度为止(n 为追加的数量src中)
注意:
	1.末尾标记'\0'
    2.返回值数据类型为 char *,返回内容为 dest 对应的空间地址
    3.dest必须有对应的空间内容
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char const *argv[])
{
    char dest[20] = {'A','B','C','\0'};
    char *src = "123456789";

    char *s1 = strcat(dest,src);
    printf("s1 = %s\n",s1);
    printf("dest = %s\n",dest);
    printf("_____________________\n");
    
    // 注意此时 dest 已经被追加过了为 "ABC123456789"
    // 4 表示追加的数量 \0 被覆盖
    char *s2 = strncat(dest,src,4);
    printf("s2 = %s\n",s2);
    printf("dest = %s\n",dest);
    return 0;
}
1.2.3 strcmp 和 strncmp

比较

字符串数据通过 == 等值判断,比较的不是【字符串内容】
是比较两端的地址是否一致

如果是两个内容一致的字符串常量比较,== 判断结果为1(true),

如果是两个字符数组或者字符串和字符数组内容一致,但是通过 == 等值判断结果为 0 (false)

【要求,任何一个语言中,字符串数据比较是否一致,请使用字符串相关函数】不允许使用 == 等值比较

int strcmp(const char *str1,const char *str2)
    把 str1所指向的字符串和 str2 所指向的字符串进行比较
返回值
	1.0 表示 str1 和 str2 两个字符串不一致
	2.1 or -1 表示两个字符串不一致
int strncmp(consr char *str1,const char *str2,sizze_t n)
    把 str1所指向的字符串和 str2 所指向的字符串进行比较,最多比较前 n 个字节
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char const *argv[])
{
    printf("ret : %d\n",strcmp("ABC","ABC"));
    printf("ret : %d\n",strcmp("aBC","CBC"));
    printf("ret : %d\n",strcmp("ABC","AzC"));
    printf("------------\n");
    /*
    字符串数据通过 == 等值判断,比较的不是【字符串内容】
    是比较两端的地址是否一致,如果是两个内容一致的字符串
    常量比较,== 判断结果为1(true),如果是两个字符数组
    或者字符串和字符数组内容一致,但是通过 == 等值判断
    结果为 0 (false)

    【要求,任何一个语言中,字符串数据比较是否一致,请使用字符串相关函数】
    C strcmp strncmp 
    【不允许使用 == 等值判断】
    */
    //比较的是地址 对于字符串函数来说 "ABC" 地址都一样 
    // 所以结果为1 ture
    printf("ret :%d\n","ABC" == "ABC");
    char arr[4] = {'A','B','C','\0'}// 字符串"ABC" 地址和 arr 中存储的 "ABC"地址不一样
    printf("ret :%d\n","ABC" == arr);
    printf("-------------------\n");

    printf("ret : %d\n",strncmp("ABCDE","ABCDE111111",5));
    printf("ret : %d\n",strncmp("ABCDEF","ABCDE11111",6));
    return 0;
}
1.2.4 strchr 和strrchr

搜索

char *strchr(const char*str,int c);
在参数 str 所指向的字符串中搜索第一次出现字符 c (一个无符号字符)的位置
// int c传递的是该字符的 ASCLL 码为了兼容和灵活
// 如果没有该元素返回 NULL
s
char *strrchr(const *str,int c);
// r 代表 right
在参数 str 所指向的字符串中搜索最后一次出现字符 c (一个无符号字符)的位置
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char const *argv[])
{
    char *str = "ABCDE7BCD";
    char *p1 = strchr(str,'7');

    printf("p1 = %s\n",p1);
    printf("p1 = %p\n",p1);
    /*
    p1 和 str 都是 char * 指针,存储对应的数据的地址,
    因为字符数据在内存中,占用的空间字节数为1,两个字符
    地址相减,可以认为是下标位置,要求必须在同一个字符串、
    地址范围内
    */

    printf("p1 - str : %ld\n",p1 - str);
    printf("--------------\n");

    int arr[5] = {1, 2, 3, 4, 5};

    /*
    两个同数组中元素取地址相减操作
        CPU 首先计算两个地址直接的字节差,根据数据类型相除
        最终结果是两个地址的【下标差/坐标差】
    */
    printf("&arr[4] - &arr[1] : %ld\n",&arr[4] - &arr[1]);
    printf("--------------------\n");

    char *p2 = strrchr(str,'Y');
    printf("p2 = %s\n",p2);
    printf("p2 = %p\n",p2);
    return 0;
}
1.2.5 strstr 和 strlen
char *strstr(const char *haystack,const char *needle)
在字符串 haystack 中查找第一次出现字符串 needle(不包含空结束字符)的位置。 

size_t strlen(const char *str)
计算字符串 str 的长度,直到空结束字符,但不包括空结束字符。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char const *argv[])
{
    char *str = "ABCDEFG";
    char *target = "DEF";

    char *p = strstr(str,target);
    // 位置打印出来为 地址 D的内存空间首地址
    printf("p = %p\n",p);
    // 地址相减为中间的距离 首地址空间距离
    printf("p - str = %ld\n",p - str);

    printf("strlen = %ld\n",strlen("ABCDE"));
    char arr[5] = {'A','B','C','D','\0'};
    // 计算字符串 str 的长度,直到空结束字符,不包括结束字符 \0
    printf("strlen = %ld\n",strlen(arr));
    
    return 0;
}
1.2.6 memory 函数

以下函数具备字符串处理功能,更多的使用场景是针对于内存数据操作

void *memchr(const void *str,int c,size_t n)
    在参数 str 所指向的字符串的前 n 个字节中搜索第一次出现字符 c(一个无符号字符)的位置
    
int memcmp(const void *str1,const void *str2,size_t n)
    把 str1 和 str2 的前 n 个字节进行比较
void *memset(void *str,int c,size_t n)
    复制字符 c (一个无符号字符)到参数 str 所指向的字符串的前 n 个字符。
void *memcpy(void *dest,const void *src,size_t n)
    从 src 复制 n 个字符到 dest 
 void *memmov(void *dest,const void *src,size_t n)
    从 src 复制 n 个字符到 dest 
 /*
 memcpy 和 memmove 功能和 strncpy 一致,memmove 可以更好的保护拷贝源数据 src
 【使用 memmove 不会导致内存数据丢失】
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct student 
{
    int id;
    char name[32];
    int age;
} Student;

int main(int argc, char const *argv[])
{
    /*
    void *memchr(const void *str,int c,size_t n)
    在参数 str 所指向的字符串的前 n 个字节中搜索第一次出现字符 c (一个无符号字符)
    */
    char *str = "ABCDEFABCDEFG";
    void * p = memchr(str,'C',5);

    printf("p = %p\n",p);

    /*
    int memcmp(const void *str1,const void *str2,size_t n)
    把 str1 和 str2 的前 n 个字符进行比较,0 相同,非 0 不同
    */
    char * str1 = "ABCDE";
    char * str2 = "ABCDE";
    int ret = memcmp(str1,str2,5);
    printf("ret = %d\n",ret);

    printf("---------------\n");
    Student *stu1 = (Student *)malloc(sizeof(Student));
    memset(stu1,0,sizeof(Student));
    Student *stu2 = (Student *)malloc(sizeof(Student));
    memset(stu2,0,sizeof(Student));

    stu1->id = 1;
    strcpy(stu1->name,"James");
    stu1->age = 39;

    stu2->id = 1;
    strcpy(stu2->name,"James");
    stu2->age = 39;

    ret = memcmp(stu1,stu2,sizeof(Student));
    printf("ret = %d\n",ret);

    free(stu1);
    free(stu2);
    stu1 = NULL;
    stu2 = NULL;
    return 0;
}
1.2.7 strtok 函数待更新

2.文件操作IO

2.1 IO 概述

I ==> Input 输入
O ==> Output 输出
【输入输出 IO 操作参照物是当前程序运行使用的内存】
内存数据流出到外部 ==> 输出 write put
外部数据流入到内存 ==> 输入 read get

基于冯诺依曼计算机理论
1.二进制程序思想
2.万物皆文件思想,都采用 IO 操作对应内容,无论是软件还是硬件。

2.2 fopen 打开文件操作

FILE *fopen(const char *filename, const char *mode );
/*
filename 提供当前函数对应文件路径,路径可以是绝对路径 or 相对路径
mode 模式,选择当前文件的打开模式
*/

mode —— 模式

r
打开一个已有的文本文件,允许读取文件。

w
打开一个文本文件,允许写入文件。如果文件不存在,则会创建一个新文件。在这里,您的程序会从文件的开头写入内容。如果文件存在,则该会被截断为零长度,重新写入。

a
打开一个文本文件,以追加模式写入文件。如果文件不存在,则会创建一个新文件。在这里,您的程序会在已有的文件内容中追加内容。

r+
打开一个文本文件,允许读写文件。

w+
打开一个文本文件,允许读写文件。如果文件已存在,则文件会被截断为零长度,如果文件不存在,则会创建一个新文件。

a+
打开一个文本文件,允许读写文件。如果文件不存在,则会创建一个新文件。读取会从文件的开头开始,写入则只能是追加模式。

如果处理的是二进制文件,则需使用下面的访问模式来取代上面的访问模式;

"rb", "wb", "ab", "rb+", "r+b", "wb+", "w+b", "ab+", "a+b"

补充说明,区分二进制文件的方式是可以利用记事本打开对应文件,如果文件是可视化文本文件,就普通文本文件内容,如果是乱码,就是二进制文件。平时的图片,视频,音频,可执行文件,都是二进制文件。

2.3fclose关闭文件操作

int fclose(FILE *fp);
/*需要提供给当前函数都是文件指针 FILE *,如果文件关闭成功,返回 0 ,失败返回 EOF(-1)【注意】 文件打开之后必须关闭!!!*/

2.4fget 和 fputc

针对于字符操作

int fput(int c,FILE *fp);
/*写入字符数据到文件中,需要提供给函数的参数是 int 类型字符数据,
对于代码而言虽然提供的数据 为 int 类型,但实际写入到文件中的内容是字符数据,
int类型数据有且是由【低 8 位】有效写入到文件中,
 第二个参数是文件指针,要求当前文件指针具备【写入能力】
 模式限制 : w a r+ w+ a+ */
int fgetc(FILE * fp);
/*从文件中读取一个字节数据,返回值类型为 int 类型,
但是实际有效数据为 int 类型内存的【低 8 位】,
在读取的过程中,【读取指针会自动后移】完成整个文件的文件的读取操作
如果文件操作到末尾返回 EOF(-1)End of file*/
  • 7
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值