标准C基础知识笔记四
定义数组要指定元素的个数(固定的)
数组名代表什么数组,当作为数值来用时,表示数组第一个元素;
下标一定比元素个数少1
尽量避免越界
一般来说多维能解决的问题,用一维数组也能解决
*(a+i);//这个是地址的加法 相当于a+i*sizeof(int)
对于char数组可以存放字符串,但是必须有\0结尾标志
^D,输入结束
strcmp();用来比较两个字符串
strcpy只能用于字符串赋值
strct在某一个字符串追加一个字符串
“字符串”是存储在只读存储器中的,只有系统能访问不能修改。===》如果修改的话,会出现段错误
strlen(...)
strcmp(...,...) 相等0,左边大为正,左边小为负(比较的是ascii码)
strchr 从左往右查找字符串
strrchr 从右往左查找字符串
strstr 从字符串中查找字符串
结构的对齐与补齐
联合(共用体)
函数
vi struct.c
#include <stdio.h>
typedef struct Goods{
char name[18];//18个字节
double price;//8个字节
char special;//1
int num;//4个字节
short saled;//2个字节
}gs;
int main()
{
gs a[10];//定义一个Goods的变量数组,不用初始化,可以通过键盘来输入
printf("%d\n",sizeof(gs));//查看gs类型占用多少字节的存储空间
//对齐;一般来说一个变量分配空间的时候都会考虑分配内存边界上,
//一个变量的占用的内存地址,一般是这个变量占用的字节的倍数;
//虽然这样看起来有点浪费,但是访问起来速度快
//char随便一个地址就可以访问;short为2的倍数,int为4的倍数;double为8的倍数
//一般编译器超过4,也按照4的倍数来访问
return 0;
}
对齐规则:每个成员都从本身长度的倍数开始
-------------------------------------------------------
| name 18 | 空2|price 8|special 1| int num 4| 空 4|
-------------------------------------------------------
补齐:是为了多个元素挨着摆放时,也能满足对齐规则
为什么要对齐和补齐呢?(不同的OS,其寻址是不一样的)
32位的操作系统在访问数据的时候都是从内存中按照4的倍数来访问数据。
数组的元素的内存存储地址不一定是连续的,可能存在间隙;
位断:
由于内存分配是按照几个字节来分配的。但个别时候可能只需要几个位即可;C语言可以设置为某几个
成员用几个位
//一般会用在嵌入式开发中。每一个位控制一个东西,控制一个管脚
#include <stdio.h>
struct mode{//比如用户的读写执行权限rwxrwxrwx
unsigned char userread:1;
unsigned char userwrite:1;
unsigned char userexecute:1;
unsigned char groupread:1;
unsigned char groupwrite:1;
unsigned char groupexecute:1;
unsigned char otherread:1;
unsigned char otherwrite:1;
unsigned char otherexecute:1;
unsigned char f3:3;
unsigned int f10:10;
};
int main()
{
struct mode m={1,1,0,1,0,0,1,0,0,6,999};//初始化
printf("size:%d\n",sizeof(m));
printf("%d%d%d,%d%d%d,%d%d%d",
m.userread,m.userwrite,m.userexecute,
m.groupread,m.groupwrite,m.groupexecute,
m.otherread,m.otherwrite,otherexecute
);
printf("%d,%d\n",m.f3,m.f10);
return 0;
}
//备注:在vi下替换某几行内的某个字符串user为另一个字符串other
// :10,12s/user/other/
联合union
所有成员共用一块地方(共用体),操作任何一个都会影响其他的。
那么什么时候用联合呢?这些成员总是只用一个。
#include <stdio.h>
union IP{
char i4[4];
int net;
//可以使用192.168.x.x格式来表示IP;也可用一个整数来表示一个IP地址
};
int main()
{
printf("sieze:%d\n",sizeof(union IP));
IP me{192,168,0,20};
printf("%x\n",me.net);
me.net=0x12345678;
int i;
for (i=0;i<4;i++)
printf("%d ",me.i4[i]);
printf("\n")
return 0;
}
不同系统,其存储方式也是不一样的,有的是小端存储有的是大端存储
C语言本身就是一个函数语言;把实现某一个功能的打个包==》函数
printf scanf strcpy strlen strcat....标准C里面的标准库函数
vi function.c
#include <stdio.h>
int main()
{
int n=Main(); //Main()带回一个数值10
printf("hello world!\n");
n+=Main();
return 0;
}
int Main()//函数名是区分大小写的
{
printf("你好 世界\n");
return 10;
}
一个C语言只有一个main函数,也是程序的入口,可以在main函数内调用其他函数。
写一个函数清输入缓冲区
#include <stdio.h>
void clear();//函数声明;
int main()
{
char name[20];
char gender;
printf("请输入姓名:");
scanf("%s",name);
clear();//这个决定了要把void clear()函数放到前面;负责会出现隐式声明错误;
printf("请输入性别(M/F):");
scanf(" %c",&gender);//理解为什么在" %c"有一个空格;因为上面输入姓名之后肯定要敲个回车来确定输入。但这个回车会留在输入缓冲区中;会影响下面的输入。
//所以要加个空格来解决这个问题
printf("%s:%c\n",name,gender);
}
void clear()//void代表这个函数不带东西回来;函数体
{
scanf("%*[^\n]");
scanf("%*c");
}
C语言中对于不认识的类型,一般会默认的为int类型(隐式声明)
函数定义:函数名、函数声明、函数体
函数调用:
从键盘输入一个指定范围内的整数(get5,80)
#include <stdio.h>
int get(int a,int b)//形参(定义的时候使用)
{
printf("请输入两个整数:\n");
printf("a=%d,b=%d\n",a,b);
int n;//这里的n与main里面的n是不同的n。在不同的{}号的是不同的。
do{
printf("请输入%d到%d的一个整数:",a,b);
//scanf("%d",&n);//切记:在这里%d后面没有\n
if(scanf("%d",&n)!=1){
scanf("%*[^\n]*c");
//进一步判断输入的a<b,如果a>b,则需要交换数值
//判断输入的是整数而非小数或字符
}
}while(n<a||n>b);
return (a+b)/2;
}
int main()
{
int n=get(1,100);//实参(调用的时候使用)
int m=get(10,50);
printf("n=%d,m=%d\n",n,m);
return 0;
}
******************************************************
写一个函数在多个程序里面能够使用(函数调用);
------------------------------------
编写一个程序里面带clear函数
vi clear.c
#include <stdio.h>
void clear(){
scanf("%*[^\n]");
scanf("%*c");
}
编写一个声明clear函数
vi func_clear.h
void clear();//前面已经写了一个clear函数,在这里只是写一个函数声明
在写的程序里面调用这个函数
vi param.c
#include <stdio.h>
#include "func_clear.h" //函数的声明
int main()
{
clear();
return 0;
}
//把声明插入一份就行了。
一个程序两个文件怎么来编译呢?==》分开编译,连接
编译:
gcc -c clear.c //只编译
gcc -c param.c
gcc clear.o param.o//合在一起,谁前谁后无所谓
man gcc
每一个头文件感兴趣就可以man下看看到底是怎么回事。
一般.h文件都在/user/include目录下
//写一个小程序来观看函数调用
//输入一行文字
//将其中的数字转换成对应的汉字,小写字母变成大写,其他不变
vi check.c
#include "check.h" //把函数声明插进来
bool isLower(char c)
{
return(c>='a'&&c<='z');
}
bool isNum(cha c)
{
return(c>='0'&&c<='9');
}
vi check.h
//函数声明
typedef enum bool{true=1,false=0}bool;//c语言里面并没有bool类型,定义一个类型
bool isLower(char c);
bool isNum(char c);
转换函数
vi convert.c
#include <stdio.h>
char toUpper(char c) //把小写转换成大写
{
return(c-'a'+'A'); //c-'a'字符在字母表中的偏移量;+'A'在大写字母中的偏移量
}
char* toChinese(char c) //汉字是一串字符,而非一个字符;操作字符串,只要知道数组的开始地址即可。
{
char num[10][5]={"零","一","二","三","四","五","六","七","八","九"};
//这样定义的含义?10个一维数组,每个一维数组
printf("%s",num[c-'0']);
return(num[c-'0']);//基本上没作用;变量是有范围的
//'0',数字为48;c-'0'
}
vi convert.h
char toUpper(char);
char* toChinese(char);
#include <stdio.h>
#include "check.h"
#include "convert.h"
int main()
{
char c;
printf("请输入一行文字:");
do{
scanf("%c",&c);
if (islower(c))
printf("%c",toupper(c));
else if(isnum(c))
printf("%s",tochinese(c));
else
printf("%c",c);
}while(c!='\n');
return 0;
}
vi charaddr.c
#include <stdio.h>
int main()
{
char a[100]="good afternoon,everyone!";
char* p=a+5;//a+5===>&a[5],在这里两者是等价的
printf("%s\n",p);
return 0;
}
问题:
//判断某年有多少天
//日期是否有效日期;
//日期是这一年的第几天
//日期是这一年的第几周的哪一天
函数:
单一定义原则;
函数多次声明;
常用的C语言标准库文件
stdio.h //输出输入
stdlib.h //工具
time.h //时间相关
math.h //数学相关
string.h //字符和内存操作
ctype.h //字符操作
局部变量和全局变量
#include <stdio.h>
#include <string.h>
char w[7][10]={"星期日","星期一","星期二","星期三","星期四","星期五","星期六"};
//这种变量为全局变量(无什么范围限制;在C里面先声明后使用)
//也可以使用extern来声明,告诉编译器,w在其他地方有定义;
//extern char w[7][10];
char* week(int);
char* weekday(int n)
{
return w[n];
}
int main()
{
printf("%s\n",weekday(3));
strcpy(week(5),"fr");//通过week(5)知道其地址,然后重新赋值
printf("%s\n",week(5));
return 0;
}
vi weekday.c
#include <stdio.h>
//下面这句配合extern来使用
char w[7][10]={"星期日","星期一","星期二","星期三","星期四","星期五","星期六"};
char e[7][10]={"Sunday","Monday",...};
//通过这种方式也可以实现多语言的支持
//static h[7][10]={,,,,};//static限制全局变量只能在本文件中使用,对外隐藏
void showweekday(int n)
{
printf("%s\n",weekday(5));
printf("%s\n",e[2]);
return 0;
}
char* week(int n)//构建一个函数,让外界通过调用这个函数来访问static全局变量
{
return h[n];
}
文件本身并不限制全局变量的范围;static可以限制全局变量只能在本文件中使用
但是其他文件怎么能访问这个static的全局变量呢,可以构建一个函数,通过调用函数的方式即可
strcpy(week(5),"fr");
全局函数只能在本文件中使用也是加static
#include <stdio.h>
#include <string.h>
char* weekday(int n)
{
static char w[7][10]={"星期日","星期一","星期二","星期三","星期四","星期五","星期六"};
return w[n];
}
int counter()
{
int cnt=0;
//static int cnt=0;
//静态局部变量,第一次使用的时候分配空间,一直保留直到程序结束。static局部变量只初始化一次。
return ++cnt;
}
int main()
{
printf("%s\n",weekday(3));
int i;
//auto signed int i;//自动,基本不用。
for (i=0;i<5;i++)
printf("%d\n",counter());
return 0;
}
由于全局变量并不安全,所以程序里面尽量少用全局变量。
静态全局变量和局部变量不会有垃圾数据,要么是0要么是指定的数据。
time:从1970.1.1 00:00:00计算到现在的时间的秒数
register寄存器---请求把变量放到寄存器中而不是内存中;寄存器比内存快
寄存器是没有地址的;通过&i取地址会报错。
#include <stdio.h>
int main()
{
register int i=100;//register是一个使用寄存器的请求,用不用不一定
printf("%d\n",i);
return 0;
}
volatile int n;//这个变量可能会随时被莫名其妙的修改
一般会用在嵌入式开发中,可能由某个硬件直接来控制(如传感器)。