一.fgets函数
fgets不能进行格式化输出输入
代码如下
<span style="font-size:18px;">//fgets()
/*
文件操作相关函数
从键盘上接收一个字符串保存到数组中
scanf()缺点不能接收空格
gets(str)优点 :可以接收空格
*/
char str[10] ;
fgets(str,sizeof(str),stdin);//安全的,输入的字符串长度大于
puts(str);
//数组长度时,会将最后一个元素变为\0
/*
12345678abcd
12345678a
*/
for (int i = 0; i < 10 ; i++) {
printf("%d",str[i]);
}
/*
如果只输入8个第九个元素为空格
aaaaaaaa
aaaaaaaa
97 97 97 97 97 97 97 97 10 0
*/
int len =strlen(str);//不包含\0如果少就包含空格所以整体字符大一个
printf("%d\n",len);
if (str[len-1]=='\n') {
str[len-1]='\0';
}
for (int i = 0; i < 10 ; i++) {
printf("%d",str[i]);
}
printf("\n");
fputs(str,stdout);//不会自动换行
printf("\n");
puts(str);//带换行
/*
总结果:
aaa
aaa
97 97 97 10 0 95 -1 127 0 0 4
97 97 97 0 0 95 -1 127 0 0
aaa
*/
return 0;
</span>
2).const使用
const int Mx =10;
//常量是read only
int *p =&Mx;
*p = 100 ;//强制修饰常量
printf("Mx = %d , *p =%d\n",Mx,*p);
//Mx = 10, *p = 100
const int Mx =10;
//常量是read only
int *p =&Mx;
//intializingint * with an expression of type const int * discards qulifier
*p = 100 ;//强制修饰常量
printf("Mx = %d , *p =%d\n",Mx,*p);
//Mx = 10, *p = 100
//主要是看const和*的位置
//1.const修饰的指针变量指向可变 const在 *左边,
int a = 10 ;
int b = 20 ;
const int *p1 =&a;
p1=&b;//指向可以改变
*p1=1000;//read-onlyvariable is not assignable
//p1指向的变量的值是不能改变
const int *p2 =&b;
p2 =p ;
*p2=1000;//read-onlyvariable is not assignable
//2.const修饰的指针变量变量指向的变量值可以变,指向不能变
//const在 *的右侧指向的值可以改变,指向不可以
int * const p3 = &a;
*p3 =2000 ;
p3=&b;//read-onlyvariable is not assignable
//3.指向和值都不能改变
//const在 *的两侧
const int * const p4 = &a;
*p4 = &b;//read-onlyvariable is not assignable
*p4 = 1000;//read-onlyvariable is not assignable
二.内存管理的基本概念
2).动态即是运行的时候分配的
3).动态内存分配的好处
1、当你定义了一个指针,而且要往里面写数据时,必须要动态分配内存给他。
2、动态分配的内存在堆上,你有权利决定什么时候将他释放掉。
3、动态分配的内存请记得一定要释放掉,不然容易引起内存泄露。
管理用户分配的内存空间
2).常见的动态内存分配函数
int *p = (int*)malloc(4*sizeof(int));//从内存的堆区分配16个字节的内存空间
if (p != NULL){
*p = 10 ;
*(p+1) = 100 ;
*(p+2) = 1000 ;
*(p+3) = 10000 ;
printf("%p\n",p);
printf("%p\n",p+1);
printf("%p\n",p+2);
printf("%p\n",p+3);
for (inti = 0 ; i< 4; i++) {
printf("%d\n",*(p+i));
}
}
/*
0x100100480
0x100100484
0x100100488
0x10010048c
10
100
1000
10000
*/
3).野指针和内存泄露
int *p = (int*)malloc(4*sizeof(int));
//该句话会造成内存泄露
free(p);//释放内存空间 free空间的首地址 p为野指针
//p =NULL;
*p =100;
printf("%d\n",*p);
//还是*p还是存放了地址可以进行访问
//但是逻辑上不能让他继续访问此时要将p = NULL;
//再访问就会报错
return 0;
在p释放之前,先释放堆区的内存空间
指针被释放后再去使用,指针已经不存在,也会成为野指针
4).free函数的使用
5).指针函数
int* max(int a,int b){
//ab 在 *max分配的内存空间里形参新分配的空间和实参地址不一样
printf("%p\n",&a);
printf("%p\n",&b);
//returna>b?&a:&b;
return NULL;
}
int* max2(int*a ,int* b){
//形参和实参地址不一样实参和形参是地址传递,没有分配新的空间
printf("%p\n",a);
printf("%p\n",b);
return *a>*b?a:b;
}
int main(intargc,const char* argv[]) {
int a = 3 ,b= 4;
printf("a =%p\n",&a);
printf("b =%p\n",&b);
//int*p=max(a,b);
int *p=max2(&a,&b);
printf("%p\n",p);
/*
a = 0x7fff5fbff78c
b = 0x7fff5fbff788
0x7fff5fbff78c
0x7fff5fbff788
0x7fff5fbff788
*/
return 0;
char *printDay2(intn ){
char *printDay[20];
switch (n) {
case 1:
*printDay="MONDAY";
break;
case 2:
*printDay="TUESDAY";
break;
case 3:
*printDay="WEDNESDAY";
break;
case 4:
*printDay="THURSDAY";
break;
case 5:
*printDay="FRIDAY";
break;
case 6:
*printDay="SATURDAY";
break;
case 7:
*printDay="SUNDAY";
break;
default:
*printDay="输入错误!";
break;
}
return *printDay;
}
int * getMax (int*arr ,int len){
int max = *arr ;
for (int i = 1;i<len; i++) {
if (*(arr+i)>max) {
max=*(arr+i);
}
}
return &max;
//addressof stack memory associated with local variable 'max' returned
}
int main(intargc,const char* argv[]) {
int arr[10]={11,22,3230,444,533,62,7,83,9,22};
printf("%s\n",printDay2(9));
printf("%d\n",*(getMax(arr,10)));
return 0;
}
6).函数指针
定义一个指针变量存放函数名的指针就叫函数指针
#include<stdio.h>
int sum(int a ,int b)
{
return a + b ;
}
int main(intargc,const char* argv[]) {
//定义函数指针可以不写形参
int (*p1)(int ,int);
//初始化函数指针
p1=sum;
printf("%d\n",p1(2,3));
printf("%d\n",(*p1)(2,3));
//5
return 0;
}
三.构造类型
数组类型,结构体类型,共用体类型
结构体:由若干成员组成
结构体定义完成后,计算机并不会给结构体分配内存空间
会在定义结构体变量后,分配内存空间
#include<stdio.h>
#include<string.h>
//1.先定义结构体
struct Student{
int sno ;
char name[20];//char*name;
char sex ;
int age;
float score ;
};
structStudentstud1,stud2,stud3;
//2.定义一个学生结构体
struct stu{
int sno ;
char name[20];//char*name;
char sex ;
int age;
float score ;
}stud5,stud6,stud7;
//3.匿名结构体
struct{
int sno ;
char name[20];//char*name;
char sex ;
int age;
float score ;
}stud8,stud9;
int main(intargc,const char* argv[]) {
//成员变量访问方法
stud1.age= 10 ;
//stud1.name="zhangsan";//arraytype 'char[20]' is not assignable
strcpy(stud1.name,"zhangsan");
stud1.sex='M';
printf("%s\n",stud1.name);
//stud1.name占用多少字节
printf("%ld\n",sizeof(stud1.name));
//utf-8国际通用编码 xcode默认的中文编码一个汉字占用3字节
//gb2312 gbk国际一个汉字占两字节
//stud1.name 字符串长度
printf("%ld\n",strlen(stud1.name));
//1.结构体初始化
//stud2={12,"zhangsans",'F',18,90.3f}; //expected expression
struct Studentstud10={12,"zhangsans",'F',18,90.3f};
//2.指定元素初始化
struct Studentstud11={.name="zhangsans"};
2).结构体数据成员对齐的意义
3).结构体对齐的含义
4).内存之间大小的倍数,结构体大小的计算方法和步骤
#include<stdio.h>
struct Student{
int sno ;//4
char sex ;//1
float score ;//4
};
struct Student2{
short sno ;//2
char sex ;//1
float score ;//4
};
struct Student3{
short sno ;//2
char sex ;//1
float score ;//4
double d;//8
};
struct Student4{
char sex[13] ;//4 16还空余3个
char score[13] ;//3 12(12个字节实际存储10个)
int d;//4
};
int main(intargc,const char* argv[]) {
struct Studentstd1;
printf("%ld\n",sizeof(std1));//12
//计算结构变量再内存中占用的字节数的方法
//1.先找对其模数,结构体变量中基本数据类型占字节数最大的那个
//2.在计算结构体变量中各个成员占用字节和
struct Student2std2;
printf("%ld\n",sizeof(std2));//8
struct Student3std3;
printf("%ld\n",sizeof(std3));//16
//double的位置如果在float之上结果为24
struct Student4std4;
printf("%ld\n",sizeof(std4));//32
return 0;
}
函数外部定义的结构体类型类似全局变量
全局作用域:从自定义的哪一行开始直到本文件结束为止
5).作用域分类
结构体根据作用于可以分为全局结构体,局部结构体
局部变量的结构体会覆盖全局的
6).结构体数组定义
#include<stdio.h>
#define LEN5
struct person {
char name[8] ;
char telNum[12];
};
int main(intargc,const char* argv[]) {
struct personcontacts[LEN];
for (int i = 0; i < LEN ; i++) {
scanf("%s%s",contacts[i].name,contacts[i].telNum);
}
for (int i = 0; i < LEN ; i++) {
printf("姓名:%s,电话:%s\n",contacts[i].name,contacts[i].telNum);
}
return 0;
}
7).指向结构体变量的指针
8).指针访问结构变量属于间接访问
#include<stdio.h>
#include<string.h>
struct person// struct是关键字 person是结构体名
{
char name[8] ;
char telNum[12];
char *id;
int age ;
}per1; //结构体变量名
int main(intargc,const char* argv[]) {
structperson *p = &per1;//p是结构体指针
//结构体指针间接访问成员值的方法
//1).(*p).age; (*p)相当于per1
//2).p->agep是结构体指针的时候写法
(*p).age =10;
(*p).id="2332";
strcpy(p->name,"sdsd");
// strcpy((*p).name,"sdsd");
printf("%s\n",(*p).name);
//incompatiblepointer to integer conversion to 'char' from char[5]
//(*p)->age =100;
//memberreference type 'struct person' is not a pointer ,maybe you
//meant touse '.' to fix it
return 0;
}
// main.c
// 结构体嵌套
//
// Created by CHINGWEI_MACPC on 15/11/6.
// Copyright © 2015年 itcast. All rights reserved.
//
#include<stdio.h>
struct Time {
int hour ;
int second ;
int minite ;
};
struct Date
{
int month;
int day ;
int year ;
struct Timetime ;
};
struct Student
{
char name[8] ;
int age ;
float score ;
struct Datebirthday;
//可以嵌套自己类型的结构体指针
//struct Student stu; //错误书写
//structStudent *stu;
};
int main(intargc,const char* argv[]) {
struct Studentstu1={"mike",18,89.5f,{2,12,2006,{10,23,13}}};
printf("姓名:%s,年龄:%d,成绩:%f,生日:%02d/%02d/%d,时间:%02dh:%02dm:%ds\n",
stu1.name,stu1.age,stu1.score,stu1.birthday.day
,stu1.birthday.month,stu1.birthday.year,stu1.birthday.time.hour,stu1.birthday.time.minite,stu1.birthday.time.second);
struct Person// struct 是关键字 person是结构体名
{
char name[8] ;
int age ;
struct Person*children;
};
//结构体嵌套指针的使用
struct Personkim={"kim",20,NULL};
structPerson p1 ={"小白",38,&kim};
structPerson p2 ={"小白",38,&kim};
printf("名字:%s,年纪:%d,儿子:%s\n",p1.name,p1.age,(*p1.children).name);
//便于理解方法2 p2.children->name
printf("名字:%s,年纪:%d,儿子:%s\n",p2.name,p2.age,p2.children->name);
return 0;
}
结构体成员值作为函数参数
#include<stdio.h>
struct Student
{
char name[8] ;
float score ;
};
void xiugai(floatscore )
{
score=2.2f;
}
void printScore(structStudent stu)
{
stu.score=2.2f;
}
int main(intargc,const char* argv[]) {
struct Studentstu1={"liu",12.3f};
//1.结构体成员变量的成员值作为函数参数是值传递
xiugai(stu1.score);
printf("%s,%f\n",stu1.name,stu1.score);
//2.用结构体变量作为函数的参数也是值传递
printScore(stu1);
printf("%s,%f\n",stu1.name,stu1.score);
return 0;
}
结构体指针作为函数参数
将地址传递给函数
#include<stdio.h>
struct Student
{
char name[8] ;
float score ;
};
void printScore(structStudent *stu)
{
(*stu).score=2.2f;
}
int main(intargc,const char* argv[]) {
struct Studentstu1={"liu",12.3f};
//liu,2.200000
printScore(&stu1);
printf("%s,%f\n",stu1.name,stu1.score);
return 0;
}
枚举类型,基本数据类型,不是构造类型,因为不能再分解为任何基本类型
#include<stdio.h>
enumweek2{KMon1,KTue1,KWed1=5,KThur1,KFri1,KSta1,KSun1};
int main(intargc,const char* argv[]) {
//定义变量 1.
enum week1{KMon,KTue,KWed,KThur,KFri,KSta,KSun}iWeek1;
//纠正型变量
//2.
enum week2iWeek2;
//赋值
iWeek1=KMon;//0
iWeek2=KFri1;//7
printf("%d\n",iWeek1);
printf("%d\n",iWeek2);
return 0;
}
#include<stdio.h>
int sum(int a ,int b ){
return a+b;
}
int main(intargc,const char* argv[]) {
//1.基本数据类型
typedef intINTERGER;
//2.用在数组,给数组起别名
typedefint ARRAY[5];//相当于
ARRAY arr1 ={5,4,5,6,7};
for (int i = 0; i < 5 ; i++) {
printf("%d\n",arr1[i]);
}
//3.给结构体起别名 1)
struct Person {
int age ;
char *name;
};
typedef struct Person P;
P person2={22,"nmle"};
printf("%d,%s\n",person2.age,person2.name);
//3.给结构体起别名 2)
typedef struct Car {
int age ;
char *name;
}MYCAR;
MYCAR car1 = {22,"sdsd"};
printf("%d,%s\n",car1.age,car1.name);
//3.给结构体起别名 3)
typedef struct {
int age ;
char *name;
}IPHONE;
IPHONE iP = {22,"sdsd"};
printf("%d,%s\n",iP.age,iP.name);
//4.给枚举起别名
//
typedef enumSex{Kse1,Kse2,Kse3}Isex;
typedef enum {Kw3,Kw2,Kw1}weekday;
typedef enum Sex S ;
S s1 ,s2;
s1=Kse2;
s2=Kse3;
//5.给函数指针
typedef int(*FUN)(int,int);
FUN f1,f2;
f1=sum;
f2=sum;
printf("%d\n",f1(2,3));
printf("%d\n",f2(4,3));
return 0;
}
预处理命令编译之前的工作
#开头的预处理命令
无参宏定义方法
#include<stdio.h>
#define LEN5
#define X (x*y+2*3)//最好加一个括号
#define Y x*y+2*3
#define PI3.14
#define R4
#define AREA PI*R*R//宏的嵌套
#define INT1 int//起别名
int main(intargc,const char* argv[]) {
#undef LEN
int a[R+4];//int a[6]
int x=1 ,y=1;
//1.宏的作用域 #undef宏名取消宏定义
printf("X*X = %d\n",X*X);//49
printf("Y*Y = %d\n",Y*Y);//13
//2.宏的嵌套
printf("%.f\n",AREA);
//3.起别名
INT1 a1 = 12;
printf("a1 = %d\n",a1);
return 0;
}
无参数宏
#include<stdio.h>
#defineMAX(x,y) x+y
#defineequaL(m,n) m=x+y;n=x*y;
//1.宏名和形参之间不能有空格
int main(intargc,const char* argv[]) {
// insertcode here...
int r = 1 ;
printf("%d\n",MAX(r, r));//2
int x = 2 , y =3;
int i ,j ;
equaL(i, j);//4
// a+3+y,a-1+y
printf("%d,%d\n",i,j);
return 0;
}
// 有参宏应用
#include<stdio.h>
#defineMAX(a,b) a>b?a:b
int main(intargc,const char* argv[]) {
printf("Max(32,444)=%d\n",MAX(32, 444));
return 0;
}
// typedef和define的区别
//
// Created by CHINGWEI_MACPC on 15/11/9.
// Copyright © 2015年 itcast. All rights reserved.
//
#include<stdio.h>
#defineINT1 int
typedefint INT2;
#defineINT3 int*
typedefint* INT4;
int main(intargc,const char* argv[]) {
//宏定义变量
int num = 10;
INT1 a ,b ;
a=10;
b=10;
printf("a = %d\n",a);
//别名定义变量
INT2 a1,b1;
a1=100;
b1=100;
printf("a1 = %d\n",a1);
//宏定义变量
INT3 a3 ,b3 ;//只有 int *a3, 只有a3是指针变量
a3=#
b3=num;
printf("a3 = %d,b3=%d\n",*a3,b3);
//别名定义变量
INT4 a4,b4;//a4,b4都是指针变量
a4=#
b4=#
printf("a4 = %d,b4=%d\n",*a4,*b4);
return 0;
}
条件编译:
发生在预处理阶段,在编译之前做的事情
核心:根据条件编译指定的代码
条件不同:编译的部分也不同,生成的目标文件也不同 .o大小不同
*/
#include<stdio.h>
#define score100
int main(intargc,const char* argv[]) {
#if score <60
printf("Grade :F");
#elif score <=69
printf("Grade : D");
#elif score <=79
printf("Grade : C");
#elif score <=89
printf("Grade : B");
#else
printf("Grade : A");
#endif
printf("\n");
return 0;
}
只编译一部分,
// 条件编译指令
//
// Created by CHINGWEI_MACPC on 15/11/9.
// Copyright © 2015年 itcast. All rights reserved.
//
#include<stdio.h>
#define DEBUG11
int main(intargc,const char* argv[]) {
int a =0 ;
#ifdefDEBUG1
a = 10 ;
#else
a=10000;
#endif
printf("%d\n",a);
printf("%d\n",DEBUG);
#ifndef DEBUG2//如果没有定义宏
a= 100 ;
#else
a=-1;
#endif
printf("%d\n",a);
return 0;
}
#include<stdio.h>
#define DEBUG11
#if DEBUG1 ==1
//显示调试信息
#defineLog(format,...) printf(format,## __VA_ARGS__);
//...表示可变参数 //##可以有一个或者多个
#else
//不显示调试信息
#defineLog(format,...);
#endif
void test2(){
Log("test------->%-5.2f ,%d,%d\n",10.3f,3,30);
}
void test(){
Log("test ----- >%d\n",10);
}
int main(intargc,const char* argv[]) {
Log("xxxxxxx----->%d\n",10);
test();
test2();
return 0;
}