C语言

C语言

一个C语言程序有且只有一个main函数,是程序运行的起点

每个C语言程序写完后,都是先编译(.c),再链接(.obj),最后运行(.exe)


标识符:

  1. 由数字、字母、下划线组成
  2. 开头不能是数字
  3. 严格区分大小写

C语言只有八(0)、十、十六(0x)进制,没有二进制

整型一般4B,字符型1B,双精度一般8B


算术表达式: + - * / %

  1. “/“:两边都是整型则结果为整型,若有一边是小数则结果也为小数
  2. “%”:取余运算,只能对整数进行操作
  3. “/”:取整运算

赋值表达式:

  1. 定义时,不可以连续赋值

    例:int x=y=10;× int x,y;x=y=10;√

  2. 赋值的左边只能是一个变量

  3. 复合表达式

    例:int a=2;a*=2+3;(相当于a=a* (2+3))

  4. 自加表达式

    例:int a=5;++a;(a== 6)/a++;(a==5)

    例:int i=7;j=i++; j=7/i=8

    ​ int i=7;j=++i; j=8/i=8

  5. 逗号表达式

    z=(2,3,4);z为4

    z=2,3,4;整个逗号表达式值为4,但z为2


三种取整丢小数情况:

  1. int a=1.6
  2. b=(int)a;
  3. 1/2;3/2;

字符:

'a':字符1B

"ab":字符串2B (包含一个结束符号\0)

''1"× ‘12’×

字符是可以进行算术运算的 ,例:'0'-0=48


输入输出函数:要在最前面加上#include<stdio.h>

  1. printf()
    %d十进制 %o八进制 %#o带前导的八进制 %x十六进制 %#x带前导的八进制

    %%:输出一个百分号

    %md:输出m位十进制整数,小于则左端补空,大于则按实际输出

例:

#include <stdio.h>

int main()
{
   printf("%5d",1234567890);	/*1234567890*/
   
   return 0;
}
#include <stdio.h>

int main()
{
   printf("%5d",12);	/*   12*/
   
   return 0;
}

%m.nf:m为最小宽度,n为小数点后位数,小数位数被截断时按四舍五入输出(小数点占一位)

例:

#include <stdio.h>
int main()

{

   printf("%6.2f",34.56789);	/* 34.57*/

   return 0;

}


  1. scanf(),

    scanf("%d,%d",&x,&y,);第二个部分一定是地址

    char a=getchar(); 从键盘输入一个字符给变量a(多个字符用getschar)

    putchar('y'); 把字符y输出到屏幕中


       scanf与gets区别:scanf("%s",a);不可以接收空格 ;gets(a);可以接收空格


关系表达式:

#include<stdio.h>
int main(){
	int x=1;
	int y=0;
	int z=2;
	int a;
	a=x<y<z;
	printf("%d",a);	/*1-----------x<y<z为真*/
	return 0;
}

逻辑表达式:(表达式的数值只能为1或0)

&&、||、!

优先级:!>&&>||


按位与或异或取反

&、|、^、~(对补码按位取反)
负数在计算机中以补码的形式存在
~:无论正负数,先对数值本身加1,再改变符号位


循环:

  1. 输入123,输出321逆序:

    int i=123;while(i!=0)


函数:

  1. 当子函数在主函数之后时需要声明,当子函数在主函数之前时则不用

  2. 函数的参数可以是常量、变量、表达式、甚至是函数调用

  3. 只能是形参向实参的传递

  4. 实参与形参之间传数值,形参变化不会改变实参;实参与形参之间传地址,形参变化有可能会改变实参;

  5. 指令的划分以函数为单位,函数调用时,在堆栈区域申请一片栈帧(函数的局部变量、参数都分配在此);函数返回时,堆栈上的栈帧就要释放,栈帧的分配和释放遵循后进先出

  6. 函数定义中可以调用本函数——递归,一定要设置出口,否则会造成栈溢出;
    递推:小问题——>大问题;递归:大问题——>小问题

    传值:

    exch(int x,int y){
      int t;
      t=x;			//子函数没有返回值,ab值不会改变
      x=y;
      y=t;
    }
    void main(){
      int a,b;
      scanf("%d,%d",&a,&b);
      exch(a,b);
      printf("a=%4d,b=%4d\n",a,b);
    }
    

    传址:

    void fun(int *a,int *b){
      int t;
      t=*a;*a=*b;*b=t;
    }
    main(){
      int x=1,y=3;
      fun(&x,&y);
      printf("%d,%d",x,y);	//3,1
    }
    

指针:

指针的定义:

  1. int x=3;int *p=&x (定义的同时初始化)

  2. int x; int *p; x=3;p=&x; (定义之后初始化)

    p当做地址来使用,可以用在scanf函数中,scanf("%d",p);

    *p++ 地址变化

    (*p)++ 数值变化

​ int *p,a[]={1,3,5,7};p=a; 把数组第一个元素的地址赋值给p

​ 此时*p++本身数值为1,指向3的地址,(*p)++指针不移动,数值变为2


C语言中没有字符串变量,所以用数组和指针存放字符串


一级指针:*p,存放变量的地址

二级指针:**p,存放一级指针的地址

​ 例:int x=7;int *p=&x,**q=p;

​ 问:*p为多少?*q为多少? * * q为多少? **q=&x写法正确吗?

​ 7 p 7 不正确,二级指针存放一级指针的地址不能存放变量的地址


移动指针

​ char *s="yuanyu";while(*s){printf("%c",*s);} 变量的同时又赋值要加*

char ch[]="iamhandsome";
char *p=ch;

问:*(p+2)和*p+2的结果是多少?
             m     i+2=k


函数返回值是地址

int *fun(int *a,int *b){

  if(a>b) return a;

  else return b;

}

main(){

  int x=7,y=8,*max;

  max=fun(&x,&y);

  printf("%d",*max);	//8

}


函数指针的用法:

int add(int x,int y){}
main(){
  int (*f)();
  f=add;
}

调用:

  1. add(2,3)
  2. f(2,3)
  3. (*f)(2,3)

三名主义:

  1. 数组名:表示第一个元素的地址,不可以自加,是地址常量名

  2. 函数名:表示该函数的入口地址

  3. 字符串常量名:表示第一个字符的地址



数组:

数组在定义时就要指定大小

当数组元素过多时需要定义为全局变量(函数之外),因为函数被分配的内存区域有限

存放类型一致,多个数组元素的地址是连续的

最大特点:一次存入,多次使用


一维数组a[10]:

  1. a表示数组名,是第一个元素的地址,即a[0]的地址,等价于&a
  2. a是地址常量,只要出现a++,或者a=a+2赋值都是错误的
  3. a是一维数组名,是一个列指针

二维数组a[3][3]:

  1. a表示数组名,是第一个元素的地址,即a[0][0]的地址
  2. a是地址常量,只要出现a++,或者a=a+2赋值都是错误的
  3. a是一维数组名,是一个行指针
  4. a[0]、a[1]、a[2]也是地址常量,不可以进行赋值,都是列指针,a[0]+1是跳一列

一维数组初始化:

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

int a[5]={1,2,3, }; √

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

int a[5]={1,2,3,4,5,6}; ×数组越界


一维数组的定义:数组个数一定是常量

int a[5] √

int a[1+1] √

int a[1/2+4] √

int x=5,int a[x]; ×x是变量

define P 5 int a[P] √define后的P是符号常量(宏定义)

例:

#include <stdio.h>




int main()
{
   int score[8]={75,68,89,72,62,83,85,92};
	int sum=0;
	int average=0;
	int max=0;
	int min=100;
	int *p;
	for(p=&(score[0]);p<=&(score[7]);p++){
		sum+=*p;
		if(*p>max){
			max=*p;}
		if(*p<min){
			min=*p;}
		
	}
	printf("sum=%d\n",sum);		//sum=626
	printf("average=%f\n",sum/8.0);		//average=78.250000
	printf("max=%d,min=%d",max,min);	//max=92,min=62

   
   return 0;
}

二维数组初始化:

int a[2][3]={1,2,3,4,5,6}; √

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

int a[2][3]={{1,2,3} {4,5,6}}; √

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

int a[2][3]={1,2,3,4,5,6,7}; ×数组越界

int a[2][]={1,2,3,4,5,6}; ×不可以缺省列个数

int a[][3]={1,2,3,4,5,6}; √


a[2]=*(a+2)

a[2][3]=*(a+2)[3]=*(*(a+2)+3)


常用函数:

  1. strlen()字符串测长度函数

    strlen与sizeof区别:

    • strlen是一个库函数,sizeof是一个操作符
    • sizeof参数可以是数据的类型也可以是变量,strlen只能以“\0”结尾的字符串做参数
    • sizeof计算的是数据类型占内存的大小,strlen计算的是字符串的实际长度
  2. strcat()字符串连接函数

  3. strcmp()字符串比较函数

  4. strcpy()字符串拷贝函数

  5. malloc()动态分配内存函数(free释放)返回类型是void*


define:

  1. 预处理
  2. 宏定义

宏定义只是做替换,会出现优先级问题

int a,b,c,d,e;a=1;b=2;c=6;d=4;e=f(a+b)*f(c+d);

#define f(x) (x*x) e=(a+b*a+b)*(c+d*c+d)=5*34=170

#define f(x) x*x e=a+b*a+b*c+d*c+d=1+2+12+24+4=43

#define f(x) ((x)*(x) e=((a+b)*(a+b)*(c+d)*(c+d))=3*3*10*10=900


文件:

  1. 引入头文件:#include
    <>中是C语言的库,而“ ”中的是自己定义的
  2. 引入另一个.c中的函数要记得调用前先定义

字符串:

字符串即字符型数组,正文以‘\0’结束,但字符串长度不包括‘\0’

scanf只能接收一个单词,遇见空格即结束,此时可以使用

  • gets(str);获取带空格的字符串
  • strlen(srt);获取字符串的长度
  • strcpy(str,str1);给字符串str重新赋值,当str1为空时可清空str
  • strcat(str,str1);将两个字符串连接起来
  • char *c=strchr(str,'a');printf("%lld",c-str+1);查找str中第一次出现'a'的位置
  • char *c1=strchr(str,"abc");printf("%lld",c1-str+1);查找str中第一次出现"abc"的位置
#include <stdio.h>
#include <string.h>

int main()
{
    char str[100];
    gets(str);
    printf("%s\n",str);
    printf("%d\n",strlen(str));
    for (int i = 0; i <strlen(str) ; ++i) {
        printf("%c ",str[i]);
    }
}
//不可将strlen(str)赋值引用,否则将输出不了空格

赋值
char ch[10]={"abcdfegh"}; √

char ch[10]="abcdfegh"; √

char ch[10]={'a','b','c','d','f','e','g','h'}; √

char *p="abcdefgh"; √

char *p; p="abcdefgh"; √

char ch[10]; ch="abcdefgh"; ×数组名不可以赋值

char *p={"abcdefgh"}; ×不能出现大括号,指针没有大括号的说法


把s指针的字符串赋值到t指针中:

  1. while((*t=*s)!=null)
  2. while(*t=*s)
  3. while(*t++=*s++);

typedef:取别名

  1. typedef int qq那么int x可以写成qq x
  2. typedef int *qq那么int *x可以写成qq x

变量

  1. 全局变量:extern
  2. 静态变量:static只初始化一次,在上一次变化的基础上继续变化
  3. auto变量:只能在函数内修饰局部变量,在内存栈上进行分配
  4. register变量:允许将局部变量的值存放在寄存器内

调用变量会使用距离最近的被赋值的值

   #include <stdio.h>

   int a=1;
   int b=10;
   int c;

   void add(){
       c=a+b;
       printf("%d\n",a);
   }

   int main() {
       a=20;
//       int a=20; //此时重新定义了a,  c=11,a=1
       add();  //20
       printf("%d",c); //30
       return 0;
   }

宏定义

必须独占一行,前面只能是空格

  1. #define PI 3.1415926
  2. #define CH *
  3. #define mj(a,b) a*b*b

条件编译

不符合条件则不进行编译

  1. #if:涉及到宏定义的条件判断必须用条件编译
  2. #ifdef:如果已经定义过则执行
  3. #ifndef:如果没有定义过则执行
posted @ 2023-01-10 17:09  原语  阅读(473)  评论(0编辑  收藏  举报