C语言详解-程序员宅基地

技术标签: C语言  c语言  

前言

这里是我对学C语言的一些总结,对于这几个月的学习进行一个复盘,共计1.2w字,希望对大家的学习能有帮助。

  • C语言入门
  • 1.C语言的具体结构
  • 2.程序的——注释
  • 3.标识符
  • 4.变量及赋值
  • 二、C语言数据类型
    • 1.基本数据类型
    • 2.构造类型
    • 3.指针类型
    • 4.void类型
  • 三、C语言函数类型及指针2.0
  • 1.函数的作用&无参函数
  • 2.有参函数
  • 3.函数指针
  • 4.指针函数
  • 5.数组指针
  • 6.指针数组
  • 7.二级指针
  • 8.void指针
  • 9.静态链表
  • 10.动态链表
  • 四、各个关键字的用法
  • 1.break
  • 2.continue
  • 3.static
  • 4.extern
  • 5,malloc
  • 6.typedef
  • 7.const
  • 五、预编译&条件编译
  • 1.#define 无参
  • 2.#define 有参
  • 3.#if 条件编译
  • 六、冒泡排序


一、C语言入门

C语言的特点灵活方便,执行效率高,可移植性好,可以用来开发应用软件、驱动、操作系统等。

1.C语言的具体结构

#include <stdio.h>

void main()
{
    printf("Hallo World");
    
}

#include <stdio.h> 包含输入输出头文件,因为你要用到printf、scanf等这些函数,所以你要包含对应的头文件才能使用,否则会编译出错。

void main()  main()是主函数,void是这个函数的类型,c程序代码的入口就是从main()开始执行的,也是c语言执行代码唯一的入口,是c程序中必不可少的存在

2.程序的——注释

#include <stdio.h>

void main()
{

    //printf("Hallo World");
}

//表示注释这一行,在//后面的内容都不会执行,是写给程序员看的

#include <stdio.h>

void mian()
{
    /*

        2021.12.26---------2022.6.21

    */
    
    printf("Hallo World");


}

  /*这里面的内容都不会被执行,也是写给程序员看的,可以一次性注释多行*/ 

3.标识符命名

#include <stdio.h>

void main()
{
    int a  = 10;//给变量取名字也就是(标识符)
    int a1 = 10;//标识符只能用数字,字符,下划线组成
    int_a  = 10;//其中开头只能用字符和下划线


}

4.变量与赋值

变量就是可以变化的量,每个变量都有一个(数据类型),变量会在内存中占据一定的存储单元,使用变量之前先定义所使用的数据类型,, 变量的名字可以自己取(不能取关键字等),变量的数据类型必须依靠c语言已有的来取。

void main()
{

    int a          = 20;//定义了一个整型变量,同时给它赋值了一个20;
    float b        = 22;//定义了一个实型(单精度)变量,同时给它赋值了一个22;
    double c       = 6; //定义了一个实型(双精度)变量,同时给它赋值了一个6
    char   d       = '2';//定义了一个字符型型变量,同时给它赋值了一个字符2;
    unsigned int e = 1; //定义了一个无符号整型.....
    
}

变量定义的一般形式:数据类型 变量名;

一次性定义多个变量:数据类型 变量名,变量名...;

 赋值分为两种:

1.先定义,在赋值

2.定义同时一起赋值

二、C语言数据类型

1.基本数据类型

#include <stdio.h>

void main()
{
    int     a; //int是整型,只能存放整数
    float   a1://float是实型,只能存放小数
    double  a2'//double是实型,只能存放小数
    char    a3;//char是字符型,只能存放字符以及字符串

}

int 用于存放整数,占4个字节(编译器不同可能也不一样)

float 和 double 都是用于存放小数,float占4个字节,doule占8个字节

char 用于存放字符,占1个字节

2.构造数据类型

数组类型

数组从语义上说就是存放数据的一个集合。

元素是数组内存里面存放的数据。

下标是对应数组元素所在数组的位置。

访问超过数组下标的元素,就越界了;

一维数组遍历

#include <stdio.h>

void main()
{

    int a[6] = {1,2,3,4,5,6};//a是数组的首地址也是第一个元素的地址也是数组名
                            //[6]表示数组存放元素的长度
    int _a[6] = {1,2,3};    //如果我数组长度写的6个,但是我赋值只有3个,那未初始化的数据就是0
    int i;

    for(i = 0;i < 6;++i)
    {
        printf("%d",a[i]);
    }                        


}

二维数组遍历

#include <stdio.h>

void main()
{

    int a[2][3]={
   {1,2,3},{4,5,6}};
    int i,j;    
    int *p ;
    p = a;

    for(i = 0;i < 2;++i)
    {
        for(j = 0;j < 3;++j)
        {
            printf("%d",a[i][j]);
        }                                                        
     }
}

 结构体类型

数组只能存放类型相同的数据的集合,而结构体就是可以存放类型不同的数据的一个集合

结构体定义 :struct 结构体名字{变量;变量;...}结构体变量;

#include <stdio.h>
#include <string.h>//因为要用到strcpy

struct student      //struct表示这是个结构体 student是结构体名字 struct student组合起来就是一个新的数据类型 a是这个结构体的变量
{
    int num;     //定义结构体成员
    char score;
    char project[20];
}a;//定义结构体变量


void main()
{
    
  //struct student b;//也可以在这里定义结构体变量
  a.num  = 10;//给结构体成员赋值
  a.score = 'c';    
  strcpy(a.project,"李建华");

  printf("%d",a.num);//输出结构体num的数值
  printf("%c",a.score);
  printf("%s",a.project);

}

typedf定义:typedf struct 结构体名字{变量;变量;...}typedf新的类型;p 结构体变量;

#include <stdio.h>
#include <string.h>//因为要用到strcpy

typedef struct student      
{
    int num;     //定义结构体成员
    char score;
    char project[20];
}p;//struct student 是数据类型,typedf 数据类型 p,p就是(struct student)只是重新修改了而已


void main()
{
    
  p a;//在这里定义结构体变量
  a.num  = 10;//给结构体成员赋值
  a.score = 'c';    
  strcpy(a.project,"李建华");

  printf("%d",a.num);//输出结构体num的数值
  printf("%c",a.score);
  printf("%s",a.project);
}

嵌套定义结构体

#include <stdio.h>

struct max1
{
    int num;

};


struct student      
{
  struct max1 b;//定义结构体变量 

}a;


void main()
{
    a.b.num = 100;
    printf("%d",a.b.num);
 
}

结构体数组

#include <stdio.h>



struct student      
{
    int num;

}a[2];//定义了一个结构体数组 每个元素都包含了一个成员项


void main()
{
    int i;
    a[0].num = 100;
    a[1].num = 200;
   

  for(i = 0;i < 2;++i)
 {
    printf("%d",a[i].num);
 }
 
}

怎样计算结构体所占的内存 

大家是不是以为,char+int+char =1+4+1 = 6,应该是6个字节,为什么是12呢?

因为结构体内存讲究对齐法则

共用体类型

为什么需要共用体?因为在以前的电脑内存是十分有限的,用结构体占用的内存太多了,用共用体可以节约内存,但是因为共用体里面的成员都用一块内存,所以共用体成员谁占的字节多,就用那块内存,你给共用体里面的成员都赋值,它也只会输出最后赋值的那个变量,因为前面赋的值都被后面赋的值给覆盖了。

#include <stdio.h>

union job //union表示这是一个共用体 job共用体名字  
{
    int a ;     //共用体成员 
    short int b; 
        
};//也可以在这里定义共用体变量 



void main()
{
    union job p;//定义共用体变量 

    p . b = 100;//给共用体赋值 
    p . a = 1000; 

    printf("%d  ",p.a);//因为它们共用一块内存 前面赋的值 被后面赋的值覆盖了 它只会输出最后被赋值的变量  
  

}

//输出结果是:1000

注意:union 也是可以用typedef来定义;

枚举类型

枚举用什么作用?通过枚举我们可以灵活定义成员里面的数据,用的时候方便取,也好调整成员里面的数据 ,#define一次性定义一个常量 enum可以一次性定义多个,大大提高了程序的可读性

输出枚举成员:

#include <stdio.h>

enum Day{a,b,c,d}p;//enum表示这是个枚举类型 Day表示这是枚举的名字 p是枚举变量 
				  //里面存放的是枚举成员的常量 没有被赋值 第一个成员= 0,后面依次加1 
				 

void main()
{
	
	printf("%d",a);	//因为枚举成员是常量,所以可以直接拿出来输出
	printf("%d",b);	
	printf("%d",c);	
	printf("%d",d);		
	
	
}
  //输出结果:0 1 2 3

既然可以直接输出枚举成员,那要枚举变量有什么用?

#include <stdio.h>
void main( ) 
{ 
	enum weekday {sun ,mon,tue,wed,thu,fri,sat} day; 
	
	int k; 
	printf("input a number(0--6)"); 
	scanf("%d",&k);
	day=(enum weekday)k; //给enum变量赋值必须用强制转换  
	
	switch(day) //可以用于判断... 
	{ 
	case sun: printf("sunday/n");break; 
	case mon: printf("monday/n");break; 
	case tue: printf("tuesday/n");break; 
	case wed: printf("wednesday/n");break; 
	case thu: printf("thursday/n");break; 
	case fri: printf("friday/n");break;
	case sat: printf("satday/n");break; 
	default: printf("input error/n");break; 
	} 
} 

注意:enum里面定义的成员是用','隔开,而不是用分号 

3.指针类型

#include <stdio.h>

void main()
{
    int  a = 5;//定义了一个整型
    int *p;    //定义了一个指针变量,它所指向的数据是一个整型
              //int 是它所指向的类型,p是一个变量,*p是告诉编译器它是一个指针变量,用于存放地址
    p = &a;   //p保持了a的地址,此时p指向a,*p就可以取a的值了


}

注意:int* 、float*、 double* 、char*都是属于指针类型 

同时指针也可以指向数组

#include <stdio.h>

void main()
{
    int a[3] ={1,2,3};
    int i;
    int *p;
    p = a; //p保存了a的地址

   for(i = 0;i < 3;++i)
   {
     printf("%d",*(p + i));//p保存了a的地址,p+1表示它指向下个地址,指向了a[1],*(p+1)取a[1]的值
   }                      //因为数组存放地址是连续的,所以p+1就可以指向下个元素的地址
   

}
#include <stdio.h>

void main()
{

    int a[2][3]={
   {1,2,3},{4,5,6}};
    int i,j;    
    int *p ;
    p = a;

    for(i = 0;i < 2;++i)
    {
        for(j = 0;j < 3;++j)
        {
            printf("%d",*(*(p + i)+j));//行就是列的首地址,p保存了行的地址,*(p+i)是行的值也是列的首地址 (*(p+i)+j)就是第0行0列的地址,*(*(p+i)+j)就是第0行0列的数值
        }                                                        
     }
}

结构体指针 

#include <stdio.h>
#include <string.h>//因为要用到strcpy

struct student      
{
    int num;     
    char score;
    char project[20];
}a,*p;


void main()
{
  p = &a;//p指向这个地址  可以p->num访问 也可以 (*p).num
  a.num  = 10;
  a.score = 'c';    
  strcpy(a.project,"李建华");

  printf("%d",(*p).num);
  printf("%c",p->score);
  printf("%s",p->project);
}

4.void类型 

C语言中的void类型,代表任意类型,而不是空的意思,而是说它的类型是未知的,是还没指定的。
void * 是void类型的指针。void类型的指针的含义是:这是一个指针变量,该指针指向一个
void类型的数。void类型的数就是说这个数有可能是int,也有可能是float,也有可能是个结构体,哪种类型都有可能,只是我当前不知道。

 

三、C语言函数类型及指针2.0

1.函数的作用&无参函数

函数有什么作用,我们来看代码来了解

#include <stdio.h>

void main()
{

    int a,b,sum;
     
    a = 2;
    b = 3;    
    sum = a + b;
    printf("sum = %d",sum);
    


}

例如这段代码,我求的是2和3的和,要是我求其他数的和那我不得修改a和b的值,很麻烦,我们可以用函数来做,可以把函数的作用理解为,可以使程序模块化,避免了重复性操作。

#include <stdio.h>

void main()
{
	void p(int a,int b);//函数声明
    int a,b,sum;
    p(2,3);//调用这个函数并给他传2,3这两个数据
     
}

void p(int a,int b)//void表示函数的返回类型是没有指定的也就是无返回类型 p是函数名字 (int a,int b)这是函数的形参 用于接收实参的数据
{
    int sum;
    sum = a+b;
    printf("sum = %d",sum);
    
} 


//输出结果:5

函数可以嵌套调用, 但不可以嵌套定义 

2.有参函数

有参函数是可以返回数据,也可以选择不返回数据的,当然函数返回可以是表达式、变量、也可以是地址;

#include <stdio.h>

 main()
{
	int p(int a,int b);
    int a,b,sum;
    sum=p(2,3);
    printf("sum = %d",sum);
     
}

int p(int a,int b)//函数返回类型是int型,所以只能返回int类型的数据
{
    int sum;
    sum = a+b;
    
    //printf("sum = %d",sum);//有参函数,我可以返回,也可以不返回
    return sum;//把sum这个值返回调用的那里去
    
}

//输出结果; 5 

3. 函数指针

void (*p)(int a,int b);函数指针的本质其实就是一个指针,只不过这个指针指向的是一个函数,它通过指向了这个函数的地址,就可以实现调用这个函数。

#include <stdio.h>

void main()
{
    void f(int a,int b);
    void (*p)(int a,int b);//定义一下函数指针

    p = f;//p指向了函数的首地址,因为函数名就是函数首地址,所以加不加&都可以
    (*p)(2,3);//*p调用这个地址,也可以直接用p调用
    

}        

void f(int a,int b)
{
    int sum;
    sum = a + b;
    printf("%d",sum);
    
        
}    

//输出结果:5                                                

4.指针函数 

int *p(int *a,int *b);指针函数本质上就是一个函数,只不过这个函数返回类型是一个指针而已,我们可以通过指针来改写实参的地址。

#include <stdio.h>

void main()
{
    int *f(int *a,int* b);
    int a,b;
    int* p;//定义一个指针用来接收返回的地址
    a = 2;
    b = 3;
    p =f(&a,&b);

    printf("%d",*p);
    
    
    

}        

int* f(int *a,int* b)
{
    int *p,*p1,*max;
    p = a;
    p1 = b;
    
    if(*p > *p1)
    {
    	max = p;
	}
	else
	{
		max= p1;
	}
    
    
    return max;//返回最大的那个数 返回的类型是int型的
    
        
} 

//输出结果:3                                                   

 5.数组指针

int (*a)[6];数组指针实际上就是一个指针,只不过这个指针指向的是数组, 一般多用于二维数组。

#include <stdio.h>

void main()
{
    int b[2][3] = {1,2,3,4,5,6};
    int (*p)[3]; //[3]数组最大的元素长度 二维数组一般看列的长度 一维数组看行的长度 
    int i,j;  //用于输出二维数组 
    p =b;

    for(i = 0;i < 2;++i)
    {
        for(j = 0;j < 3;++j)
        {
            printf("%d",*(*(p+i)+j));//p保存了行的地址 
        }        
    }

  
}

//输出结果:1 2 3 4 5 6

6.指针数组 

int* p[3];指针数组本质上就是一个数组,只不过这个数组存放的元素是指针

#include <stdio.h>

void main()
{
   int a,b,c;
   int*p[3];//定义了一个指针数组
   a = 2;
   b = 3;
   c = 4;
   p[0] = &a;//数组里面的元素指向一个地址
   p[1] = &b;
   p[2] = &c;

	printf("%d",*p[0]); //输出指向地址的值
	printf("%d",*p[1]); 
	printf("%d",*p[2]); 
  
}

7.二级指针 

int **p;二级指针,也就是指向指针的指针

#include <stdio.h>

void main()
{
    int a = 5;
    int *p =&a;
    int**p1 = &p;//指向这个指针 
    
    printf("%p\n",p1);//p1的地址 
    printf("%p\n",*p1);//a的地址 
    printf("%p\n",&a);//a的地址 
    printf("%d\n",**p1);//a的值 
}

8.void指针 

void *p;这个指针它所指向的数据类型是不确定的,但是你仍然可以让他指向一个地址,你要输出这个地址的值,就必须用强制转换成你要输出数据类型的指针。

#include <stdio.h>

void main()
{
    int a = 5;
    void *p;
    p = &a;//p指向这个地址 
    
    printf("%d\n",*(int *)p);//因为这个数据是int类型的,所以要强制转换成对应类型的指针 
  
    
}

//输出结果:5

9.静态链表 

静态链表指的就是用一个头指针指向第一个地址、第一个地址保存下一个地址.....如图:

1.head保存a的地址,a里面有两个数,一个是数据,一个是指针也称节点,a的节点保存b的数据,b的节点保存c的数据,c的节点保存d的数据,d的节点没有了也就是保存的null。
2.为啥和数组一个功能都是指针指向一个地址再输出元素,数组不更好用吗?
数组的地址是连续的,链表的地址不是连续的,是自己指针分配的,所以也叫静态链表
3.静态链表用法:

#include <stdio.h>

typedef struct student
{
    int score;
    struct student *next;//创建一个节点 
}p;//重新定义了struct student这个类型 

void main()
{
  p a,b,c,d,*head; 
  a.score = 10;//给结构体变量赋值 
  b.score = 20;
  c.score = 30;
  d.score = 40;

  head = &a;//头指针保存a的地址 
  a.next = &b;//a的节点保存结构体变量b的地址 
  b.next = &c;//b的节点保存结构体变量c的地址
  c.next = &d;//c的节点保存结构体变量d的地址
  d.next = 'A';//给最后一个节点写个内容 用于判断节点是否已经遍历完成 

  while(head != 'A')//头指针如果没有保存最后一个节点的内容 就一直遍历 
    {
        printf("%d  ",head->score);//遍历score 
        head = head->next;//指向下一个节点 
    }       

}

//输出结果;10 20 30 40

10.动态链表 

动态链表用来节约内存,用多少创建多少,把一些不连续的内存进行合好的利用,弥补了不联系内存的浪费。

#include <stdio.h>
#include <malloc.h>

struct student
{
	int data;//数据 
	struct student *next;//节点 
	
 } ;
 
 
 struct student *Chuangjian()//创建节点函数 
 {
 	int a;//用于给数据赋值 
 	struct student *head,*last,*new;//定义头指针,尾指针,和创建新节点的指针 
 	head = (struct student *)malloc(sizeof(struct student));//头指针指向第一个节点 
 	last = head;//尾指针始终指向新的节点 
 	
 	scanf("%d",&a);//给数据赋值 
 	
 	while(a != -1)//用于判断是否创建新的节点 ==-1是不创建新的节点 
 	{
 		new = (struct student*)malloc(sizeof(struct student));//创建新的节点 
 		new ->data = a;//把刚刚的数据赋给data 
 		last -> next = new;//第一个节点的next指向下一个节点的地址 
 		last = new;//last始终指向新的节点,用作于判断是否遍历完成 
 		
 		scanf("%d",&a); 
	 }
	 
	 last -> next = NULL;//用作于判断是否遍历完成
	 
 	return head;//返回头指针 
 }
 
 void print(struct student *p)//接收头指针 
 {
 	struct student *head;//创建一个指针用于接收头指针 
 	
 	head = p ->next; //指向下一个地址,因为第一个地址只有next,没有数据 
 	
 	if (head == NULL )
 	{
 		printf("你还没有创建节点\n");
	 }
 	
 	while(head != NULL)
 	{
 		printf("%d ",head->data);
 		head = head->next;
 		
	 }
 	
 	
 }
 
 
 
 
 void main()
 {
 	struct student *head =Chuangjian();//接收头指针 
	print(head); 
	 
 }
 void print(struct student *p)//接收头指针 
 {
 	struct student *head;//创建一个指针用于接收头指针 
 	
 	head = p ->next;
 	
 	if (head == NULL )
 	{
 		printf("你还没有创建节点\n");
	 }
 	
 	while(head != NULL)
 	{
 		printf("%d ",head->data);
 		head = head->next;
 		
	 }
 	
 	
 }
 
 
 
 
 void main()
 {
 	struct student *head =Chuangjian();//接收头指针 
	print(head);  //遍历头指针 
 }

四、关键字的用法

1.break

break用于打断循环,也就是执行到break,直接跳出循环,可以打断for,switch,while,do..while。

break可以跳出for,但是如果用一个以上的for,则是打断离它最近的for

#include <stdio.h>

void main()
{
    int a =0;
    int sum = 0;
    int i;

    for(i =0 ;i < 11;++i)
    {
        if(i ==11) //如果i==11 就跳出循环 
        {
           break;

        }
        
        sum =sum +i;
    }

	printf("%d",sum); 
}

//输出结果;55
#include <stdio.h>

void main()
{
    int a =0;
    int sum = 0;
    int i,j;

    for(i =1 ;i < 2;++i)
    {
    	 
        for(j = 0;j < 11;++j) 
    	{
			 
           break;//只打破离break最近的for 
		   sum =sum +j;

	   }
 
 		sum = sum +i;
  }	

	printf("%d ",sum); 
}

输出结果:1

用于 switch的时候

#include <stdio.h>

void main()
{
    int a;
    
    printf("请输入你的楼层号:\n");
	scanf("%d",&a);
	
	switch(a)
	{
		case -1:
			printf("您已经到达-1层");//如果没有break,你输入1,后面所有楼层都会输出 
			break;
		case 1:
			printf("您已经到达1层");
			break;
		case 2:
			printf("您已经到达2层");
			break;
		case 3:
			printf("您已经到达3层");
			break;
		default :
		    printf("还未盖起来");
			break;
			 	
	 } 
    


}

 用于while&&do..while的时候

#include <stdio.h>

void main()
{
    int a = 2;
    
	while(a ) 
	{
	
	printf("hallo world\n");
	break;//本来可以执行两次hallo world,第一次输出后 就被打破了 所以就循环了一次 
	
	--a;
	}

}

输出结果:hallo world
#include <stdio.h>

void main()
{
    int a = 2;
    
	do//do..while默认就执行一次 
	{
		printf("Hallo world\n");	
		break; 
		
	} while(a--);

}

2.continue 

continue用于跳出本次循环,不是退出循环,而是只跳出本次的循环

#include <stdio.h>

void main()
{
	int i = 1;
	 
	 for (i = 1; i < 10; i++)
	 {
		  if (i == 5)
	  {
		   continue;//当i = 5的时候跳出本次循环,不执行 
	  }
		  printf("%d ", i);
	 }
	
	 
}



输出结果:1 2 3 4 6 7 8 9

3.static的用法

static就两个作用:

1.修饰全局变量,如果static修饰了全局变量,那只能在本工程使用,其他工程就不能调用了,

2.修饰局部变量,它是存储在静态存储区的,用static修饰过后,就是函数执行结束,值依然在,如果static未被赋值,默认值就是 0;

3.static修饰函数,函数也只能在本工程使用,其他工程不可调用。

#include <stdio.h>

void main()
{

	int a ; 
	a = f();
	
	printf("%d\n",a);//a = 1 
	
	a = f();//第二次调用这个函数,i的值并没有消失 ,因为通过static修饰过后,i存在了静态存储器 
	
	printf("%d\n",a);//a = 2 

	a = f();
	
	printf("%d\n",a);//a = 3
	
	
 }
 
 int  f(int a)
 {
 	static int i  = 0;

	i++;
	
	return i;
  } 

输出结果:1 2 3 

4.extern

extern 用来扩宽作用域的,可以通过extern来使用全局变量,也可以用于访问另一个工程。

#include <stdio.h>
 
// 函数外定义变量 x 和 y
int x;
int y;
int addtwonum()
{
    // 函数内声明变量 x 和 y 为外部变量
    extern int x;
    extern int y;//本来用不到全局变量x,y,通过extern扩宽了作用域,使得能访问外部变量了 
    x = 1;
    y = 2;
    
    return x+y;
}
 
int main()
{
    int result;
    // 调用函数 addtwonum
    result = addtwonum();
    
    printf("result 为: %d",result);
    return 0;
}


输出结果:3

5.malloc

malloc可以手动分配动态内存,避免了内存的浪费,可以以用malloc手动分配地址。

#include <stdio.h>
#include <malloc.h>

void main()
{
	int *p;
	int i;
	p = (int *)malloc(8);//给指针p分配了8g字节,也就是两个int 
	
	*(p+0) = 20;//给第一个4个字节赋值 
	*(p+1) = 30;//给第二个4个字节赋值  因为malloc分配的地址是连续的 
	
	printf("%d",*(p+1));
    printf("%d",*(p));
	  
}

输出结果:30 20

6.typedef

C语言允许为一个数据类型起一个新的别名,就像给人起“绰号”一样。起别名的目的不是为了提高程序运行效率,而是为了编码方便。

#include <stdio.h>
#include <malloc.h>

void main()
{
	typedef int a;//把int这个数据类型,改写成了a
	a b = 2; 
	
	printf("%d",b); 
	  
}

输出结果: 2

7.const 

1.对变量声明只读特性,保护变量值以防被修改

2.节省空间,避免不必要的内存分配。const修饰的变量在程序运行过程中只有一份拷贝。

#include <stdio.h>


void main()
{
	int b = 4;
	const int a = 5;//const修饰了a这个变量,所以只能读,不能被改写,const无视数据类型,int consst a = 5 ;== const int a =5; 
	//a = 10;//error
	
	//const int*p =&a;//const 修饰了*p   == int const *p =&a 
	//p = &b;   //可以继续指向地址,但是不能改写地址的内容 
	//*p = 4;  //error
	
	//int*const p =&b;
	//*p = 4; //可以改写它内容里面的值,但是不能让他重新指向地址了
    //p = &a; //error
    
    const int * const p =&b;//p不能指向其他地址,*p也不能改写内存的数值 
	
	
	  
}

五、预编译&条件编译

1.#define 无参

#define 既不是定义,也不是声明,所以是不分配内存的,#define说白了就是替换的意思。

#define 宏名 字符串

#include <stdio.h>
#define N 52

void main()
{
    int a;
	a = N; 
	
	printf("%d",a); 
	  
}

输出结果:52

2.#define 有参

带参就是跟函数一样可以代替一些操作。

#include <stdio.h>
#define N(y) ((y)*(y)) //如果不带括号结果就是160

void main()
{
    int a;
	a = 160/N(2);//为什么结果不是40,而是160?这里计算过程 160/2*2 因为没有括号是先除在乘的 
	
	printf("%d",a); 
	  
}

输出结果:40

3.#if条件编译

#include <stdio.h>
#define N 1

void main()
{
	
	#if N  //如果是真就执行下面的语句, 
	
	printf("李建华");
	
	#else //不满足真就执行下面的语句, 
	
	printf("李珍");
	
	#endif//条件编译结束的意思 没有这个if else 不成立 
	
	printf("iverson"); 
	  
}

运行结果:只要是1,李建华就会一直在

六、冒泡排序

代码如下(示例):

#include<stdio.h> 

void main()
{
	 int n[10] = { 25,35,68,79,21,13,98,7,16,62 };//定义一个大小为10的数组
	 int i, j, temp;
	 
	 for (i = 1; i <= 9; i++)//外层循环是比较的轮数,数组内有10个数,那么就应该比较10-1=9轮
	 {
	  
	  for (j = 0; j <= 9 - i; j++)//内层循环比较的是当前一轮的比较次数,例如:第一轮比较9-1=8次,第二轮比较9-2=7次
	  {
	   
	   if (n[j] > n[j + 1])//相邻两个数如果逆序,则交换位置
	   {
	    temp = n[j];
	    n[j] = n[j + 1];
	    n[j + 1] = temp;
	   
	   }
	  
	  }
	
	 }
	
	 printf("排序过后的数顺序:\n");
	 for (i = 0; i < 10; i++)
	 printf("%4d", n[i]);
	
}



版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/lijianhua003/article/details/125391667

智能推荐

C#连接OPC C#上位机链接PLC程序源码 1.该程序是通讯方式是CSharp通过OPC方式连接PLC_c#opc通信-程序员宅基地

文章浏览阅读565次。本文主要介绍如何使用C#通过OPC方式连接PLC,并提供了相应的程序和学习资料,以便读者学习和使用。OPC服务器是一种软件,可以将PLC的数据转换为标准的OPC格式,允许其他软件通过标准接口读取或控制PLC的数据。此外,本文还提供了一些学习资料,包括OPC和PLC的基础知识,C#编程语言的教程和实例代码。这些资料可以帮助读者更好地理解和应用本文介绍的程序。1.该程序是通讯方式是CSharp通过OPC方式连接PLC,用这种方式连PLC不用考虑什么种类PLC,只要OPC服务器里有的PLC都可以连。_c#opc通信

Hyper-V内的虚拟机复制粘贴_win10 hyper-v ubuntu18.04 文件拷贝-程序员宅基地

文章浏览阅读1.6w次,点赞3次,收藏10次。实践环境物理机:Windows10教育版,操作系统版本 17763.914虚拟机:Ubuntu18.04.3桌面版在Hyper-V中的刚安装好Ubuntu虚拟机之后,会发现鼠标滑动很不顺畅,也不能向虚拟机中拖拽文件或者复制内容。在VMware中,可以通过安装VMware tools来使物理机和虚拟机之间达到更好的交互。在Hyper-V中,也有这样的工具。这款工具可以完成更好的鼠标交互,我的..._win10 hyper-v ubuntu18.04 文件拷贝

java静态变量初始化多线程,持续更新中_类初始化一个静态属性 为线程池-程序员宅基地

文章浏览阅读156次。前言互联网时代,瞬息万变。一个小小的走错,就有可能落后于别人。我们没办法去预测任何行业、任何职业未来十年会怎么样,因为未来谁都不能确定。只能说只要有互联网存在,程序员依然是个高薪热门行业。只要跟随着时代的脚步,学习新的知识。程序员是不可能会消失的,或者说不可能会没钱赚的。我们经常可以听到很多人说,程序员是一个吃青春饭的行当。因为大多数人认为这是一个需要高强度脑力劳动的工种,而30岁、40岁,甚至50岁的程序员身体机能逐渐弱化,家庭琐事缠身,已经不能再进行这样高强度的工作了。那么,这样的说法是对的么?_类初始化一个静态属性 为线程池

idea 配置maven,其实不用单独下载Maven的。以及设置新项目配置,省略每次创建新项目都要配置一次Maven_安装idea后是不是不需要安装maven了?-程序员宅基地

文章浏览阅读1w次,点赞13次,收藏43次。说来也是惭愧,一直以来,在装环境的时候都会从官网下载Maven。然后再在idea里配置Maven。以为从官网下载的Maven是必须的步骤,直到今天才得知,idea有捆绑的 Maven 我们只需要搞一个配置文件就行了无需再官网下载Maven包以后再在新电脑装环境的时候,只需要下载idea ,网上找一个Maven的配置文件 放到 默认的 包下面就可以了!也省得每次创建项目都要重新配一次Maven了。如果不想每次新建项目都要重新配置Maven,一种方法就是使用默认的配置,另一种方法就是配置 .._安装idea后是不是不需要安装maven了?

奶爸奶妈必看给宝宝摄影大全-程序员宅基地

文章浏览阅读45次。家是我们一生中最重要的地方,小时候,我们在这里哭、在这里笑、在这里学习走路,在这里有我们最真实的时光,用相机把它记下吧。  很多家庭在拍摄孩子时有一个看法,认为儿童摄影团购必须是在风景秀丽的户外,即便是室内那也是像大酒店一样...

构建Docker镜像指南,含实战案例_rocker/r-base镜像-程序员宅基地

文章浏览阅读429次。Dockerfile介绍Dockerfile是构建镜像的指令文件,由一组指令组成,文件中每条指令对应linux中一条命令,在执行构建Docker镜像时,将读取Dockerfile中的指令,根据指令来操作生成指定Docker镜像。Dockerfile结构:主要由基础镜像信息、维护者信息、镜像操作指令、容器启动时执行指令。每行支持一条指令,每条指令可以携带多个参数。注释可以使用#开头。指令说明FROM 镜像 : 指定新的镜像所基于的镜像MAINTAINER 名字 : 说明新镜像的维护(制作)人,留下_rocker/r-base镜像

随便推点

毕设基于微信小程序的小区管理系统的设计ssm毕业设计_ssm基于微信小程序的公寓生活管理系统-程序员宅基地

文章浏览阅读223次。该系统将提供便捷的信息发布、物业报修、社区互动等功能,为小区居民提供更加便利、高效的服务。引言: 随着城市化进程的加速,小区管理成为一个日益重要的任务。因此,设计一个基于微信小程序的小区管理系统成为了一项具有挑战性和重要性的毕设课题。本文将介绍该小区管理系统的设计思路和功能,以期为小区提供更便捷、高效的管理手段。四、总结与展望: 通过本次毕设项目,我们实现了一个基于微信小程序的小区管理系统,为小区居民提供了更加便捷、高效的服务。通过该系统的设计与实现,能够提高小区管理水平,提供更好的居住环境和服务。_ssm基于微信小程序的公寓生活管理系统

如何正确的使用Ubuntu以及安装常用的渗透工具集.-程序员宅基地

文章浏览阅读635次。文章来源i春秋入坑Ubuntu半年多了记得一开始学的时候基本一星期重装三四次=-= 尴尬了 觉得自己差不多可以的时候 就吧Windows10干掉了 c盘装Ubuntu 专心学习. 这里主要来说一下使用Ubuntu的正确姿势Ubuntu(友帮拓、优般图、乌班图)是一个以桌面应用为主的开源GNU/Linux操作系统,Ubuntu 是基于DebianGNU/Linux,支..._ubuntu安装攻击工具包

JNI参数传递引用_jni引用byte[]-程序员宅基地

文章浏览阅读335次。需求:C++中将BYTE型数组传递给Java中,考虑到内存释放问题,未采用通过返回值进行数据传递。public class demoClass{public native boolean getData(byte[] tempData);}JNIEXPORT jboolean JNICALL Java_com_core_getData(JNIEnv *env, jobject thisObj, jbyteArray tempData){ //resultsize为s..._jni引用byte[]

三维重建工具——pclpy教程之点云分割_pclpy.pcl.pointcloud.pointxyzi转为numpy-程序员宅基地

文章浏览阅读2.1k次,点赞5次,收藏30次。本教程代码开源:GitHub 欢迎star文章目录一、平面模型分割1. 代码2. 说明3. 运行二、圆柱模型分割1. 代码2. 说明3. 运行三、欧几里得聚类提取1. 代码2. 说明3. 运行四、区域生长分割1. 代码2. 说明3. 运行五、基于最小切割的分割1. 代码2. 说明3. 运行六、使用 ProgressiveMorphologicalFilter 分割地面1. 代码2. 说明3. 运行一、平面模型分割在本教程中,我们将学习如何对一组点进行简单的平面分割,即找到支持平面模型的点云中的所有._pclpy.pcl.pointcloud.pointxyzi转为numpy

以NFS启动方式构建arm-linux仿真运行环境-程序员宅基地

文章浏览阅读141次。一 其实在 skyeye 上移植 arm-linux 并非难事,网上也有不少资料, 只是大都遗漏细节, 以致细微之处卡壳,所以本文力求详实清析, 希望能对大家有点用处。本文旨在将 arm-linux 在 skyeye 上搭建起来,并在 arm-linux 上能成功 mount NFS 为目标, 最终我们能在 arm-linux 里运行我们自己的应用程序. 二 安装 Sky..._nfs启动 arm

攻防世界 Pwn 进阶 第二页_pwn snprintf-程序员宅基地

文章浏览阅读598次,点赞2次,收藏5次。00为了形成一个体系,想将前面学过的一些东西都拉来放在一起总结总结,方便学习,方便记忆。攻防世界 Pwn 新手攻防世界 Pwn 进阶 第一页01 4-ReeHY-main-100超详细的wp1超详细的wp203 format2栈迁移的两种作用之一:栈溢出太小,进行栈迁移从而能够写入更多shellcode,进行更多操作。栈迁移一篇搞定有个陌生的函数。C 库函数 void *memcpy(void *str1, const void *str2, size_t n) 从存储区 str2 _pwn snprintf

推荐文章

热门文章

相关标签