字符串
[1]常量字符串
“hello” 一共6个字节
h | e | l | l | o | ‘\0’ |
---|
- 常量字符串存储在常量区,用户只能访问,不可修改。
- 就算使用指针接收字符串常量,也不可以通过指针修改常量字符串内容
[2]字符串存储
char str [10] = {‘a’,‘b’,‘c’,‘\0’};
char str [10] = “abc”;
char str [] = “abc”;
char str [] = “宝”;//一共4个字节,一个汉字3字节
下面代码验证结果打印输出:sizeof(str) = 4
#include <stdio.h>
int main(){
char str[] = "宝";
printf("sizeof(str) = %ld\n",sizeof(str));
return 0;
}
[3]gets()和puts()
char str[10];
gets(str);
puts(str);
- 获取一行字符串,只到遇到回车键,并将回车转换为尾零,进行存储;
- 一般与puts()成对使用,因为gets获取丢弃回车,但puts打印会在结尾加上回车;
- 因其不对内存进行管理,已被废弃,不建议使用,去用fgets和fputs吧
[4]fgets()和fputs()
原函数:char *fgets(char *s,int size,FILE *stream);
s:存放字符串起始地址
size:内存大小
stream:文件指针,标准输入缓冲区用:stdin,输出用:stdout
char str[10];
fgets(str,10,stdin);
fputs(str,stdout);
- 在内存允许范围内,获取一行字符串,直到遇到回车,连回车一起获取。
- fputs()打印输出时,不会在结尾加上回车。
[5]字符串函数
头文件string.h
-
strlen(str):字符串长度计算函数
计算str字符串长度,不包含’\0’
-
strcpy(dest,str):字符串拷贝函数
dest:目标位置 str:拷贝的字符串
dest的目标内存一定要有效,长度还要足够长
-
strcmp(str1,str2):字符串比较函数
str1和str2对应字符比较;
两字符串不同时,返回值为第一对不同字符作差结果;
两字符串相同时,返回值为最后一对字符作差结果及返回值为0.
-
strcat(dest,str):字符串拼接函数
dest:目标字符串 str:拼接的字符串
dest的目标内存一定要有效,长度还要足够长
1>练习:重写(自己封装实现)这四个字符串函数
/*strlen()*/
int my_strlen(const char *str){
int count = 0;
for(int i = 0;str[i] != '\0';i++){
count++;
}
return count;
}
/*strcpy()*/
char *my_strcpy(char *dest,const char *str){
int i;
for(i = 0;str[i] != '\0';i++){
dest[i] = str[i];
}
/*清空dest剩余字符串*/
for(;dest[i] != '\0';i++){
dest[i] = '\0';
}
return dest;
}
/*strcmp()*/
int my_strcmp(const char *str1,const char *str2){
int i;
for(i = 0;str1[i] != '\0' || str2[i] != '\0';i++){
if(str1[i] != str2[i]){
return str1[i]-str2[i];
break;
}
}
return 0;
}
/*strcat*/
char *my_strcat(char *dest,const char *str){
for(int i = 0;;i++){
if(dest[i] =='\0'){
int j,k = 0;
for(j = i;str[k] != '\0';j++,k++){
dest[j] = str[k];
}
dest[j] = '\0';
break;
}
}
return dest;
}
[6]字符串数组
-
字符指针数组:
char *str[n] = {"abc","1234",......};
字符串只读不可修改,一般用于保存待显示字符串,效率高。
-
二维字符数组:
char str[n][m] = {"abc","1234",......};
n表示有几个字符串,m应大于或等于最长的字符串长度,可以修改每个字符串,但分配内存使用率低。
结构体
[1]结构体定义
-
定义结构体类型(结构体名称可以省略,但是只能在定义结构体时定义结构体变量)
struct structurename{
typename variablename;
....;
....;
};
struct {
typename variablename;
....;
....;
}s1,s2...;
-
定义结构体变量
struct structurename s1;
-
变量初始化
struct structurename s1 = {....,....,.....};
-
赋值(字符串成员要用strcpy赋值!)
struct structurename s1;
s1.成员名 = ;
-
键盘输入(字符串scanf输入不要加&取地址)
scanf("%d",&s1.成员名);
-
访问结构体变量中的成员
1、变量名.成员名 如
s1.name
2、定义结构体指针变量指向s1
struct stu *p = &s1;
第一种访问:
(*p).name
第二种访问:
p->name
[2]结构体数组
struct stu s[10];
赋值三种方法: 初始化、s[i].成员名
一个一个赋值、循环中输入每个结构体变量中的每个成员。
输出:
-
s[i].成员名
-
定义指针指向结构体数组:
struct stu *p = s;
p+±>成员名、(*(p++)).成员名
(p+i)->成员名、(*(p+i)).成员名
p[i].成员名
[3]嵌套结构体
- 嵌套的结构体,应该在之前定义好该结构体类型;
- 访问嵌套结构体变量中的成员时,要逐级访问。
1->综合小项目:影片管理系统
/*************************************************************************
> File Name: work4.c
> Author: Jerich
> Mail: 2213993021@qq.com
> Created Time: Wed 10 Aug 2022 05:31:59 PM CST
************************************************************************/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#if 0
定义一个结构体,表示影片信息:
编号 片名 导演 片长
要求:
(1)设计菜单
(2)1==========》添加影片
2==========》删除影片
3==========》修改影片
4==========》查找影片
5==========》显示所有影片
6==========》退出
(3)每一模块封装成一个函数
(4)影片编号不允许重复
(5) 数据结构 : 数组存储
#endif
struct TIME{
int hour;
int min;
int sec;
};
struct MOVIE{
int num;
char name[48];
char director[32];
struct TIME time;
};
/*影片编号*/
static int id = 1;
void mainFrame(){
puts(" __________________________");
puts("|_________影片系统_________|");
puts("| 1==========》添加影片 |");
puts("| 2==========》删除影片 |");
puts("| 3==========》修改影片 |");
puts("| 4==========》查找影片 |");
puts("| 5==========》显示所有影片|");
puts("| 6==========》退出 |");
puts("|__________________________|");
}
void showMovie(struct MOVIE *m,int N){
puts(" _______________________________________________");
puts("|____________________所有影片___________________|");
puts("|编号 片名\t\t导演\t\t时长\t|");
if(N == 0){
puts("| 空 |");
}
for(int i = 0;i < N;i++){
printf("|%2d %s\t\t%s\t\t",m[i].num,m[i].name,m[i].director);
printf("%.2d:%.2d:%.2d|\n",m[i].time.hour,m[i].time.min,m[i].time.sec);
}
puts("|_______________________________________________|");
}
void addMovie(struct MOVIE *m,int *N){
char *find = NULL;
/*从已有影片编号后开始添加*/
/*id = *N+1;添加保存读取数据功能时,取消该注释*/
m[*N].num = id++;
printf("输入片名:");
fgets((m+*N)->name,48,stdin);
find = strchr((m+*N)->name,'\n');
if(find) *find = '\0';
printf("输入导演:");
fgets((m+*N)->director,32,stdin);
find = strchr((m+*N)->director,'\n');
if(find) *find = '\0';
printf("输入时长(xx:xx:xx):");
scanf("%d:%d:%d",&m[*N].time.hour,&m[*N].time.min,&m[*N].time.sec);
while(getchar() != '\n');
(*N)++;
}
int searchMovie(struct MOVIE *m,int N){
int n;
printf("输入编号:");
scanf("%d",&n);
while(getchar() != '\n');
if(n > N){
puts("->没有该影片!");
return 0;
}
else{
puts("->查找成功!");
puts(" _______________________________________________");
puts("|编号 片名\t\t导演\t\t时长\t|");
printf("|%2d %s\t\t%s\t\t",m[n-1].num,m[n-1].name,m[n-1].director);
printf("%.2d:%.2d:%.2d|\n",m[n-1].time.hour,m[n-1].time.min,m[n-1].time.sec);
puts("|_______________________________________________|");
return n;
}
}
void deleteMovie(struct MOVIE *m,int *N){
int n = searchMovie(m,*N);
if(n != 0){
memset(m+n-1,0,sizeof(struct MOVIE));
puts("->删除成功!");
/*删除后前移*/
for(int i = n;i < *N;i++){
m[i-1] = m[i];
m[i-1].num--;
}
(*N)--;
id--;
}
}
void modMovie(struct MOVIE *m,int N){
int n = searchMovie(m,N);
while(n){
int a;
printf("输入1进入修改菜单(0退出):");
scanf("%d",&a);
while(getchar() != '\n');
if(a == 1){
puts(" __________________________");
puts("|_________修改菜单_________|");
puts("| 1==========》修改片名 |");
puts("| 2==========》修改导演 |");
puts("| 3==========》修改时长 |");
puts("| 4==========》退出菜单 |");
puts("|__________________________|");
while(1){
int opt;
char *find = NULL;
printf("请输入选项:");
scanf("%d",&opt);
while(getchar() != '\n');
if(opt == 4){
puts("菜单退出");
break;
}
switch(opt){
case 1:
printf("输入新片名:");
fgets((m+n-1)->name,48,stdin);
find = strchr((m+n-1)->name,'\n');
if(find) *find = '\0';
break;
case 2:
printf("输入新导演:");
fgets((m+n-1)->director,32,stdin);
find = strchr((m+n-1)->director,'\n');
if(find) *find = '\0';
break;
case 3:
printf("输入新时长:");
scanf("%d:%d:%d",&m[n-1].time.hour,&m[n-1].time.min,&m[n-1].time.sec);
while(getchar() != '\n');
break;
default:
puts("Error:指令错误");
}
}
}
else{
break;
}
}
}
int main(){
struct MOVIE m[100];
/*记录影片个数*/
int N = 0;
/*进度条*/
puts("加载中...");
char buff[40];
memset(buff,'\0',40);
for(int i = 0;i < 40;i++){
printf("[%-39s][%.1f%%]\r",buff,(i+1)*2.5);
fflush(stdout);
buff[i] = '#';
usleep(70000);
}
putchar('\n');
/*读取数据,并记录影片个数*/
/*int N = fileRead(m,100);
showMovie(m,N);添加保存读取数据功能时,取消该注释,并删除上面的int N = 0;*/
/*显示主菜单*/
mainFrame();
while(1){
int option;
printf("请输入选项:");
scanf("%d",&option);
while(getchar() != '\n');
switch(option){
case 1:
puts(" _______________________________________________");
puts("|____________________添加影片___________________|");
addMovie(m,&N);
showMovie(m,N);
mainFrame();
break;
case 2:
puts(" _______________________________________________");
puts("|____________________删除影片___________________|");
deleteMovie(m,&N);
showMovie(m,N);
mainFrame();
break;
case 3:
puts(" _______________________________________________");
puts("|____________________修改影片___________________|");
modMovie(m,N);
showMovie(m,N);
mainFrame();
break;
case 4:
puts(" _______________________________________________");
puts("|____________________查找影片___________________|");
searchMovie(m,N);
mainFrame();
break;
case 5:
showMovie(m,N);
mainFrame();
break;
case 6:
puts("->系统退出");
/*保存数据*/
/*fileWrite(m,N);添加保存读取数据功能时,取消该注释*/
return 0;
default:
puts("Error:指令错误!");
}
}
return 0;
}
[4]结构体成员对齐原则
- 每个成员按照自己字节数对齐
- 最后对齐数为最大对起数的整数倍,如果不是,加到第一个整数倍位置
- 结构体变量按照自己的最大对齐数对齐
- 数组按照元素大小对齐、
[5]位域和位段
struct 位域名称{
类型 成员名称:指定位数
}
[6]typedef定义类型别名
给已经存在的数据类型取别名
语法:typedef 类型名 别名
[7]联合体
关键字: union
按照最大成员类型分配类型空间
总字节数是最大成员数的整数倍
文件
- 读操作:将文件中的数据加载到程序
- 写操作,将程序中的数据保存到文件
文件操作步骤:
-
打开文件:将应用程序和文件建立关联------->
fopen(文件路径,打开模式);
成功:返回结构体起始地址 失败:返回NULL
-
读写、文件操作----> 打开模式:文本文件:r,w,a;二进制文件:rb,wb,ab
- r:读方式打开,只能读取文件内容
- w:如果文件不存在则创建,存在则格式化写入
- a:追加方式打开,如果文件不存在则创建,存在则在文件已有内容后面继续写入
-
关闭文件
fwrite:以二进制方式写入文件(返回值为写入个数,失败返回0)
fwrite(数据的起始地址, 数据类型大小, 数据个数, 文件指针);
fread:以二进制方式读文件(返回值为读入个数,为0表示到达文件结尾)
fread(存放读入数据内存的起始地址, 数据类型大小, 数据个数, 文件指针);
fprintf:以文本方式写入文件(返回值为写入个数,写入失败返回负值)
fprintf(文件指针, " 格式化说明符 ", 参数表 );
fscanf:以文本方式读文件(返回值为读入个数,为EOF表示到达文件结尾)
fscanf(文件指针, " 格式化说明符 ", 参数表 );
**应用:**下面的movieSysFileIO.c为之前的影片系统添加了数据保存和读取功能
/*************************************************************************
> File Name: movieSysFileIO.c
> Author: Jerich
> Mail: 2213993021@qq.com
> Created Time: Fri 12 Aug 2022 05:08:02 PM CST
************************************************************************/
#include <stdio.h>
#include "movieSystemTools.h"
int fileRead(struct MOVIE *m,int N){
FILE *fp = fopen("./movieSys.txt","r");
if(fp == NULL){
perror("open error");
return 0;
}
struct MOVIE temp;
int i = 0;
while(EOF != fscanf(fp,"%d%s%s%d%d%d",&temp.num,temp.name,temp.director,\
&temp.time.hour,&temp.time.min,&temp.time.sec)){
m[i++] = temp;
if(i == N){
perror("read error");
fclose(fp);
return 0;
}
}
puts("----->影片数据读取成功!");
fclose(fp);
return i;
}
void fileWrite(struct MOVIE *m,int N){
FILE *fp = fopen("./movieSys.txt","w");
if(fp == NULL){
perror("open error");
return;
}
int fw;
for(int i = 0;i < N;i++){
fw = fprintf(fp," %d %s %s %d %d %d ",m[i].num,m[i].name,m[i].director,\
m[i].time.hour,m[i].time.min,m[i].time.sec);
if(fw < 0){
perror("write error");
fclose(fp);
return;
}
}
puts("----->影片数据保存成功!");
}