配置C语言运行环境,下载code::blocks并运行第一个代码:
#include <stdio.h>
#include <stdlib.h>
int main()
{
printf("hello world!");
return 0;
}
数据类型
bool类型
非零(true),零(false)
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
int main()
{
bool a;
a = 1;
if(a){
printf("true, %d\n", a);
}
else{
printf("false, %d\n", a);
}
return 0;
}
bool类型只有零与非零的关系,只要是非零值都判定为真。
char类型
类型名称 | 长度(字节byte) | 值域 |
---|---|---|
char | 1byte==8bit | -128127或0255 |
signed char | 1 | -128~127 |
unsigned char | 1 | 0~255 |
原码反码补码
正数的原码反码补码都相同;
负数的反码即原码的除符号位其它位取反,补码就是反码+1
原码 | -1 | 1000 0001 |
---|---|---|
反码 | 1111 1110 | |
补码 | 1111 1111 |
计算机在内存中存储方式是补码。
使用char数据类型需要的变量需要注意防止超出阈值:
char c1 = 128; //出错,数据越界 -128
char c1 = 129; //出错,数据越界 127
unsigned char c2 = -1; //出错,数据越界 255
//1000 0001补码1111 1111
short类型
类型名 | 长度(字节byte) | 值域 |
---|---|---|
short | 2 | -32768~32767 |
unsigned short | 2 | 0~65535 |
int类型
类型名 | 长度(byte) | 值域 |
---|---|---|
int | 4 | |
unsigned int | 4 |
常量
常量指在程序运行时数值不发生改变的数据。
整形常量
整数可以是十进制数,八进制数和十六进制数
浮点常量
浮点常量又被称为实数,一般含有小数部分。
指数常量
指数形式的实数一般由尾数部分、字母e或E和指数部分组成。一般都用来表示特别大或特别小的数。
字符常量
字符常量是一个单一字符,其表示形式是由两个单引号包括的一个字符。
字符常量的值就等于字符的ASCII码值。
//可以把字符常量看作一个字节的正整数。
char a,b,c,d;
a = 'F'; //把70赋值给a
b = 'A'+2; //b存放的是'C'字符
c = ' '+'B'; //c存放的是'b'字符
d = 'b'-32; //d存放的是'B'字符
//他们分别相当于下列运算:
a = 70;
b = 65+2;
c = 32+66;
d = 97-32;
示例代码:
#include <stdio.h>
int main()
{
char c1 ,c2, c3;
c1 = 'A';
c2 = 'A'+' ';
c3 = 'A'+' '+2;
printf("%c %c %c",c1,c2,c3);
return 0;
}
字符串常量
字符串常量就是用双引号括起来的一串字符来表示的数据。(字符串以’\0’结尾)
#include <stdio.h>
int main()
{
char arr[] = {"abc"};
char arr2[] = {'a','b','c','\0'};
printf("%d %d \n",sizeof(arr),sizeof(arr2));
printf("%s %s \n",arr,arr2);
return 0;
}
标识常量
也叫符号常量,一般用大写英文字母的标识符。在使用之前必须预先定义,说明形式为:宏。
#include <stdio.h>
#define ONE 1
#define TWO ONE+ONE
#define TWOO ((ONE)+(ONE))
int main()
{
int a=10,b=20,c,c2;
c=ONE + TWO*b + a;//1+1+1*b+a = 32
c2=ONE + TWOO*b +a;//1+2*b+a = 51
printf("%d %d\n",c,c2);
return 0;
}
这里面的宏定义是企业笔试题经常会挖的坑,在宏定义时必须使用括号来标记优先级。
变量
变量在程序中用变量名表示,变量名由字母、数字、下划线组成,不能以数字开始,不能和C的关键字重名。
程序运行时,变量占据存储空间的大小由其数据组成。变量在内存空间中的首地址,称为变量的地址。
变量的声明
变量在程序中使用时,必须预先说明他们的存储类型和数据类型。
说明的一般形式是:<存储类型><数据类型><变量名>;
存储类型是关键字:auto、register、static和extern
数据类型可以是基本数据类型,也可以是自定义的数值。
变量的存储类型:
auto
说明的变量只能在某个程序范围内使用,通常在函数体内或函数中的复合语句中(默认是随机数)。
#include <stdio.h>
int main()
{
if(1){
auto int a;
printf("a=%d",a);
}
printf("a=%d",a);
return 0;
}
//例如这段代码编译会报错,auto定义的变量是一个局部变量,只能在if(1)的范围内使用,范围外则不能再使用auto定义的变量。
register
称为寄存器型,register变量想将变量放入CPU的寄存器中,这样可以加快程序的运行速度。如果申请不到就使用一般内存,同auto
register变量必须是能被CPU所接收的类型。这通常意味着register变量必须是一个单个的值,并且长度应该小于或等于int的长度。
不能用“&”获取register变量的地址。由于寄存器的数量有限,真正起作用的register修饰符的数目都依赖于运行程序的机器。
在某些情况下,把变量保存在寄存器中反而会降低程序运行速度。因为被占用的寄存器不能用于其他目的,或者变量被使用的次数不够多,不足以装入和存储变量所带来的额外开销。
#include <stdio.h>
int main()
{
register int a;
printf ("%d %p \n",a,a);//%p就是打出地址
return 0;
}
//这段程序会乱码,类型不匹配
static
static变量称为静态存储类型的变量,既可以在函数体内,也可以在函数体外说明(默认为0)。
局部变量使用static修饰有一下特点:
1.内存中以固定地址存放,而不是以堆栈形式存放;
2.只要程序没有结束,就不会随着说明他的程序段的约束而消失,它下次再调用该函数,该存储类型的变量不会重新说明,而且还保留上次调用存储。
#include <stdio.h>
int main()
{
int i=1;
while(i<5){
static int a=0;
a++;
printf("a=%d \n",a);
i++;
}
return 0;
}
static修饰的全局变量或者函数,意味着只能在本文件内使用。
extern
当变量在一个文件中的函数体外说明,所有其他文件中的函数或程序段都可以引用这个变量。
extern称为外部参照引用型,使用extern说明的变量是想引用在其他文件中的函数体外声明的变量。
static修饰的全局变量,其他文件无法使用。
//main.c
#include <stdio.h>
extern int a;
int main()
{
printf("a=%d\n",a);
return 0;
}
//extern.c
int c = 20;
上面extern则是告诉编译器这个变量a是来自外部文件的。
运算符
算数运算符
C语言提供的算数运算符:+、-、*、/、%、++、–。(float、double不能取余)
关系运算符
>、>=、<、<=、==、!=
逻辑运算符
!、&&、||
位运算
运算符 | 功能说明 | 举例 |
---|---|---|
~ | 按位取反 | |
& | 按位与 | |
| | 按位或 | |
^ | 按位异或 | |
>> | 位右移 | |
<< | 位左移 |
#include <stdio.h>
int main()
{
unsigned char x = 0126, y= 0xac, z;
z= x&y;
printf("%#x \n",z);
return 0;
}
//out:0x4
赋值运算符
+=、-=、*=、/=、%=、&=、|=、^=、>>=、<<=
#include <stdio.h>
int main()
{
int count = 0,sum = 0;
while(count++ < 100)
{
sum+=count;
}
printf("sum=%d\n",sum);
return 0;
}
//从1加到100。
特殊运算符
条件运算符
“?:”是个三目运算符
#include <stdio.h>
int main()
{
int x=70,y=25;
y=x++>70?100:0;
printf("x=%d y=%d \n",x,y);
return 0;
}
逗号运算符:
#include <stdio.h>
int main()
{
float x = 10.5, y=0.8, z=0;
z = (x+=5, y=x+0.8, z=x+y);
printf("x=%f y=%f z=%f \n",x,y,z);
return 0;
}
//逗号运算符的结果是由最后一个表达式所决定的。
//out x=15.5 y=16.3 z=31.8
sizeof运算符:
它只针对数据类型,而不针对变量
如:sizeof(double)、sizeof(long)
运算符优先级
优先级 | 运算符 |
---|---|
1 | ()、[] |
2 | +、- |
3 | ++、–、! |
4 | *、/、% |
5 | +、- |
6 | <<、>> |
7 | >、>=、<、<= |
8 | ==、!= |
9 | & |
10 | ^ |
11 | | |
12 | && |
13 | || |
14 | ?: |
15 | =、+=、-=、*=、/=、%= |
16 | &=、|=、<<=等位赋值运算 |
例如:
int x=1,y=0,z=0;
x++ && y++ || ++z; //结果为1
!(x+1>0) && y++ || ++z;//结果为1
x+=y==z,y=x+2,z=x+y+z>0;//x为2,y为4
输入输出
数据输出
C语言无I/O语句,I/O操作由函数实现
#include <stdio.h>
字符输出函数
putchar©
参数:c为字符常量,变量或表达式
功能:把字符c输出到显示器中
返回值:正常,为现实的代码值
#include <stdio.h>
int main()
{
int c;
char a;
c=65;a='B';
putchar(c);putchar('\n');putchar(a);
}
//out:
A
B
格式输出函数 printf
#include <stdio.h>
int main()
{
int a = 245;
char b = 'A';
char hello[] = "hello world";
float c =3.14;
printf("%d - %x - %o \n",a,a,a);//十进制、十六进制、八进制
printf("%c - %d \n",b,b); //字符、ASCII码
printf("%s \n",hello); //字符串
printf("%f - %e - %g \n",c,c,c);//浮点数、指数型、带小数点后有效数
return 0;
}
#include <stdio.h>
int main()
{
int a = 1234;
float f =123.456;
char ch='a';
char a[]="hello world";
printf("%8d, %2d \n",a,a);
printf("%f - %8f - %8.1f - %.2f\n",f,f,f,f);
printf("%3c \n",c);
printf("%s - %15s - %10.5s",a,a)
return 0;
}
字符输入函数 getchar
格式输入函数 scanf
语法:scanf(“格式控制串”, 地址表);
#include <stdio.h>
int main()
{
int a,b,c;
scanf("%4d%2d%2d",&a,&b,&c);
printf("%d-%d-%d\n",a,b,c);
return 0;
}
//若输入20210388则a为2021,b为03,c为88
int a,b;
scanf("%2d %*3d %2d",&a,&b);
//*为抑制符号,代表中间3位不要了。
//若输入1234567,则a为12,b为78。
输入函数垃圾清理
//使用输入函数可以会留下垃圾:
int x;
char ch;
scanf("%d",&x);
scanf("%c",&ch);
printf("x=%d ch=%c\n",x,ch);
//这段代码会有bug,只输入x,按下回车后会跳过ch的输入
方法1:用getchar清除回车符
方法2:用格式串中空格或"%*c"吃掉回车
字符串输入输出函数
字符串输入函数gets
char * gets(char *s)
功能:从键盘输入一回车结束的字符串放入字符数组中,并自动加’\0’
说明:输入串长度应小于字符数组维数;与scanf函数不同,gets函数不以空格作为字符串输入结束的标志
字符串输出函数puts
int puts(const char *s)
说明:字符数组必须以’\0’结束。
控制语句
if-else语句
switch语句
#include <stdio.h>
int main()
{
float score = 0;
printf("please input your score:");
scanf("%f",&score);
if(score<0 || score>100){
printf("input error\n");
return 0;
}else{
switch((int)score/10)
{
case 9:
printf("A");
break;
case 8:
printf("B");
break;
case 7:
printf("C");
break;
case 6:
printf("D");
break;
default:
printf("E");
}
}
return 0;
}
循环语句
goto
//如何使用goto 完成1-100求和
int main()
{
int i=1,sum=0;
loop:
if(i<=100){
sum=sum+i;
i++;
goto loop;
}
printf("sum=%d",sum);
return 0;
}
当程序有多个出口,使用goto集中到一处很方便。
理由:无条件跳转易于理解;可以减少嵌套;可以避免那些忘记更新某一个出口的问题
while
do-while
for
题目:九九乘法表
#include <stdio.h>
int main()
{
int i,j;
for(i=1;i<=9;i++)
{
for(j=1;j<=i;j++)
{
printf("%d*%d=%d \t",i,j,i*j);
}
printf("\n");
}
return 0;
}
辅助控制语句
break
用于从循环体内跳出循环体,即提前结束循环。
break只能在循环语句中和switch语句中。
for(r=1;r<=10;r++)
{
area=pi*r*r;
if(area>100)break;
printf("%f\n",area);
}
continue
结束本次循环,接着判定下一次是否执行循环。
for(n=100;n<=200;n++)
{
if(n%3 == 0){
continue;
}
printf("%d\n",n);
}
return
数组
一维数组
具有一定顺序关系的若干个变量的集合,组成数组的各个变量称为元素。数组中各元素的数据类型要求相同,用数组名和下标确定。
1.所谓一维数组是指只有一个下标的数组,它在计算机内存中是连续存储的。
2.C语言中,一维数组说明一般形式如下:
<存储类型> <数据类型> <数组名>[<表达式>]
数组名表示内存首地址,是地址常量。sizeof(数组名)表示数组占用的总内存空间。
编译时分配连续的内存,内存字节数=数组维数*sizeof(元素数据类型)
注意事项:
C语言对数组不做越界检查,使用时要注意
int a[5];
a[5]=10;//这么写是错的
关于用变量定义数组维数
int i=15;
int a[i];
一维数组的引用
数组必须先定义,再使用。
只能逐个引用数组元素,不能一次引用整个数组。
数组元素表示形式:数组名[下标]
int a[10];
printf("%d",a);//错误写法
for(i=0;i<10;i++)
printf("%d",a[i]);//正确写法
一维数组的初始化
1.在定义数组时,位数组元素赋值
int a[5] = {1,2,3,4,5};
2.说明
1.数组不初始化,其元素值为随机数
2.对static数组元素不赋初值,系统会自动赋以0
3.只给部分数组元素赋初值
static int a[5]; | 等价于a[0]=0;a[1]=0…a[4]=0 |
---|---|
int a[5]={6,2}; | 等价于a[0]=6,a[1]=2,a[2]=0,a[3]=0,a[4]=0 |
int a[]={1,2,4,4}; | 编译系统根据初值个数确定数组维数。 |
#include <stdio.h>
int main()
{
int a[]={1,2,3,4,5,6},i,n;
n = sizeof(a) / sizeof(int);//确定数组大小
for(i=0;i<n;i++){
printf("%d\n",a[i]);
}
printf("%d\n",sizeof(a));
return 0;
}
//最后out:24。说明数组a的内存大小是24个字节。
冒泡排序:
#include <stdio.h>
int main()
{
int a[]={1,2,14,16,8},i,j,n;
int t=0;
n=sizeof(a)/sizeof(int);
for(i=0;i<n;i++){
printf("%d ",a[i]);
}
printf("\n");
for(i=0;i<n-1;i++)
{
for(j=0;j<n-i-1;j++)
{
if(a[j]<a[j+1])
{
t=a[j];
a[j]=a[j+1];
a[j+1]=t;
}
}
}
for(i=0;i<n;i++){
printf("%d ",a[i]);
}
}
二维数组
二维数组的存放顺序:内存是一维的,按行序优先。
二维数组的引用:
数组名[下标][下标]
二维数组元素的初始化:分行初始化 / 按元素排列顺序初始化
例如:int a[2][3]={{1,2,3},{4,5,6}};
可以省略行数定义:int a[][3]={{1,2},{3,4,5}};
#include <stdio.h>
int main()
{
int a[2][3];
int i,j;
for(i=0;i<2;i++)
{
for(j=0;j<3;j++){
printf("%p ",&a[i][j]);
}
printf("\n");
}
printf("%p %d \n",a,sizeof(a));
printf("%p %d \n",a[0],sizeof(a[0]));
printf("%p %d \n",a[1],sizeof(a[1]));
return 0;
}
/*out:
000000000061FE00 000000000061FE04 000000000061FE08
000000000061FE0C 000000000061FE10 000000000061FE14
000000000061FE00 24
000000000061FE00 12
000000000061FE0C 12
*/
字符数组和字符串
字符数组
字符数组初始化,以下形式均可:
char ch[5] = {‘H’,‘e’,‘l’,‘l’,‘o’};
char ch[6]={“hello”};
char ch[6]=“hello”;
char ch[]=“hello”;
#include <stdio.h>
int main()
{
char str1[]={'a','b','c','\0'};
char str2[5]={'a','b','c'};
int i,n;
n=sizeof(str1)/sizeof(char);
for(i=0;i<n;i++)
{
putchar(str1[i]);
}
putchar('\n');
n=sizeof(str2)/sizeof(char);
for(i=0;i<n;i++)
{
putchar(str2[i]);
}
putchar('\n');
printf("%s \n",str1);//使用%s输出字符串必须以'\0'结束
printf("%s \n",str2);
return 0;
}
字符串数组
C语言中没有字符串常量,用字符数组处理字符串,字符串结束表示:‘\0’
char fruit[][7]={"apple","grape","pear","orange","peach"};
上面代码相当于5个1维数组。
#include <stdio.h>
#include <stdlib.h>
int main()
{
char fruit[][7]={"apple","grape","pear","orange","peach"};
int n,m,i,j;
n=sizeof(fruit)/sizeof(fruit[0]);//行数,总内存/1行的内存
m=sizeof(fruit[0])/sizeof(char);//列数
/*
for(i=0;i<n;i++){
for(j=0;j<m;j++)
{
putchar(fruit[i][j]);
}
putchar('\n');
}
*/
for(i=0;i<n;i++){
printf("%s \n",fruit[i]);
}
return 0;
}
倒序输出字符串:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 20
int main()
{
char str[N]={0};
int n,i;
printf("please input str:");
gets(str);
//n=sizeof(str)/sizeof(char);
n = strlen(str);
for(i=n-1;i>=0;i--){
putchar(str[i]);
}
return 0;
}
另一种思路:交换
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 20
int main()
{
char str[N]={0};
int n,i,j;
printf("please input strL");
gets(str);
n=strlen(str);
i=0;
j=n-1;
while(i<j)
{
t=str[i];
str[i]=str[j];
str[j]=t;
i++;j--;
}
puts(str);
return 0;
}
字符串函数
C语言库中实现了很多字符串处理的函数:#include <string.h>
几个常见的字符串处理函数:
1.strlen,求字符串长度
2.strcpy,字符串拷贝
3.strcat,字符串连接
4.strcmp,字符串比较
strlen函数
计算字符串长度,返回值字符串实际长度,不包含’\0’在内。
#include <stdio.h>
#include <string.h>
#define N 20
int main()
{
char s[10]={'a','0','b','\0','c'};
char s1[] = "\tab\v\\c";
printf("%d %d\n",strlen(s),sizeof(s));
printf("%d %d\n",strlen(s1),sizeof(s1));
return 0;
}
//这一例子中:out:
//3 10
//6 7
//原因,strlen当遇到'\0'则不再计算,只计算'\0'前面的字符数。
面试题:strlen和sizeof的区别:
1.strlen是一个函数,sizeof是一个运算符。而且strlen只计算’\0’前面的字符,而sizeof是计算整个的内存大小。
strcpy函数
格式:strcpy(字符串1,字符串2);
功能:将字符串2拷贝到字符串1。
返回值:返回字符串1的首地址
说明:字符数组1必须足够大;拷贝时’\0’一同拷贝。
#include <stdio.h>
#include <string.h>
#define N 30
int main()
{
char str[] = "hello";
char des[N];
int i,n;
n=strlen(str);
//strcpy(des,str);
//等价于↓
while(i<=n)
{
des[i]=str[i];
i++;
}
puts(str);
puts(des);
return 0;
}
strcat
格式:strcat(字符数组1,字符数组2);
功能:把字符数组2连接到字符素组1后面
返回值:返回字符数组1首地址
说明:字符数组1必须足够大;连接前,两串均以’\0’结束,连接后,串1的’\0’取消,新船最后加’\0’。
strcmp
格式:strcat(字符串1,字符串2);
功能:比较两个字符串
比较规则:对两串从左向右逐个字符比较ASCII码值,直到遇到不同字符或’\0’为止。
返回值:返回int型整数
若字符串1<字符串2,返回负整数
若字符串1=字符串2,返回0
字符串拓展用法
strncpy(str1,str2,n);复制指定长度字符串
strncat(str1,str2,n);指定长度附加