C语言

 

  1.C语言的特点

            (1)C语言是一中面向过过程的编程语言

            (2)是一种结构化程序设计语言,特别适合大型程序的模块设计   (通过函数来实现)

            (3)允许直接访问物理地址,能进行位(bit)操作,可以直接对硬件进行操作

2.HelloWord程序

#include<stdio.h>//这个是个标准的输入输出头文件
int main()//一个主函数
{
	printf("Hello world!\n");  //输出hello world  并且要换行
	printf("中国");
	return 0;//结束。
}

/*

#:是一种预编译符号

stdio:standard input & output  标准的输出输入函数

h:header 头文件

#include<stdio.h>:C语言不提供输入输出函数,作用是引入输出输入函数

注释:解释这个代码的作用,不参与C语言的执行,编译器看不到的意思

*/

//:一行的注释

/*:注释多个行*/

/*int main():一个程序里面有且只有一个主函数(main()),必须要有主函数,但是只可以是一个主函数,主函数是程序执行的入口

语句:就是以一个;结尾就叫做一个语句

{}:叫做函数体

注意:每次修改了程序后,要运行的话,首先要编译,且没有错误,才可以运行

所有的编程必须在英文状态下敲代码,包括符号也是,必须在英文状态下*/

    总结

           1.C语言本身是不提供输入输出语句,输入输出操作是由C标准函数库中的函数实现的      <stdio.h> <math.h>等等

           2.C语言的算法可以有0个或者多个输入,但必须要有1个或者多个输出(必须要有输出)

           3. .c源文件—— 编译——.obj 目标文件 ——连接—— .exe可执行文件

 

3.基本数据类型和基本输入输出

       一.常量

                  其值不可改变的量。例如1,-1,0,0.1,1.2E10。

          1.整型常量     1,0,-1

          2.实型常量(小数)

               1).小数形式  0.1

               2).指数形式    E或者e代表以10为底的指数        12000   1.2e4

                   注意:(大小写都是一样的)e或者E之前必须有数字,且e或E后面必须是整数   E4   1.1e1.1(错误形式)

               3).进制形式

                      八进制:以0开头,由0-7组成的数。如,012

                      十六进制:(0--15)以0X或0x开头,由0-9,A-F或a-f 组成。如,0x3A

                 3.字符常量

                        普通字符(字符)单:单字符,  单引号括起来   ‘a’  ‘1’

                  

                  在ASCII中得出的规律:

                        1.记住A  和 a 的ascii码  A 65   a  97  A+32=a;

                         2.大写的字母比小写的顺序要小,十进制小 

                         3.相同大小写的字母顺序大的 十进制也大

                         4.字符和整型可以直接转换

              4.字符串: 

                          双:  双引号  “aa”  “aaa” “a”用字符数组来表示字符串

               5.转义字符:

                           什么叫转义字符  赋予其另外一种含义

                            

                        

                         空格:32

                         扩展

                                 ‘\12’  2*8^0+1*8^1     八进制对应的ASCII码值(十进制)

                                  ‘\x12’ 2*16^0+1*16^1   十六进制对应的ASCII码值(十进制)

     

                    6.符号常量:

                            用一个符号名代表一个常量  关键字(define)        编译预处理会在编译前处理好

                  格式如下

#define  PI  3.1415926
注意:习惯性用大写字母表示,且见名只义:例如PI,表示圆周率
代码:
#include<stdio.h>
#define PI 3.1415926
int main()
{
   printf("%lf",2*PI);
   return 0;
}
--------------------
输出结果是:6.2831852

             二.变量

                  可以改变的量       必须先定义,再使用   

                  它的本质:(一段连续)内存空间的别名,变量是一个符号  内存空间可以再取别名

                  变量的声明:int a      a=10;     没有分配字节   空壳子

                   变量的定义:int a=10;  分配了字节     有内容的

                   1.常变量

                           const  int a=1;

                           表示在变量存在期间它的值不会改变

                       补充:

      常变量、符号常量和常量的区别:符号常量不占用内存空间,在预编译时就全部由符号常量的值替换了,而常变量占用内存空间,只是此变量在存在期间不能重新赋值,常量是没有名字的不变量,常变量是由名字的不变量

                三.标识符

                      在程序中使用的变量名、函数名、标号等统称为标识符

                       特点:

                标识符只能是字母(A~Z,a~z)、数字(0~9)、下划线(_)组成的字符串,并且其第一个字符必须是字母或下划线

                 在标识符中,大小写敏感。A  和 a

                 尽量做到见名知义

                  关键字是不可以作为标识符的,否则乱

                  四.数据类型

                    通过存储单位(字节数)来区分数据的大小

                    不同类型的的数据在内存中占用的存储单元长度是不同的

                    数据类型的本质:

                          (1) 数据类型可理解为创建变量的模具(模子);是固定内存大小的别名

                          (2) 作用:编译器预算对象(变量)分配的内存空间大小

                      

                   

                         C语言是没有规定哪个数据类型占用多大的字节数,全是编译系统规定的

void main21()
{
	int b = 10;
	int a[10] = {1, 3, 44, 2, 3, 44, 5, 5,6, 67};
	printf("a:%d &a:%d \n", a, &a); //a &a大小一样
	printf("a+1:%d &a+1:%d \n", a+1, &a +1 ); //+1 大小不一样 
	//a &a数据类型不一样   步长不一样
	system("pause");
}

                    1.  int型       分配4个字节(32位)

                                      存储方式:用整数的二进制补码形式存放

                                      正数:二进制原码,反码,补码均为相同     负数看图知

                                                                  13                -13

                                           原码    0000 1101         1000 1101

                                           反码    0000 1101         1111 0010

                                           补码    0000 1101         1111 0011

                                      二进制转十进制

                                              0001 0101       0001 1111        从二进制转为十进制方法如下,如是八进制则将2 改为8

                                      

                                       在二进制码中,为了区分正负数,采用最高位是符号位的方法来区分,正数的符号位为0、负数的符号位为1

                     2.short(短整型)   分配2个字节,其他和int一样

                     3.long(长整形)    分配4个字节,其他和int一样

                     4.有符号和无符号:             

                                   针对的是整型和字符型

                                   有符号:有正数也有负和0 [signed] int    int  例如4个字节 -2^31--0--2^31-1

                                   无符号:只能为正和0  unsigned int   范围不一样    例如4个字节  0----2^32-1    无符号的输出控制为%u

                                   当给无符号赋值为负的时候,会出现错误的结果.         

/*Demo11(无符号的输出)*/
#include<stdio.h>
int main()
{
	unsigned int a=-1;
	printf("%u\n",a);
	return 0;
}

   

      5.char  字符型    占一个字节    如char a='c';

                      6.float   单精度浮点型,占4个字节      六位有效数字

                          系统保证在规定的有效数字之内是正确的,但超过了有效数字的范围,系统就不保证你的正确性了

                          系统只会输出小数点的后6位

                          如:12.   有个点可以理解为小数

                      7.double 双精度浮点型  占8个字节   15位有效数字

                        Sizeof是操作符.关键字,不是函数:sizeof(变量名或者是数据类型) 例如sizeof(i),sizeof(int )输出的是占用的字节数

                      double类型的输入不能使用%f进行输入,得用%lf才能正常得到a的值。

                      而在输出ddouble类型时却可以用%f,这是因为printf("%f",a);在执行时C自动将float型的参数转换成double型。

                       故double型的输入输出形式如下:

                                      double a;
                                      scanf("%lf",&a);
                                      printf("%f",a);

                     float 为单精度,有效数字为6~7   double 为双精度,有效数字为15~16 但他们在输出时,小数点后都有6位小数

 

                 五.输出

                        printf(“全部输出”);除特殊% \之类的     

                       注意:printf("格式",数据);数据是什么类型,格式就写与之对应的类型,不然会输出错误的结果

任务:输出%  输出\
代码:
/*输出百分号和反斜杠*/
#include<stdio.h>
int main()
{
	//printf("%chello world!\n",97);
	//printf("hello world!\n%c",97);
	//printf("c\n");
    printf("%q\n");//百分号类似于打印的功能,除非特殊情况下(%d,%c,%lf.....)
	printf("\q");//\类似于打印的功能,除非特殊情况下(转义字符的情况下)
	return 0;
}
-----------
输出结果  q   q
#include<stdio.h>
int main()
{
	printf("I Love China!");
	return 0;
}
------------
输出结果 I Love China!

                    1,int,short型输出  %d

代码:
/*Demo10(整型的输出)*/
#include<stdio.h>
int main()
{
	int num1;//num1是个变量,并且它是int 型变量
	num1 = 10;//这里两句语句可以用一句来表示  int num1 = 10;
	printf("%d\n",num1);
	printf("%3d\n",num1);//总共输出三列,并且靠右边,左边没有的数字用空格来表示
	printf("%-3d",num1);//总共输出三列,并且靠左边,右边没有的数字用空格来表示
	return 0;
}
--------------
输出结果
10
 10
10 

                    2. 无符号的输出  %u

#include<stdio.h>
int main()
{
	unsigned int a =-1;
	printf("%u",a);
	return 0;
}
------------------------
输出结果   4294967295  看Demo11



思考
#include<stdio.h>
int main()
{
	unsigned short a =-1;
	printf("%u",a);
	return 0;
}

                       3.short型输出   %d   如果超出该类型的数字会溢出,则会输出垃圾数字

                       4.long型输出 %ld   同上述

                       5.char 型输出   %c

                                  char 与 整型的转换     

                                  char  类型在计算时都转换成整型   再进行计算  例如  ch='A'   ch+32=65+32=97

                                   字符转换为整型  如‘5’-‘0’=5                整型转化为字符  如  5+‘0’=‘5’

/*Demo14(字符型和整型的转换)*/
#include<stdio.h>
int main()
{
	char ch='a';
	int a=65;
	printf("%c\t%d\n",ch,ch);
	printf("%c\t%d\n",a,a);
	return 0;
}
---------------
输出结果是
a    97
A    65

       字符与整型有的时候是可以通用的(范围内)

注意:当你的整型超过了字符型的范围时,就会按照你所在的地方的国家规定的编码来输出,我们国家是gbk编码(在网上看的)

                        6.字符串输出  %s

代码
/*字符串的输出*/
#include<stdio.h>
#include<string.h>
int main()
{
	char arr[10]="drererert";//利用数组来装字符串
	int a = sizeof(arr);
	int b = strlen(arr);
	printf("%s\n",arr);//字符串的输出格式
	printf("数组里面分配%d个字节\n",a);
	printf("数组里面有%d个字符\n",b);
	return 0;
}
-----------------
输出结果   
drererert
数组里面分配10个字节
数组里面有9个字符

                         7.float型输出  6位小数,6-7位有效数字

#include<stdio.h>
int main()
{
	float a;
    a=1.2345678f;//输出结果为1.234568,小数点的第七位是利用四舍五入进了一位,所以为1.234568
	printf("%f\n",a);
	return 0;
}



%m.n格式输出 -%m.n格式输出
/*float的输出*/
#include<stdio.h>
int main()
{
	float a;
  a=1.2345678f;
	printf("%f\n",a);//输出结果为1.234568,小数点的第七位是利用四舍五入进了一位,所以为1.234568
	printf("%12.7f\n",a);//m.n的格式,m是共占用多少的列,n是指小数点输出多少位,并且它是靠右边的  1.234568
	printf("%-12.7f",a);//m.n的格式,m是共占用多少的列,n是指小数点输出多少位,并且它是靠左边的1.2345678  
	return 0;
}

                  对于%c用m.n格式的用法都是 一样的   scanf(“%4s”,ch);4s表示有效字符为四个

                                                                                 printf("%ns",ch);    n表示最少输出n列(靠右)的意思,不够用空格补充

                                                                                                               若是-n则最少输出n列靠左边的,不够也用空格补充

#include<stdio.h>
int main()
{
	char ch[10];
	scanf("%4s",&ch);
	printf("%s\n",ch);
    return 0;
}
----------------
输出结果
asdasdasd
asda

                8.double型输出 6位小数,15位有效数字(有效%n数字之内保证正确,超过了不负责)  %lf  %f

#include<stdio.h>

int  main()

{

double a=1.0;

double b=3.0;

printf("%lf",a/b);

return 0;

}
-------------------
输出结果 0.333333333f



#include<stdio.h>

int  main()

{

double a=1.0;

double b=3.0;

printf("%20.17lf\n",a/b);//输出为 0.33333333333333331 ?  这就是有效数字在作怪

printf("%.17lf\n",a/b)//输出17位小数

return 0;

}
---------------------------
输出结果    

                            9.指数形式输出  %e

#include<stdio.h>

int main()

{

float a=22223.34567888f;

printf("%e",a);

return 0;

}
---------------
输出结果 :2.222335e+004

                        11.指数.小数格式输出 %g 

                           (看谁输出的字符更短就输出谁)

           %g格式 符,用来输出实数,输出格式为f格式或e格式,系统根据数据占宽度m大小,自动选择占宽度较小的某种格式输    出,%g格式符不输出小数点后无意义的零

                         12.八进制格式输出 %o  

#include<stdio.h>
int main()
{
    int a=16;
    printf("%o",a);
    return 0;
}
--------------------
输出结果   20

                          13.十六进制格式输出  %x

#include<stdio.h>
int main()
{
    int a=16;
    printf("%x",a);
    return 0;
}
-------------------
输出结果   10

          注意:x,e,g外,其他输出格式必须小写。

               六.输入

       大多数情况下都要加上&(取地址符);

              一般格式

                       scanf(格式控制%d,地址表列&a)     scanf遇到空格结束

                       scanf(格式控制n%d,地址表列&a)  若输出的数中间有空格  n若取到第一个空格之前的数,之后的数就无效

 反之,第一个空格之前的数没有达到n个,将数值全部输入

          如

int main()
{
	  
	  int a,b;
	  scanf("%3d%d",&a,&b);
	  printf("%d%d\t",a,b);
	  return 0;
}
---------------------
输入
123 45
输出结果
12345


输入
12 345 67
输出结果
1234567

                   用语句scanf( %c%c%c ,&c1,&c2,&c3)输入a└┘b└┘c时,变量c1、c2、c3的值分别为

                  └ ┘ 应该是空格
                   scanf 需要精确匹配, 因为你的匹配项目是 %c%c%c 所以答案是`a`,`└ ┘`,`b`
                   如果匹配项目是 %c %c %c 那么答案就是 a b c (注意%c中间有空格)

             格式控制那里不一样的格式,控制台就会有不一样的输入格式

              注意事项:输入数值数据时,遇到空格回车tab或者非法字符则认为该数据结束输入

scanf("%d%d%d",&a,&b,&c);
输入:用空格,或者回车,或者tab或者非法字符来结束一个变量的输入
scanf("%d,%d,%d",&a,&b,&c);
按照格式控制表列里面的格式来输入,例如是,则用,来隔开
scanf("%d%c%lf",&a,&b,&c);
输入格式为:1c3.3     输出为 1  c   3.300000
scanf("%d,%c,%lf",&a,&b,&c);
输入格式为:1,c,3.3  输出为 1  c   3.300000
scanf(“%d,%f,%c”,&a,&b,&c);
输入格式为:1,2.2,c  输出为 1  c   3.300000
scanf(“%d:%f:%c”,&a,&b,&c);
输入格式为:1:2.2:c   输出为 1  c   3.300000

               总结:scanf输入的内容  是根据scanf中双引号的格式进行输出,若格式对应不上,就会出现输出错误

               

补充:整型的格式输入,例如20170822

#include<stdio.h>
int main()
{
	int year,month,day;
	scanf("%4d%2d%2d",&year,&month,&day);//读取指定位数的数字  %4d :读取前面四个数字  20170822  读取的是2017
	printf("%4d\n%2d\n%2d\n",year,month,day);
	return 0;
}

 

                 七.运算符

      1.运算符的种类

     (1).算术运算符 

     用于各类数值运算。包括加(+)、减(-)、乘(*)、除(/)、求余(或称模运算%)、自增(++)、自减(--)共七种。

  1. +-*/混合运算  (5/3) (-5/3)= -1(vc.0)不一样的编译系统答案可能不一样,有的可能为-2 int/int 型 结果也为int 型
  2. 格式控制输出%d 之类的  ,必须和后面的变量计算的结果类型相一致,不然就会出错    printf("%d\n",5/3);
  3. 求余数(参与操作的数只能为整数)
  4. 自增 i++, ++I,前者是先让i运算,再加1,后者则先加1,在运算
  5. 自减 i--,--I; 前者是先让i运算,再减1,后者则先减1,在运算

     注:printf("%d\n",x+=x++;x++);

             pirntf函数中的表达式的结合顺序是由右向左,所以先算x++,再算x+=x++

      (2).关系运算符 

       用于比较运算。包括大于(>)、小于(<)、等于(==)、 大于等于(>=)、小于等于(<=)和不等于(!=)六种。

       关系运算符运算返回的结果的是逻辑结果.bool类型,就是一个逻辑值,即“真 1”“假 0”

       =赋值   ==  !=

      (3).逻辑运算符(返回的结果也是真,或者假这两种情况) 

       用于逻辑运算。包括与(&&)、或(||)、非(!)三种。

      四种关系一一对应:(真true 1 非0)    (假 false 0 0)

  1.      &&相当于并且的意思,||相当于或的意思
  2.      &&:两个为真则为真,其中一个为假则为假 4&&0
  3.       ||:两个为假则为假,其中一个为真则为真
  1.       !:非0为真,0为假(判断计算过程) !5
  2.      1为真,0为假(结果)
  3.      && 和 ||短路现象
  4.      && 短路   假&&  不判断后面了

     (4).位操作运算符(针对整型和字符型

     参与运算的量,按二进制(补码)位进行运算。包括位与(&)、位或(|)、位非(~)、位异或(^)、左移(<<)、右移(>>)六种。

     计算方法:1.先算出整数的补码 ( 正数:二进制原码,反码,补码均为相同)      2.操作,3.再求补码

           如         

 3&8     (先右对齐,看列)如果同一列两个都为1,才为1,否则为0

 -8&-9   补码:1001 0000 = 整型的 -16

  3|8 同一个列只要有一个为1,就是为1,其他为0

  ~3   全部取反,如果为1,则为0,为0则为1

      ~0=-1                     >>相当于除以2^n   <<相当于乘以2^n

     8^3  两个不一样则为1,否则为0

 

         (5).赋值运算符(=) 

            用于赋值运算,分为简单赋值(=)、复合算术赋值(+=,-=,*=,/=,%=)和复合位运算赋值(&=,|=,^=,>>=,<<=)三类共十一种。 

            a=3;(简单赋值)

            a=8,a^=3;  等于 a=a^3;

             a=8 a+=3; 等于 a=a+3 (a-=4) 等于a=a-4;

          (6).条件运算符 

             这是一个三目运算符,用于条件求值(表达式1?表达式2:表达式3)。 

              如果表达式1为真,则执行表达式2,否则执行表达式3

              Max=a>b?a:b;

           (7).逗号运算符 

              用于把若干表达式组合成一个表达式(,)。

               A=(3,4),这是取最后的一个数A的值为4

              A=3,4; 这里的值是A=3,以为逗号的优先级最低,比赋值还低

           (8).指针运算符 

              用于取内容(*)和取地址(&)二种运算。 

            (9).求字节数运算符 

                    用于计算数据类型所占的字节数(sizeof)。是关键字,运算符,但不是函数

 

    2.优先级(不同的计算顺序)

         总结:算数运算符>关系运算符>逻辑运算符>条件运算符>赋值运算符>逗号运算符

          在逻辑运算中:!>&&>||,其值!优先级是比较大的

          

          

        3.运算中自动转换

(1)float 和 double 运算,会自动先转换成double 再运算

(2)int 与 float double运算,会自动先转换成double 再运算

(3)字符char与int ,先让字符char转换成int 型 (ASCII码)int和char 是可以随便直接转换的,前提是在规定的范围内,最后实在sacII表的范围内

(4)字符char与 float double ,先让字符char转换成int 型 (ASCII码)

总结:系统保证最大的精确度,谁是最大的精确度 (double)

注意:是个小数如果不定义成l.0f,那么系统就自动默认为double了,而不管你前面是什么, float a= 1.0  ;是把double1.0赋值给float  (有的时候精确度会受到影响,最好是  float  a = 1.0f)

     4.运算中强制转换

用(数据类型)变量

(int)(12.0/6.0) 输出的结果为2(int)2.9,输出为2,与四舍五入没关系

(int)12.0/6.0

注意:强制转换是有要求的:double 8个字节 int 4个字节 转换的时候不要超过了范围

printf("%lf\n",444444444444.0);//强制转换是有范围的

printf("%lf\n",(int)i/j);//i现在等于多少,且是什么类型?

补充:i还是double类型,且其值没有改变,其性质没有改变,也就是说强制类型转换只不过是一个临时的值,赋值完之后就不存在了

      5.math.h头文件

      int  abs(int i);针对的是int类型 求取绝对值的函数,除了这里用可以用int 其他函数最好用double,以免出错

      fabs(d):这个是针对double,float类型

       log(double x);   //返回以e为底的对数  ln(e)=1  log e (e)

      double log10(double x)   log10 和数学一样                     double pow(double x,double y)        x的y次方的意思

      double sqrt(double x)       //开平方                                   double floor(double x);                     //返回不大于x的最大整数

      double ceil(double x);   //返回不小于x的最小整数            double sin(double x);                       //输入的是弧度制

       弧度公式 

      double cos(double y);                               printf("%lf\n",sin(PI/6));//30度要换算成弧度制,PI/6;

      double tan(double z);

      double asin (double x);    

      double acos (double x);   

      double atan (double x); ,

 

   6.putchar字符常量 整型常量   字符变量,整型变量)(在控制台上输出)和 printf 对比   

       如    char a;    putchar(a);

   7.getchar() 和scanf对比

        总结:除了写法有些不一样,其他(控制台输入)好像没什么不一样了,但输入时,getchar  scanf  都是不能有空格,不需紧邻着写,写完全部在enter  getchar输入的是一个字符   

        注意:putchar()括号 可以有东西,没有换行的功能,a = getchar()是没有东西的

    8.puts (放东西)  在控制台上输出   参数 -->变量

    9.gets (放东西)  在控制台上输入   参数 -->变量     遇到回车键才结束输入

#include<stdio.h>
int main()
{
    char arr1[]="I love you!",arr2[20];
    gets(arr2);//在控制台上输入
    puts(arr1);//控制台上输出
    return 0;
}
--------------------
输出结果
I am chinese
I love you!

补充:字符串在C语言中是用数组来存的,以后我们会学到的

总结:

               不同于getchar,gets()括号里面是要放变量(数组)的,puts有自带的换行的功能。Scanf和gets()是有不一样的,当用scanf时,在控制台输入时,输入空格,tab,enter键意味着就是结束输入,而gets是遇到enter键则会结束

                 在键盘中输入字符,输出用%c进行输出,则输入过程中不能中间不能有空格,否则最后一个读不到数据

 若输出用%d进行输出,则输入可以有空格,可以没有空格

 

               八.选择结构   顺序结构    循环结构

                1.选择结构   if  ....else.....   

                                    switch(表达式)   ....

                                           case  ...break;(代表case中的语句中止) 

                                            default  break; (默认输出)

                   注意 

                           if语句else(嵌套)的匹配规则 :else总是与其前面最近的尚未配对的if匹配

                           switch(表达式)中的表达式只能为整型或字符串

                           continue;终止本次循环               break;终止所在范围整个循环

                           continue和break都可以用在循环中,一般和if搭配,如果if不在循环范围中,就不可以和if搭配

                   2. 循环结构   

                             while(表达式)  {  }            do {  } while(表达式)

                             While 的判断次数比执行次数多一次。

                             do  while 执行和判断次数一样多

                              for(表达式1;表达式2;表达式3)

                              for(循环变量赋初值;循环条件;循环变量增值,减值)

            for(表达式1;表达式2;表达式3)

    表达式1

  • 一般设置初始条件 for(i=1;i<=100;i++)
  • 可以有0个或者多个for(;i<=100;i++) for(i=1,j=1,i<=100;i++)(两者之间用逗号隔开)
  • 只执行一次

    表达式2

  • 循环条件表达式,可以一个,可以0个,
  • 0个是表示条件为真for(i=1;;i++),一直循环下去

      表达式3

  • 一般为循环变量的增,减
  • 可以为其他语句
  • 可以0个语句或者多个语句
  • 执行完循环体后,才执行

           缓存问题    清除缓存   fflush(stdin)

 

       九.数组

          1.什么是数组(篮子)

           之前我们学习了简单的数据类型(整型,字符型,小数型),例如输入一个double数据(scanf(”%lf”,&x)),如果你想输入一个班上所有学生的成绩,该怎么办?

          我们可以利用数组。double score[60]={56,67,77.5,0,}; score[0] score[59]

           2.数组的分类

            一维数组:书上的一行字

            二维数组:书上的第一行第二列所在的字

            三维数组:书上第一页第二行第三列

            3.特性

  • 同一种数据类型的元素放在一个集合里面(一张成绩表)。
  • 数组是一组有序的集合(班上的学号)
  • 数组的下标第一个为0
  • 数组引用时切记不能超过了数组的大小

   

            一.整型和实型的一维数组

             1.定义   //int a=10;

              数据类型名 数组名[常量表达式]

                    Int arr1[5] ;float arr2[5];

                     数组里面共有5个元素,分别为arr1[0] ,arr1[1] ……arr1[4]

                     注意:常量表达式不能包括变量int arr1[n],不允许动态定义数组大小

                     如果在被调用函数中,可以int arr[n](了解)

                      但是static int arr[n]是不可以的(了解)

              2字节的计算 

                       int arr1[5];共20个字节   sizeof(arr1)

               3.一维数组能做什么?

                       一维数组能用来存同种数据类型的一行或者一列元素。

               4怎么用数组

                     (1)初始化Demo1

  • Int arr1[5]={3,4,1,4,7};int a; a=4;
  • Int arr1[]={3,4,1,4,7};
  • int arr1[7]={1,2,3,4,5,6};
  • int arr[4]={1,2,3,4,5}; 错的

                

  • Int arr1[5]={1,2};

                

                 结论:未初始化列表赋值为0

               5.引用数组的元素

                   数组名[下标] 下标的最大值为数组的大小-1

                   Int arr1[5];

                   里面共有5个元素,分别为arr1[0] ,arr1[1] ……arr1[4]

  •             Printf(“%d”,arr[4]);
//数组的输入	
    int a[10];
	scanf("%d",a);
	printf("%d\n",a[0]);
	int a[2],i;
	for(i=0;i<2;i++)
	scanf("%d",&a[i]);
	printf("%d",a[0]);

                6.数组和地址的关系

                       C语言规定数组名代表数组里头第一个元素的地址

                7.数组的内存分析

                       一整块相连接的内存配  有顺序的

                   

                二.整型和实型的二维数组(矩阵)

                     1.二维数组是什么?

                      矩阵:行和列组成

                     2.二维数组怎么用?

                    (1)定义二维数组

                             数据类型名 数组名[行 常量表达式][列 长常量表达式] int arr[10]

                            Int arr1[3][4];行的最大引用为 2,列的最大引用为3

                           

                        (2)二维数组的初始化

                             Int arr1[3][4]={{1,2,3,4},{5,6,7,8},{9,10,11,12}};

                             Int arr1[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};

                             Int arr1[][4]={1,2,3,4,5,6,7,8,9,10,11,12};//必须写列

                             Int arr1[3][4]={{1},{5,6},{9}};//没有初始化列表的数值型默认为0

                              Int arr1[3][4]={{1},{5,6} };

                              记住两点:列规定了多少,不能超过,总共多少个元素,表里也不能超过

                              可以少,不能多

                 字符的一维和二维数组

                               初始化:没有初始化的列系统默认为’\0’,数值型不写,默认为0

                             

                                没有赋值的列则用’\0’来补充,’\0’是个空字符

                字符数组来表示字符串

                          1.一维的字符串

                                char str[12]={“I love you\0\0”};

                               char str[12]=”I love you”;

                                字符串有个结束标志’\0’,你不写系统会加上去,你要留出空间

                               (1)定义 

                                    char  str[8];

                               (2)初始化

                                      char ch[10]={“I love you”};

                                      char str[11]={"i love you\0"};

                                      char str1[]={"i love you"};结束标志,如果你不写,系统默认的加上去

                                      printf("%d\n",sizeof(str));//10

                                      printf("%d\n",strlen(str));//11

                                     printf("%d\n",sizeof(str1));//11

                                      printf("%d\n",strlen(str1));//10

                                    sizeof  strlen  的区别

                                        sizeof是计算分配的字节,strlen计算是实际字符(其中不包括’\0’)

                                        因为字符串数组系统会隐藏一个结束符’\0’,你也可以自己加上,不加则系统自己帮你加上,但你要留出位置

                                        Printf(“I love you \0 I love china”);只能打印 I love you 因为有结束标志

                                  (3)引用  

                printf(“%s”,str);是用数组名字,数组名字代表着一个首元素的地址,字符串只有有地址就可以输出,直到结束才停止

                Printf(“%c”,str[1]);

                      2.字符串的二维数组

                           定义:char ch[2][20];

                          初始化:char ch[2][20]={{"i love you"},{"i love china"}};

                          引用:printf("%s\n",ch[1]);//输出第二行的字符串

                         字符型数组(包括字符数组和字符串数组)的输入和输出

                         %c一个一个字符输入输出,%s按照字符串来输入输出

输出:Demo9
Char ch[10]={“ I love you”};
printf(“%s”,ch)
char ch[2][20]={{"i love you"},{"i love china"}};
printf(“%s\n”,ch[0]);
输入
Char ch[10];
Scanf(“%s”,ch);
gets(ch);//两者区别  ,前者为遇到空格则为结束,后者则通过enter键结束
Char ch[13],ch1[14];
Scanf(“%s%s”,ch,ch1);//输入时用空格隔开
char ch[2][15];
scanf("%s",ch[0]);

                         3. 字符串的头文件<string.h>的使用

                             1.Strcat

                                 Strcat(str1,str2)//连接两个字符串,把str2连接到str1的后面

                                 Strcat和strcpy都得注意第一个字符串的空间要足够大

                             2.Strcpy

                               不能用=赋值

                     strcpy(str1,str2) //把str2复制给str1

#include<stdio.h>
#include<string.h>
int main()
{
	char a[]={"assdsad"},b[]={"123"};  
	 printf("%s",strcpy(a,b));
	 return 0;
}
------------------
输出的结果
123

                    strncpy(str1,str2,3); //把str2的前3个字符复制给str1。意思是将str2前3个字符用来代替str1三个字符然后将str1输出   

#include<stdio.h>
#include<string.h>
int main()
{
	
	char a[]={"assdsad"},b[]={"123"};  
	 printf("%s",strncpy(a,b,3));
	 return 0;
------------------
输出的结果
123dsad


char a[]={"assdsad"},b[]={"1234567"};  
printf("%s\n",strncpy(a+2,b,5));
printf("%s",a);

------------------
输出的结果  a从第二个开始进行输出
12345
as12345

}

                              strcpy(str2+2,str1+5));从str1的第六个元素后的复制到str2的第三个位置那里去,输入的数取决于str1后面有多少位,str2就从第三位开始输出多少位

#include<stdio.h>
#include<string.h>
int main()
{
	
	 char a[]={"assdsad"},b[]={"1234567"};  
	 printf("%s\n",strcpy(a+2,b+5));
	 printf("%s",a);
}
------------------
输出的结果
67
as67

                            3.Strcmp

                                   Strcmp(str1,str2)//比较方法,一个一个字符比较大小

                                   结果:1(前者大),-1(后者大),0(相等)

                            4.Strlen

                                   Strlen(str1)//不包括结束标识符    显示结束标志前的字符

                                   统计字符的大小(不包括’\0’)

                             5.Strlwr(把字符转换成小写)

                             6.Strupr(把字符转换成大写)

 

 

 

               十.函数

             1.  模块化设计

  • 就是让每个函数负责不一样的功能,最后利用main函数来调用各种函数,从而实现各种功能
  • 一个源程序文件是由一个或者多个程序模块组成,每个模块负责一个功能
  • C程序总是从main函数开始执行的,main函数调用其他函数,系统调用main函数
  • 函数之间不可以嵌套定义,但可以嵌套调用,但不能调用main

 

               2.函数调用的过程分析(只能是实参传递给形参,不能反过来,实参形参时通过值传递)

                  实际参数(实参):调用时的参数

                  形式参数(形参):函数定义时的参数

                3.函数的定义-(需要实现功能

                   返回值的类型名/void  函数名(数据类型名 参数1,……(或者里面没有参数)))

                           {

                                 函数体,你要实现的功能

                                 Return (需要的值) /或者这里什么都不写(void)

                              }

 

                   自定义函数的好处:可以让主函数分配少量的内存,当自定义函数结束后,就会释放内存,给其他的资源用

                 4.函数的声明(和定义的书写格式区别)

                      返回值的类型名/void  函数名(数据类型名[谢茂茂1]  参数1,……(或者里面没有参数)));

  •                函数声明和定义简直一模一样,声明多加了一个(分号),写程序的时候,可以复制
  •                声明一般写在main函数里面的第一句话,定义写在main函数外面
  •                函数声明位置应该在函数调用的位置前面

 

                  补充:函数声明和函数定义的位置问题?

                5.声明的位置:

                        第一种:在main函数里面的开头

                        第二种:在main函数之前

                         第一种要么函数声明在函数定义之前出现

                         第二种要么不要声明,但定义必须在调用之前出现,就是在主函数之前定义

               6.函数的调用(怎么使用定义函数)

                        函数名(参数1,……(或者里面没有参数)));

                       库函数<math.h> int abs(int n);                        自定义函数  int get_sum(int n);

                      有参数的函数 int get_sum(int n);                    无参数的函数 void print();

                     有返回值的函数 int get_sum(int n);                 无返回值的函数 void   print();

 

 

                7.值传递:只可以是实参传递到形参(值传递,单向传递),可以称之为“虚实结合”,形参的值改变不会影响实参值的改变 test2.c

#include<stdio.h>
int main()
{
	int fun(int m);
	int num=10;
	printf("调用前num的值%d\n",num);
	fun(num);
	printf("函数调用完后返回来的值%d\n",fun(num));
	printf("调用完后num的值%d\n",num);
	return 0;
}
int fun(int m)//m 和 num是不一样的地址的,重新分配了内存给m
{
	m=m+10;
	return m;
}
------------------
输出的结果
调用前num的值10
函数调用完后返回来的值20
调用完后num的值10

                     要求:实参形参的类型一般要相同,如果不同, 函数类型决定返回值类型,要求返回的值的类型决定自定义函数返回的值类型,其中int char 可以直接转换,其他的则通过强行转换的规则

实参和形参的参数个数一定要相同 

一个函数一个或者多个语句

               8.函数的嵌套 

                     函数的嵌套调用(有的)

                      当有多个嵌套时,是从最里面一次往外进行的

补充:

  • 声明int()那里可以不写参数名字 例如 int max(int x,int y);  int max(int ,int )
  • main函数里面出现的变量名字,在自定义当中也可以出现,他们所占用的地址是不一样的
  • 函数名和变量名字一样怎么办?(这是不允许的)
#include<stdio.h>
int main()
{
	int max(int,int);
	void print();
	int a,b,c,max1;
	scanf("%d%d%d",&a,&b,&c);//分别1,2,3
	max1=max(max(a,b),c);//嵌套调用,第一次调用max(a,b),然后调用得到的max和c
	printf("%d\t",max1);
	//print();//C语言不允许嵌套定义
	return 0;
}
int max(int a,int b)
{
	if(a>b)
		return a;
	else 
		return b;
	void print()
	{
		printf("haha");
	}
}
---------------
输出结果
1 2 3
3

              9.函数的递归调用 Demo6

                 递归调用:是某个函数调用自己或者是调用其他函数后再次调用自己的      主函数可以调用自己

                 例子:搬砖的例子

                          递归调用的代码简洁,但是效率不高。(消耗内存)

                          怎么写递归调用的代码:

                      (1).找到上层与下层之间的规律

                      (2).找到跳出循环的一个点(终结点)

include<stdio.h>
int main()
{
	int fac(int n);//5!  和  4!  有什么关系  4!*5=5! 3!*4=4!1! 0!=1
	int n;
	scanf("%d",&n);//n=5
	printf("%d\n",fac(n));
	return 0;
}
int fac(int n)
{
	if(n==1||n==0)
		return 1;
	else
		return fac(n-1)*n;
}

              10.一维数组作为函数的调用(数组名做实际参数

  • 数组元素做函数实参时,传递的是数组元素的值
  • 数组名做函数实参时,传递的是数组首元素的地址(会导致形参数组改变后,实参的数组也会跟着一起改变,为什么?共用一个存储单元,或者说地址)
  • Int paixu(int a[10]);可以写 int paixu(int a[]);(因为C语言数组只要求知道地址,而不需要实际大小)

  注:输入结束标识可以用scanf("%d")!=EOF或ctrl+c结束

               11.二维数组作为函数的调用 Demo8

                    形参可以用 int arr[3][4],

                    也可以用  int arr[][4],第一维可以省略,但第二维不可以省略

#include<stdio.h>
int main()
{
	void test(int a[][3]);
	int arr[2][3],i,j;//这里有i,j
	for(i=0;i<2;i++)
		for(j=0;j<3;j++)
	scanf("%d",&arr[i][j]);
	test(arr);//调用
	for(i=0;i<2;i++)//输出实参的数绿
		for(j=0;j<3;j++)
			printf("%d\t",arr[i][j]);
}
void test(int a[][3])
{
	int i,j;//这里有i,j 问是否会因为变量重名而出问题呢?  不会  。局部变量,随函数结束而释放内存
	for(i=0;i<2;i++)
		for(j=0;j<3;j++)
			a[i][j]=a[i][j]+100;
}

 

             十一.局部变量和全局变量

                 变量存储方式和生命期

 

                       1.按变量的作用域的范围不一样,分了全局变量局部变量(相对的)

                       2.全局变量

                               变量在(包括自定义函数和main函数)外定义/声明   范围:本文件

#include<stdio.h>
int num1=10;//num1为全局变量,定义在主函数外的变量
int main()
{	
	printf("%d\n",num1);
	return 0;
}

                      3.局部变量

                              函数内定义的(包括形参) 范围:所在函数内

#include<stdio.h>
int main()
{
	void print();
	int num1=10;//局部变量,范围是main 函数内
	print();
	return 0;
}
void print()
{
	
	int a=30;//局部变量,范围是print函数内
	printf("%d\n",a);
	//printf("%d\n",num1);
}

                       4.全局变量和局部变量同名,(在局部所在范围内)全局则被屏蔽(以局部为准)

                            局部变量和局部变量同名(不影响) 若是变量同名相同,则输出与输出语句距离近的变量

#include<stdio.h>
int num1=10,num2=20;//全局变量
int main()
{
	int num1=30;//局部变量
	printf("num1=%d\nnum2=%d\n",num1,num2);
	return 0;
}
--------------------
输出的结果
num1=30
num2=20

                       5.一般规定:全局变量首字母大写

                       6.静态存储:运行期间由系统分配的固定的存储空间 (全局变量,static变量)

                          动态存储:运行期间根据需要进行动态分配存储空间,用完之后释放这些空间  (形参和auto)

                      7.存储类别:auto  static  register extern

                           7.1 auto(自动变量)(在局部内使用)

                             函数调用完结束则释放内存(不写为默认auto)

#include<stdio.h>
int main()
{
	void print(int );
	int num1=10,i;
	for(i=0;i<5;i++)
	print(num1);
	return 0;
}
void print(int x)
{
	auto int num2=20;//执行了5次
	num2++;
	printf("num2=%d\n",num2);
}

                               7.2 Static(静态局部变量)

#include<stdio.h>
int main()
{
	void print();
	int i;
	for(i=0;i<5;i++)
	print();
	return 0;
}
void print()
{  
	int static num2;//这句话只有第一次调用时执行了一次  下次执行该方法,则不执行第一句
	num2++;
	printf("num2=%d\n",num2);
}

                                函数调用结束后不释放内存,保留值

                               只赋一次值,赋初值的语句只调用一次

                              不赋值的话,系统根据不一样的类型,而默认赋值,数值型0,字符型为’\0

                             7.3 Register(寄存器变量)

#include<stdio.h>
int main()
{
	void print();
	print();
	return 0;
}
void print()
{
	register int num1=1,i=0;
	for(i=0;i<1000;i++)
	{
		num1++;
	}
	printf("%d",num1);
		
}

局部变量使用频繁,可以用regist,意思是把变量放在CPU中的寄存器中,运算时可以更快的取到这个值,而不用去内存中取值

       网上解释

一般情况下,变量存放在内存中,当程序中用到哪个值时,将其从内存中取出送到CPU。对于频繁使用的变量,如for循环操作,为了提高效率,可以请求编译器将这个变量保存在CPU的寄存器中,即寄存器变量,从而加快程序的运行。不过现在的编译器,优化性较强,所以不必用register声明变量。

                        7.4 extern(外部(全局)的变量

                        引用范围到哪里的意思(跨文件使用)     vc6.0在project里add 文件把 Demo1.c 加入

 

Demo1.c
#include<stdio.h>
extern int B=100;


Demo2.c
#include<stdio.h>
extern B;//把它的范围引到这里来
int main()
{
	printf("B=%d\n",B);
	return 0;
}

--------
输出的结果
B=100;

     extern只能用来声明已定义的变量,不能用于变量的定义。

声明包括定义,但不是所有的声明都是定义。关于声明和定义的简单区分方法可以用:建立存储空间的声明称为定义性声明,把不建立存储空间的声明称引用性声明。

int a;        //定义性声明,既是声明,又是定义。为变量a开辟存储空间

extern int a;  //只是声明,不是定义,不为变量a开辟存储空间

 

                          8.Static(静态外部变量)(本文件范围)

#include<stdio.h>
 static int num1=10;//这里不写,就是默认extern
/*int main()
{
	printf("num1=%d\n",num1);
	return 0;
}*/


#include<stdio.h>//stdio.h在系统目录中
extern num1;
int main()
{	
	printf("num1=%d\n",num1);
	return 0;
}

                        (不写为默认extern)

                 变量声明和定义的补充:

           1.定义包括了声明

#include<stdio.h>
extern A;//声明
int main()
{
	
	printf("A=%d\n",A);
	return 0;
}
int A=10;//定义

           1.声明不占用内存,定义变量,系统才会分配内存

          2.声明类似于告诉编译器程序中有这么一个变量名字,预定了一个名字而已(虚的),而定义却是真正的拥有的(实的)(平常几乎可以不考虑这个问题)

             补充:#include<stdio.h >和#include””的区别

              作用:把文件包进来

             #include< >编译器从系统路径开始寻找,用于系统的头文件,头文件也可以用””,当使用“”时,编译器首先从用户目录查找,没有找到再去系统目录中查找

              #include””从用户路径中开始寻找,一般用于把自己编写的文件包括进来

Demo7a.c
#include<stdio.h>
static int a=1;



Demo7b.c  //调用Demo7a,c中的a的值
#include<stdio.h>
#include "Demo7a.c"
int main(){
   printf("%d",a);

}
--------------
输出的结果
1

 

      存储和生命周期的总结:

             函数

                   1.内部函数(范围只在本文件中)

                      函数定义时,加上一个static  例如:static void print() {printf(“哈哈”);}    只能在内部调用,不能外部调用

Demo1.c
static void print()
{
	printf("*****\n");
}


Demo2.c    //vc6.0在project里add 文件把 Demo1.c 加入,否则访问不到print()方法
#include<stdio.h>
extern void print();//试图引进外部函数
int main()
{
	print();
	return 0;
}

                      2.外部函数(可以被外部文件引用)

                              函数定义时,加上一个extern(或者不写)  例如:extern void print() {printf(“哈哈”);}

Demo1.c
void print()
{
	printf("hello world\n");
}



Demo2.c           //vc6.0在project里add 文件把 Demo1.c 加入,否则访问不到print()方法
#include<stdio.h>
extern void print();  //  引进这个函数:extern 函数声明 
int main()
{
	print();
	return 0;
}

          总结:如果变量和函数前面没有写东西的话代表的就是extern (前提是全局变量,函数)

         

         十二.指针

                    1.指针操作效率高,通过地址来操作(间接操作),直接按变量名来访问(直接访问)

                               指针:就是地址。区别地址和内容

                    2.&取地址

                       *指针指向的变量(取内容)

                   2.指针——>地址,指针指向该变量单元

                  3.存储单元的地址 和存储单元的内容

                  4.一个变量的地址叫做该变量的指针

                  5.指针变量  :存指针(地址)的变量

                      指针是个地址,存放地址的变量叫做指针变量

                  6.指针类型 int *; int *p;float *q;

                         Int a;a只能放整型的,int *p p指针变量只能指向int型数据

                  7.指针的定义

                         类型名 *指针变量名   如 int *p;

                  8.指针入门

#include<stdio.h>
int main()
{
	/* int num1,num2;//定义了两个整型
	int *p,*q;//定义了两个指向整型变量的指针变量 *///快捷键 ctrl + shift +Q 可以跨行注释,ctrl +Q 本行注释
	int num1,num2,*p,*q;
	num1=10;//内容是10
	num2=20;//内容是20
	p=&num1;//把num1的地址给p,p指向num1
	q=&num2;//把num1的地址给q,q指向num1
	printf("内存中的地址%d\n",&num1);
	printf("num1=%d\n",*p);
	printf("内存中的地址%d\n",&num2);
	printf("num1=%d\n",*q);
	//&num2-&num1==4? 因为int 类型所占字节是4
	return 0;
}

                       Int 有四个字节,一般输出地址,则指向第一个字节的地址

                        int num1,num2,*p,*q;基类型一样的话,可以写在一起

                        区别:int *p;//定义一个指向整型的指针变量p

                       *p//取指针变量p指向的变量中的内容,

             9.一份地址一个字节 //

                 求最大值    a,b的地址中的值没有变化,所以没有变化

#include<stdio.h>
int main()
{
	int *p1,*p2,*p,a,b;
	scanf("%d%d",&a,&b);
	p1=&a;//p1用来存变量a的地址  p1指向a
	p2=&b;//p2用来存变量a的地址  p2指向b
	if(a<b)//a=3,b=4;
	{
		p=p1;
		p1=p2;
		p2=p;
	}
	printf("a=%d,b=%d\n",a,b);
	printf("max=%d,min=%d\n",*p1,*p2);
	return 0;

}
--------------------
输出的结果
3  4
a=3,b=4
max=4,min=3

             10.指针做函数参数

                     指针做函数参数的书写格式:void swap(int *p1,int *p2);//关于指针函数声明  

                    传地址   (形参和实参的地址一样,共用一个内存)    & 取地址      *取该地址上变量的值

a.b的值都会发生改变
#include<stdio.h>
int main()
{
	void swap(int *p1,int *p2);//关于指针函数声明
	int a,b;
	int *point1,*point2;
	scanf("%d%d",&a,&b);//3, 4
	point1=&a;//point1存变量a 的地址
	point2=&b;
	if(a<b)
  swap(point1,point2);//函数实参和形参传递(值传递)单向,形参改变,实参不受影响(数组例外的,数组传递的是地址(引用))
	printf("max=%d,min=%d\n",a,b);//4 3
	return 0;
}
void swap(int *p1,int *p2)
{
	int temp;
	temp=*p1;
	*p1=*p2;
	*p2=temp;
}

             11.指针和一维数组数组

                      共同点,跟地址有关系

                      数组的地址:连在一起的地址  int arr[5]       突破口:数组名字代表着该数组的第一个元素的地址

            12.地址的表示:

                       Arr:第一元素的地址 &arr[0]                            Arr+1:第二个元素的地址 &arr[1]

                      P=&arr[0]      第一元素的地址 &arr[0]             P+1: 第二个元素的地址 &arr[1]

#include<stdio.h>//学会类比
int main()
{
	int arr[5]={1,2},*p,i;
	//int *p=arr;
	//p=arr;
	p=&arr[0];// 第一元素的地址
	for(i=0;i<5;i++,p++)
	printf("第%d个元素的地址%d\n",i+1,p);
}
---------------------
输出的结果   应为int占4个字节  所以每个地址相差4
第1个元素的地址6487600
第2个元素的地址6487604
第3个元素的地址6487608
第4个元素的地址6487612
第5个元素的地址6487616

                     //内存当中变量的地址随着电脑内存所占的多少,可能地址会变化

           13.一维数组,指针,函数混搭

                记住:数组可以做实参,指针也可以达到一样的效果

#include<stdio.h>
int main()
{
	int arr[5]={1,2,3,4,5},i;
	void testMax(int *x,int n);
	testMax(arr,5);//传首元素的地址
	for(i=0;i<5;i++)
		printf("%d\t",arr[i]);
	return 0;
}
void testMax(int *x,int n)//x是指向首元素地址    *x代表第一个元素
{
	int max=*x,i;//max=1;
		for(i=0;i<n;i++)
		{
			if(max<*(x+i))
				max=*(x+i);
		}
		printf("max=%d\n",max);
}
-----------------
输出的结果
max=5
1       2       3       4       5

               14.指针和二维数组数组

#include<stdio.h>
int main()
{
	int arr[2][3]={1,2,3,4,5,6},i;
	int *p;
	p=arr[0];
	for(;p<arr[0]+6;p++)//是否可以用p
		// printf("%d\t",arr[i]);
		printf("%d\t",*p);
		return 0;
}
--------------------
输出的结果
1       2       3       4       5       6

            

                    突破口:数组名字代表第一行的地址,

                       arr[0],arr第一行元素的地址, 第一行第一个元素的地址 

                       arr[0]+1 第一行的第二个元素的地址

                      arr+1 第二行的地址 ,第二行第一个元素的地

            15.注意写法(数组和指针的地址)

                      Int arr[2][3];

                    下面的两个都是地址

                      arr[0]  =   *(arr+0)等价        arr+1 = arr[1]  =  *(arr+1)  突破口

                   *(arr+1)+1//第二行第二个元素的地址

#include<stdio.h>
int main()
{
	int arr[2][3]={1,2,3,
		           4,5,6};
	printf("%d\n",&arr[0][0]);//第一行第一列的元素的地址
	printf("%d\n",arr);//第一行的地址,可看做是第一行第一个元素的地址
	printf("%d\n",arr[0]);//第一行第一列的元素地址,第一行的地址
	printf("%d\n",*arr);//第一行第一列的元素地址,第一行的地址
    
	//arr[0]  和   *(arr+0)等价  
	// arr[1]  =  *(arr+1)

	printf("%d\n",arr+1);//第二行的地址,第二行第一个元素的地址
	printf("%d\n",*(arr+1));//第二行的地址,第二行第一个元素的地址


	printf("%d\n",(arr[0]+1));//第一行第二个元素的地址
	printf("%d\n",*(arr+1));//第二行的地址,第二行第一个元素的地址


	printf("%d\n",((arr[1])+1));//第二行第二个元素的地址
	printf("%d\n",*(arr+1)+1);//第二行第二个元素的地址
	printf("%d\n",*(*(arr+1)+1));//二维数组去内容的格式 第二行第二个元素的值	
}

                   printf("%d\n",*(*(arr+1)+1));//二维数组内容的格式 第二行第二个元素的值

#include<stdio.h>
int main()
{
	int arr[3][4],(*p)[4],i,j;//int (*p)[4] 定义了一个指向包含了4个元素的一维数组的指针变量
	p=arr;
	for(i=0;i<3;i++)
		for(j=0;j<4;j++)
			scanf("%d",(*(p+i)+j));
	for(i=0;i<3;i++)
		for(j=0;j<4;j++)
		{
			printf("%d\t",arr[i][j]);
			printf("%d\t",*(*(p+i)+j));
		}
}
-------------------
输出的结果
1
2
3
4
5
6
7
8
9
10
11
12
1       1       2       2       3       3       4       4       5       5       6       6       7       7       8
8       9       9       10      10      11      11      12      12

             16.指针和一维字符串数组

          关于字符数组表示字符串类型:只要有地址,就可以输出,从改地址处开始输出,直到‘\0’出现结束符为止;Printf(“%s”,str)

#include<stdio.h>
int main()
{
	//char *str="ilove china";//等价,类似于数组,指针变量存字符串时,只有当字符串出现\0意味着结束
	char *str;
	str="i love china";
	printf("%s\n",str);//第一个字符的地址
	printf("%c\n",*(str+2));
	return 0;
}
-----------------------
输出的结果
i love china
love china


#include<stdio.h>
#include<string.h>
int main()
{
	int i,n;
	char str[]={"i love china"};
	char *p;
	p=str;(1.p=str+2;)
	n=strlen(str);//字符长的长度
	/* for(i=0;i<n;i++)
		printf("%c\t",*p++); */
	printf("%s\n",p);
	return 0;
}
---------------
输出的结果
i love china
1.输出的结果  从第三个元素开始输出
love china

             17.指针变量和数组的区别

                 str1++;这是不可以的,因为数组名是地址,不可以加的,它是固定的,且是常量

                 str1+7;这是可以的,因为没有改变str1的值

                 char *str="i love china",这是个字符指针,它是可以加的 str=str+7;

#include<stdio.h>
int main()
{
	char *str="i love china",str1[]={"i love china"},*p;
	p=str;
	// p++;
	//str1++;//str1=str1+1;
	
	printf("%c\n",*(str1+5));
	p=p+7;
	printf("%s",p); 
}
-------------
输出的结果
e
china

               18.指针和二维字符数组

                     n = strlen(str);//strlen(str)//str是地址,开始统计,知道遇到'\0'   求出字符串的实际长度

#include<stdio.h>
#include<string.h>
int main()
{//看下出了什么问题
	char *p;
	char str[2][10]={{"abcdefg"},{"ABCDEFG"}};
	int n,m;
	p=str[0];
	n = strlen(str);//strlen(str)//str是地址,开始统计,知道遇到'\0'
	m = strlen(str+1);
	printf("n=%d\t",n);//7
	printf("m=%d",m);//7
	printf("\n");
	for(;p<str[0]+n+m;p++)
		printf("%c",*p);
	return 0;
}
--------------------
输出的结果是
n=7     m=7
abcdefg   ABCD

                     p=str;//int arr[2][3]  arr  第一行的地址,第一行第一个元素的地址,字符二维数组也是一样

#include<stdio.h>
int main()
{
	char str[2][30]={{"i love you"},{"i love china"}};
	char (*p)[30];//char (*p)[30] 定义了一个指向包含了30个元素的一维数组的指针变量
	p=str;//int arr[2][3]  arr  第一行的地址,第一行第一个元素的地址,字符二维数组也是一样
	printf("%s\n",p);
	printf("%s\n",p+1);
	printf("%c\n",*(*(p+1)+5));//第二行第六个元素
}
--------------
输出的结果
i love you
i love china
e

                19.字符指针,函数

#include<stdio.h>
#include<string.h>
int main()
{
	int compare(char *x,char *y);
	char str1[]="i love you";
	char str2[]="i love china";
	char *p,*q;
	p=str1;
	q=str2;
	printf("%d",compare(str1,str2));
}
int compare(char *x,char *y)
{
	return strcmp(x,y);//从第一个地址那里开始比较的
	//strcmp(str1,str2);
}
----------------
输出的结果
1

                     strcmp(x,y);//从第一个地址那里开始比较 的

               20.指针数组(一般用于字符串)

                   int *p[4]; //定义一个指针数组,该数组中每个元素是一个指针,每个指针指向哪里就需要程序中后续再定义了。
                   int (*p)[4]; //定义一个数组指针,该指针指向含4个元素的一维数组(数组中每个元素是int型)。

                  区分int *p[n]; 和int (*p)[n]; 就要看运算符的优先级了。
                  int *p[n]; 中,运算符[ ]优先级高,先与p结合成为一个数组,再由int*说明这是一个整型指针数组。
                  int (*p)[n]; 中( )优先级高,首先说明p是一个指针,指向一个整型的一维数组。

                  int *p[4]:由4个指向整型数据的指针元素组成的

                 对比      int *p[4]             int (*p)[4]; 定义了一个指向包含了4个元素的一维数组的指针变量

#include<stdio.h>
#include<string.h>
int main()
{
	int n=4;
	void compare(char *name[],int n);//char *name[]指针数组
	char *name[]={"i love china","i love you","i am student","i am from china"};
	compare(name,n);
}
void compare(char *name[],int n)
{
	
	int i,k;//k是用来标记下标的(值更大的下标) name[k]是最大的字符串
	for(i=0,k=i;i<n;i++)
		if(strcmp(name[k],name[i])<0)
		{
			k=i;
		}
		printf("%s",name[k]);
}
-----------------
输出的结果
i love you

 

                 21.指向函数的指针(了解)

              格式:

                   int (*p)(int ,int );//定义了一个指向函数的指针变量

                   p=max;//入口地址给p

                  (*p)(num1,num2));//通过调用指针变量来调用max函数

                 注       int **q;//声明指向指针的指针变量                  printf("%d",(**q));//*q==p  (**q) = *p

#include<stdio.h>
int main()
{
	int max(int x,int y);
	int (*p)(int ,int );//定义一个指向函数的指针 
	int num1,num2;
	scanf("%d%d",&num1,&num2);
	p=max;//P指向了函数,函数的名字就是地址,可以不用&,入口地址
	printf("最大值%d\t",(*p)(num1,num2));
	return 0;
}
int max(int x,int y)
{ 
	if(x>y)
		return x;
	else
		return y;
}
#include <stdio.h>
int main(){
    char *str[3] = {
        "c.biancheng.net",
        "C语言中文网",
        "C Language"
    };
    printf("%s\n%s\n%s\n", str[0], str[1], str[2]);
    return 0;
}
运行结果:
c.biancheng.net
C语言中文网
C Language

需要注意的是,字符数组 str 中存放的是字符串的首地址,不是字符串本身,字符串本身位于其他的内存区域,和字符数组是分开的。

也只有当指针数组中每个元素的类型都是char *时,才能像上面那样给指针数组赋值,其他类型不行。

           十三.结构体

       1.  结构的定义

                   定义一个结构的一般形式为: struct 结构名   {   成 员表列  } 

                   成员表由若干个成员组成,每个成员都是该结构的一个组成部分。 对每个成员也必须作类型说明

                  例如: struct stu { int num; char name[20]; int age; }         struct stu    ---- 类比成  int    

                 //结构体类型的名字(Person)首字母要大写

                 定义结构体的变量      Struct 结构体名字 变量名字     如    struct stu student      student为结构体变量的名字

         2.  结构体变量初始化

#include<stdio.h>
int main()
{
		struct Person
	{
		int id;
		char name[10];
		int age;
		char sex;
		char addr[20];
	}zhangsan={1001,"zhangsan",12,'M',"101street"},lisi={1002,"lisi",13,'M',"102street"};
	//初始化
	printf("%d\n%s\n%d\n%c\n%s\n",zhangsan.id,zhangsan.name,zhangsan.age,zhangsan.sex,zhangsan.addr);
	return 0;
}

           声明的时候,定义了,又初始化了

           zhangsan={1001,"zhangsan",12,'M',"101street"},lisi={1002,"lisi",13,'M',"102street"};它是按照结构体类型成员里面出现的顺序一一对应赋值的

//利用数组初始化
#include<stdio.h>
int main()
{
		struct Person
	{
		int id;
		char name[10];
		int age;
		char sex;
		char addr[20];
	} student[2]={{1001,"zhangsan",12,'M',"101street"},{1002,"lisi",13,'M',"102street"}};
	printf("%d\n%s\n%d\n%c\n%s\n",student[0].id,student[0].name,student[0].age,student[0].sex,student[0].addr);
	return 0;
}

             注意:

  • 不能整体输出输入(结构体变量),只能一个一个成员的输出输入
  • 结构体变量可以相互赋值(同类)
  • 结构体变量中的成员可以进行运算
  • 利用scanf对变量成员初始化,但不能用&整体初始化

              3.结构体指针

                     Struct Person *pt;

                      //Int *p;

                     P=&zhangsan;

                     (*p).age;

                    (*p)表示p指向的结构体变量(zhangsan),(*p).age表示指向的结构体变量的成员

  • printf("%d\t%s\t%d\t%c\t%s\n",(*p).id,(*p).name,(*p).age,(*p).sex,(*p).addr);
  • printf("%d\t%s\t%d\t%c\t%s\n",p->id,p->name,p->age,p->sex,p->addr);

                    这两种是等价的,只是书写格式不一样而已

  1. printf("%d\t%s\t%d\t%c\t%s\n",zhangsan.id,zhangsan.name,zhangsan.age,zhangsan.sex,zhang)这种是最原始的
#include<stdio.h>
int main()
{
		struct Person
	{
		int id;
		char name[10];
		int age;
		char sex;
		char addr[20];
	}zhangsan,lisi;
	struct Person *p;//定义了一个指向结构体类型的指针
	scanf("%d%s%d%c%s",&zhangsan.id,zhangsan.name,&zhangsan.age,&zhangsan.sex,zhangsan.addr);
	p=&zhangsan;
	printf("%d\t%s\t%d\t%c\t%s\n",zhangsan.id,zhangsan.name,zhangsan.age,zhangsan.sex,zhangsan.addr);
	printf("%d\t%s\t%d\t%c\t%s\n",(*p).id,(*p).name,(*p).age,(*p).sex,(*p).addr);
	//(*p)表示p指向的结构体变量,(*p).age表示指向的结构体变量的成员
	printf("%d\t%s\t%d\t%c\t%s\n",p->id,p->name,p->age,p->sex,p->addr);
	return 0;
}

#include<stdio.h>
int main()
{
		struct Person
	{
		int id;
		char name[10];
		int age;
		char sex;
		char addr[20];
	} student[2]={{1001,"zhangsan",12,'M',"101street"},{1002,"lisi",13,'M',"102street"}};
	struct Person *p;
	p=student;
	for(;p<student+2;p++)
	{
		//printf("%d\n%s\n%d\n%c\n%s\n",student[0].id,student[0].name,student[0].age,student[0].sex,student[0].addr);
		printf("%d\t%s\t%d\t%c\t%s\n",(*p).id,(*p).name,(*p).age,(*p).sex,(*p).addr);
		printf("%d\t%s\t%d\t%c\t%s\n",p->id,p->name,p->age,p->sex,p->addr);
	}
	return 0;
}

 补:

typedef struct与struct的区别

       1.typedef为C语言的关键字,作用是为一种数据类型定义一个新名字。在编程中使用typedef目的一般有两个,一个是给变量一个易记且意义明确的新名字,另一个是简化一些比较复杂的类型声明。

 typedef struct tagMyStruct

 int iNum;
 long lLength;
} MyStruct;

这语句实际上完成两个操作:

1) 定义一个新的结构类型

struct tagMyStruct

 int iNum; 
 long lLength; 
};

分析:tagMyStruct称为“tag”,即“标签”,实际上是一个临时名字,struct 关键字和tagMyStruct一起,构成了这个结构类型,不论是否有typedef,这个结构都存在。

我们可以用struct tagMyStruct varName来定义变量,但要注意,使用tagMyStruct varName来定义变量是不对的,因为struct 和tagMyStruct合在一起才能表示一个结构类型。

2) typedef为这个新的结构起了一个名字,叫MyStruct。

typedef struct tagMyStruct MyStruct;

因此,MyStruct实际上相当于struct tagMyStruct,我们可以使用MyStruct varName来定义变量。

              十四.动态分配和链表

              1.Void 指针类型(void *)  int *p;  void  空的

                定义一个基类型为void的指针变量,不指向任何类型的数据(指向空类型),而不是指向任何的类型。

#include<stdio.h>
int main()
{
	int a=10;
	int *p1=&a;
	char *p2;
	void *p3;//空类型的指针,不指向任何类型的数据
	p3=(void *)p1;  // b=4.4 ;int a = (int)b; b的值没有变
	p2=(char *)p3;
	printf("%d",*p1);
	p3=&a;//错误,赋值后得到的是纯地址,没有指向
	return 0;
}

            2. 静态分配:

               char str[3][50];

               编译器在处理程序源代码时分配.系统为我们分配,不需要我们自己动手分配

               动态内存在函数执行完毕之后仍然可以被其他函数所调用(动态内存可以跨函数使用)

          3. 动态分配:需要使用指针

            程序执行时按动态要求分配.如果需要空间的话,就分配相应的空间吗,不需要的时候就释放掉空间,节约资源

        4.区别:

  • 静态分配都是有名字的变量, 我们直接对其操作, 而动态对象是没有名字的变量, 我们是用指针间接地对它进行操作.
  • 静态分配与释放由编译器进行处理, 动态分配必须由程序员显式的管理, 相对来说较易出错
  • 所需的头文件(stdlib) stdlib 头文件即standard library标准库头文件

                (1).malloc

                void *malloc(unsigned int size);分配多少个字节,如果此函数没有能成功分配,则会返回一个空指针(NULL),指向一个不被使用的地址。

                (2).calloc

                Void *calloc(unsigned n,unsigned size); 分配n个size大小的空间,如果此函数没有能成功分配,则会返回一个空指针(NULL)

               (3).realloc 之前分配的不够用,再增加一些空间,mallloc calloc  觉得不够用 ,就用realloc重新分配空间使用

               Void *realloc(void *p,unsigned int size); 如果此函数没有能成功分配,则会返回一个空指针(NULL)

               (4).free();

              Void free(void *p); 释放空间

#include<stdio.h>
#include<stdlib.h>
int main(void)
{
	int i;
    int *p=(int *)malloc(5*sizeof(int));
	int *q=(int *)calloc(5,sizeof(int));
    if(p!=NULL)//成功了
	{
          for(i=0;i<5;i++)
		  {
			  *(p+i)=i+1;
			  printf("%d\t",*(p+i));			  
		  }
    }
	else//失败了
	{
        printf("malloc error\n");
    } 
    p = (int *)realloc(p,10*sizeof(int));
	for(i=5;i<10;i++)
	{
		*(p+i)=i+1;
	    printf("%d\t",*(p+i));
	}
		
	free(p);
		
	/*if(q!=NULL)
	{
          for(i=0;i<5;i++)
		  {
			  *(q+i)=i+2;
			  printf("%d\t",*(q+i));			  
		  }
    }
	else
	{
        printf("calloc error\n");
    } 
    free(q);*/	
    return 0;
}

              5.链表的介绍(数据结构)

                    链表类似铁链子

  • 链表时常跟着结构体出现  struct person {int age ;char sex;};
  • 需要指针
  • 是一种动态分配的数据结构
  • 内存中的地址可以不是连续的
  • 找一个元素,必须知道前一个元素的地址
  • 链表中的每个元素叫做结点
  • 链表中的每个结点有两个部分组成 ,数据和下一个结点的地址,一个是数据域,一个是指针域
  • 会有头指针

NULL:

  • 仅仅代表空值,也就是指向一个不被使用的地址,
  • 在大多数系统中,都将0作为不被使用的地址
  • 所以有些系统把0与NULL等价起来
  • NULL和0的值都是一样的,NULL用于指针和对象,0用于数值
  • 最好不要将0与NULL等价起来
  • 是否可以用null代替NULL  不可以

              2.静态链表(简单的链表)

                 不是临时开辟的,而是在程序当中定义的,不需要释放空间

#include<stdio.h>
struct Student   //类似int
{
	int num;//学号
	int score;//分数
	struct Student *next;//类比int *p;
};
int main()
{
	struct Student a, b, c, *head, *p;
	a.num = 101; a.score = 88;
	b.num = 102; b.score = 99;
	c.num = 103; c.score = 100;
	head = &a;
	a.next = &b;
	b.next = &c;
	c.next = NULL;
	p = head;//p是遍历指针
	do
	{
		printf("%d\t%d\n", p->num, p->score);
		p = p->next;//p往下遍历
	} while (p != NULL);
	return 0;
}
----------------
输出的结果
101   88
102   99
103   100

                     十五.共用体(联合体)   枚举类型(enum)

                    学会对比,和结构体类似

                   1.关键字:union

                             同一段存储单元存放不同类型的变量

                    2.定义共用体类型变量的形式  

#include<stdio.h>
int main()
{
	union Person
	{
		int age;
		char sex;
	};
	//union Person zhangsan = {98};
	union Person Zhangsan,lisi;
	zhangsan=lisi;
	Zhangsan.age=98;
	printf("%d\t",sizeof(Zhangsan));//4
	printf("%d\t",Zhangsan.age);//98   98
	Zhangsan.sex='A'; 
	printf("%d\t",Zhangsan.age);//b   65
	/*union Person
	{
		int age;
		char sex;
	}zhangsan;*/
    return 0;
}

        Union 共用体名                              例如:定义共用体变量                                       Union Person

       {                                                              Union Person                                             {   Int age;   Char sex;}

       成员表列                                                {  Int age;   Char sex;}                                Union Person zhangsan,lisi;

       }  变量名字;                                            zhangsan,lisi;                                               

 

                        3.共用体和结构体的所占内存的区别

                                      共用体是最长长度代表整个共用体长度

                                      结构体是各种成员数据相加(理论值)

                        4.引用共用体变量

                                 Zhangsan.age;

                       5.初始化成员列表,只能初始化一个

                                  Union Person Zhangsan.age={12};

                                  {}是对整个变量赋值

                              Union Person

                                 {

                                     Int age;

                                     Char sex;

                                   }zhangsan={12,’m’};这是错误的

  • 共用体起作用的成员是最后一次赋值的成员,之前的会被取代
  • 共用体变量的地址和它各成员的地址都是同一个地址,同用一个存储单元
  • 不能对共用体整体赋值
  • 同种类型的共用体变量可以互相赋值
  • 共用体也可以和指针,数组之类的搭配
  • 初始化成员列表,只能初始化一个

                枚举类型(enum)

                      学会对比

              1.如果一个变量有几种可能的值,则可以定义为枚举类型,就是把各种存在的值一一的列举出来

              2.关键字;Enum  

#include<stdio.h>
int main()
{
	enum month {january=6 ,february=1 ,march ,april ,may ,june,july ,august,september ,october ,november ,decembert};
	
	enum month month1,month2;
	month1=march;
	//march=3;这是错误的
	//month1=march;
	printf("%d",month1);//默认是跟数组下标的顺序是一样的,如果设置值了,则每次是加1,没有的话,默认最开始的为0
	//根据最近的一个值来设置大小的,
	return 0;
}

                     3.声明枚举类型的一般形式

                               enum 枚举名 {枚举元素列表}

                              //struct  student {int age ;char sex};

                      4.定义变量

                                Enum month  month1,month2; 

                               //struct Student zhangsan,lisi;

                                Zhangsan.age=23,43;

                                思考month1可以取哪些值?答:只可以去枚举元素列表里面的值

          Enum month{january ,february ,march ,april ,may ,june,july ,august,september ,october ,november ,decembert}

                      5.括号里面叫做枚举元素或者枚举常量

                                全部可能出现的值

                      6.枚举的特点

  1. 不能赋值

             march=3;这是错误的

  1. 本身代表着一个顺序数值

 

                  用typedef声明新的类型名

                 用一个新的类型名代替原有的类型名(int double float)dou

                 格式:typedef 旧的类型名  新的类型名

                              double a;                    typedef double dou;

                              double a;                    dou a;

               思考 换上了新的名字,旧的名字有用吗         依然有用

1.普通的

/*#include<stdio.h>
typedef  int Integer;//用  Integer  代替 int
int main()
{
	
	//Integer a=23;//int  a=23;
	int a=22;
	printf("%d",a);
	return 0;
}*/


/*#include<stdio.h>
typedef char String[20];//注意写法,简单的表示字符串 String 代替 char str[20];
int main()
{
	String str="i love you";//代表了一个可以放20个字符的字符串类型
	printf("%s",str);//
	return 0;
}*/



#include<stdio.h>
typedef char * String;
int main()
{
	//char *p="i love you";
	String p="i love you";
	printf("%s",p);
	return 0;
}

2.结构体的

#include<stdio.h>
int main()
{
	/*struct Person
	{
		int age;
		char sex;
	} ;//结构体变量
	struct Person person1;
	*/


	/*typedef struct Person
	{
		int age;
		char sex;
	} person1;//person1代表着 struct Person
	person1 p;
	struct Person p1;*/
	
	

	typedef struct 
	{
		int age;
		char sex;
	}student;//student代表着 struct {};
	student p;
	return 0;
}

#define的介绍

#include<stdio.h>
#define X  (5+3)//这里是没有分号的
int main()
{
	printf("%d",X*X);//5+3*5+3=23 //(5+3)*(5+3)=64
	return 0;
}

Define  与 typedef的对比

  1. #define是在预编译时候处理的,它只是做简单的字符串替换
  2. typedef在编译阶段处理的,不是简单的替换处理,而是采用如同定义的方法来处理的
  3. typedef有利于程序的移植和通用 

                      十六.文件(file)

                文本文件和二进制文件

                       1.需要的头文件(stdio.h)

  1. 输入输出的过程象流水一样从一个地方流向另一个地方
  2. 磁盘存储形式:字符使用ASCII形式存储,整型可以用ASCII形式,也可以用二进制形式
  3. 数据在内存中是以二进制存储的,如果不加转换就输出到外存就是二进制文件,用ASCII形式保存在外存为文本文件,则在需要存储前需要转换

                         2.文件路径:g:\\cworkspace\\part14\\Demo1.c  单个反斜杠可以找到路径吗?会访问不到

                         3.怎么访问文件呢                用FILE 文件指针  大写的,小写不行

                         4.程序数据区  内存 (缓冲区) 磁盘

                    

                         5.定义一个文件指针 FILE * fp;

                         6.打开和关闭文件   //打开了文件,也要关闭文件,不然会出现问题

                          7.fopen(文件名,打开方式);//函数,返回一个地址 该文件的起始地址

       打开方式

文本文件打开的方式(单一)

文件使用方式

含义

如果不存在

r(只读)

输入数据,打开一个已经存在的文本文件

出错

w(只写)

输出数据,打开一个文本文件(w方式擦除原来的东西)

建立一个新文件

A(追加)

文件尾添加数据

出错

二进制的文件的打开方式(单一)

Rb(只读)

输入数据,打开一个已经存在的二进制文件

出错

Wb(只写)

输出数据,打开一个二进制文件

建立新的文件

Ab(追加)

向二进制文件尾添加数据

出错

文本文件打开的方式(两个)

 

r+(读写)

输入输出数据,打开一个已经存在的文本文件

出错

W+(读写)

输入输出数据,建立一个文本文件

建立一个文件

A+(读写)

输入输出文件尾添加数据

出错

二进制的文件的打开方式(两个)

Rb+(读写)

输入输出数据,打开一个已经存在的二进制文件

出错

Wb+(读写)

输入输出数据,打开一个二进制文件

建立新的文件

Ab+(读写)

输入输出向二进制文件尾添加数据

出错

        总结:   文本文件  r是只读,w只写

                      二进制    rb是只读,w只写  (文本文件上加了个b)

                       又读又写  只需要在原有的基础上 后面加个+   w+  wb+

打开一个文件

#include<stdio.h>
FILE *fp;
if((fp=fopen("g:\\cworkspace\\part14\\Demo1.c","r"))!=NULL)//file1的位置是在和我本文件同一个文件夹     
如果当前目录没有该文件,就会自动创建一个 
//g:\\cworkspace\\part14\\Demo1.c
{
	printf("成功了");
	
}
else
{
	printf("失败了");
	exit(0);//正常关闭程序  头文件的支持  stdlib.h
	exit(-1);//关闭程序,异常的关闭程序
}

关闭文件

fclose(文件指针)//函数,成功的关闭了的话,就返回0,失败的话返回 -1(EOF)//EOF是个失败的标志

Fclose(fp)                为什么要关闭文件     因为缓存的原因

读写字符的函数

fgetc(fp)

从fp指向文件读入一个字符

成功返回字符,失败EOF(-1)

fputc(ch,fp)

从fp指向文件写到一个字符

成功返回字符,失败EOF(-1)

给文件里面写入数据

#include<stdio.h>  //FILE* 
#include<stdlib.h>//exit(0)
int main()
{
	FILE *fp;
	char ch, filename[10];
	scanf("%s", filename);
	if ((fp = fopen("g:\\cworkspace\\part15\\lala", "w")) == NULL)//同一个地方的文件
	{
		printf("失败了");
		exit(0);//如果失败了,就关闭程序
	}
	ch = getchar();//接收enter键的值,因为我输入filename的时候,按下了enter键
	ch = getchar();//e
	while (ch != '#')//用来做结束的
	{
		fputc(ch, fp);//写入到文件xiexie
		putchar(ch);//同时也输出到屏幕,显示效果
		ch = getchar();//又输入字符,a
	}//eaaaads#
	fclose(fp);//关闭文件,解决缓冲的问题
	putchar(10);//输出到屏幕,ASCII表 10 代表的是换行
	return 0;
}

读取文件中的数据

          文件结束标志                           feof(fp)//判断文件结束了没

          文件结束 函数值为1                  文件没有结束 函数值为0

#include<stdlib.h>
#include<stdio.h>
int main()
{
	FILE *fp;
	char ch;
	if((fp=fopen("xiexie","r"))==NULL)
	{
		printf("失败了");
		exit(0);
	}
	while(!feof(fp))//结束返回1,没有0
	{
		ch=fgetc(fp);//从磁盘一直去字符出来
		printf("%c",ch);
	}
	fclose(fp);
	return 0;
}

读写一个字符串

fgets(str,n,fp)

从fp指向文件读入长度(n-1)的字符串

成功返回str,失败NULL

fputs(str,fp)

从fp指向文件写到一个字符串

成功返回0,失败非0值

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
	int i;
	FILE *fp;
	char str[3][20];
	for(i=0;i<3;i++)
		gets(str[i]);//填入三行字符串,准备好有内容的字符串
	if((fp=fopen("mmmmm","w"))==NULL)
	{
		printf("失败了");
		exit(0);
	}
	for(i=0;i<3;i++)
	{
		fputs(str[i],fp);//写入内容
		fputs("\n",fp);//换行
		printf("%s",str[i]);//在屏幕上输出相应的内容
	}
	return 0;
}

格式化方式读写文件

                      fprinf(文件指针,格式化字符串,输出表列)//从数据区输出到磁盘

                      fscanf(文件指针,格式化字符串,输入表列)//从磁盘读入数据

#include<stdio.h>
#include<stdlib.h>
int main()
{
	FILE *fp;
	char *p="i love you";//代表一个字符串
	if((fp=fopen("xiexie","w"))==NULL)//同一个地方的文件
	{
		printf("失败了");
		exit(0);
	}
	fprintf(fp,"%s",p);//格式输出,把p的字符串输出到磁盘xiexie里面
	fclose(fp);
}
#include<stdio.h>
#include<stdlib.h>
int main()
{
	FILE *fp;
	char str[20];
	if((fp=fopen("lala","r"))==NULL)//同一个地方的文件
	{
		printf("失败了");
		exit(0);
	}
	fscanf(fp,"%s",str);//读入数据到数据区   将fp的内容读到str中
	printf("%s",str);
	fclose(fp);
}

补充:

    1.memset的介绍

          void *memset(void *s, int ch, size_t n);

函数解释:将s中当前位置后面的n个字节 (typedef unsigned int size_t )用 ch 替换并返回 s 。 ch的值只能为0或-1

memset:作用是在一段内存块中填充某个给定的值,它是对较大的结构体数组进行清零操作的一种最快方法 。

memset()函数原型是extern void *memset(void *buffer, int c, int count) buffer:为指针或是数组,c:是赋给buffer的值,count:是buffer的长度.

#include<stdio.h>
#include<string.h>
int main()
{

   int arr[10];
   int i;
   memset(arr,-1,sizeof(arr));//统一处理,给一块内存空间初始化//只能用  0  -1
   for(i=0;i<10;i++)
	   printf("%d\t",arr[i]);
   return 0;
}

    常见的错误:

/*#include<stdio.h>  没有取地址符
int main()
{
	int a;
	scanf("%d",&a);
	printf("%d",a);
}*/

/*#include<stdio.h>超过数据的范围
int main()
{
	int a=128;
	char ch;//最大127
	ch=a;
	printf("%d",ch);
}*/

/*#include<stdio.h>
int main()
{
	int a,b;
	scanf("%d%d",&a,&b);//按照格式来输入
	printf("%d\t%d",a,b);
	return 0;
}*/

/*#include<stdio.h>
int main()
{
	char name[10];//字符数组输入
	scanf("%s",name);//这里可以不用加&,因为数组名字就是一个地址
	gets(name);//输入字符
	printf("%s",name);
}*/

/*#include<stdio.h>
int main()
{
	char *p;//指针必须得指向东西后,才能拿来输出,拿来用
	printf("%c",*p);
	return 0;
}*/

/*#include<stdio.h>
int main()
{
	int a=10;
	if(a>5)
		;//这是个空语句而已,当条件为真的时候,就执行这个空语句
	return 0;
}

#include<stdio.h>
int main()
{
	int a=10;//C语言当中大小写敏感,大小写是不一样的东西
	printf("%d",a);
	//printf("%d",A);
}

#include<stdio.h>
int main()
{
	int arr[10]={1,2,3,0};//最大存是个int型的数据
	printf("%d",arr[10]);//arr[0],就是第一个数据,访问下标为10,也是就是说第十一个数据。
	
}

#include<stdio.h>
int main()
{
	char str[11]={"i love you"};//这个数组用来存字符串,字符串是有结束标志的'\0',也是个字符
	char str1[10]={'i','l','o','v','y','o','u','h','e','a'};//用来存字符
	//printf("%s",str+5);//字符数组,只有有地址,就从地址这里开始输出,直到遇到'\0'
	//printf("%s",str1+3); 
	//printf("%s",str1);//以找到了地址就输出    在Dev c++输出ilovyouhea
	
}*/


#include<stdio.h>
int main()
{
	char str[][2]={{'2','2'},{'2','3'}};//必须要写上列,行可以不写
	
}

#include<stdio.h>
int main()
{
	int arr[10]={1,2,3};//指针是可以变动的,尽管数组名代表着地址,但是数组名不可以变动,不可以自加和自减
	int *p=arr;//代表着首元素的地址
	//printf("%d",*arr);
	//printf("%d",*(++p));
	printf("%d",*(arr+1));
}*/



/*#include<stdio.h>先写数组,再赋值就出错了
int main()
{
	int arr[10];
	arr={1,2,3,4,5,5};//不能这样写
	return 0;
}*/


#include<stdio.h>
int main()
{
	printf("hahah");//最好养成一个习惯  把定义写在最前面
	int a;
	a=10;
}

        头文件介绍

         Windows.h

1. GetAsyncKeyState() //检测程序运行时某个按键的状态

      简单的用法,真正的用法是

VK_SHIFT Shift键        VK_LSHIFT 左Shift键          VK_RSHIFT 右Shift键        VK_CONTROL Ctrl键  VK_LCONTROL 左Ctrl键

VK_RCONTROL 右Ctril键     VK_MENU Alt键     VK_LMENU 左Alt键     VK_RMENU 右Alt键     VK_LBUTTON 鼠标左键

VK_RBUTTON 鼠标右键      VK_ESCAPEESC键    VK_RETURN回车键    VK_TABTAB键    VK_SPACE空格键   VK_UP 上

VK_DOWN 下      VK_LEFT  左      VK_RIGHT 右

#include<windows.h>
#include<stdio.h>
int main()
{
	while(1)
	{
		if(GetAsyncKeyState(VK_UP)) //检测是否按下键盘上的上键,大家可以尝试给它加个while(1),再来测试
		printf("hahagjjjjjjjjjjjjjjjjjjjjjjjd\n");//如果按下上键  则输出此语句
	}
		return 0;
}

2.system(“pause”);//暂停的功能

3.Sleep(1000);//休眠了多少毫秒,s是大写

4.system(“cls”);//清理屏幕

#include<windows.h>
#include<stdio.h>
int main()
{
	int i;
	for(i=0;i<10;i++)
	{
		Sleep(300);//s是大写
		printf("%d\n",i);
	}
	system("pause");//按下任意键继续
	system("cls");//清理屏幕
	//Pos(10,10);
	printf("hahahahahha");
	return 0;
}

  

             Stdlib.h

    1.rand()  生成的是伪随机数 其值0--RAND_MAX                       其值与编译器实现有关,至少为32767

                     Rand()不是真正的随机

网友:srand(unsigned t)是为rand()产生伪随机数下一个“种子”。所谓“种子”就是给伪随机发生器赋一个初值,因为如果初值一样,后面产生的伪随机数的规律也就一样,达不到“随机”的目的。所以srand(unsigned t)一般是用机中的实时时间来启动的,因为实时时间的值每时每刻都在变化,这样启动的rand()函数产生的伪随机数序列就能达到真正随机的效果。

    2.srand((unsigned)time(NULL));//为了防止每次产生的随机数相同,种子设置为time(0),在rand()之前使用

注:

因为,对于任意数,0<=rand()%(n-m+1)<=n-m

因此,0+m<=rand()%(n-m+1)+m<=n-m+m

因此,如要产生[m,n]范围内的随机数num,可用:

int num=rand()%(n-m+1)+m;

其中的rand()%(n-m+1)+m算是一个公式,记录一下方便以后查阅。

比如产生10~30的随机整数:

srand(time(0));

int a = rand() % (21)+10

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
int main()
{
	int a,i;
	srand((unsigned int)time(NULL));//真正实现伪随机数,用时间的唯一性产生一个种子
	for(i=0;i<100;i++)
	{
		a=rand();//每次随机产生一个数
		a=rand()%12+3;//[3,14];
		
		printf("%d\t",a);
	}
	return 0;
}

               <time.h>

            time()函数  32位  2^31-1

            time(0)是计算从1970年1月1日零时零分零秒到目前为止累计的秒数,而ctime函数将这个值,转换成字符串,输出为正常的时间

include <stdio.h>   
#include <time.h>   
int main()   
{   
    time_t t; //类似 int a;   
    t = time(0);          //同时这里也可以写作 time(NULL)   
    printf("%ld \n" , t);  //总共的秒数 
    printf("%s", ctime(&t));   //输出正常的时间
    return 0;   
}

                 <conio.h>

             getch()//不用按下回车键就可以读取  区别    getchar() 得按下enter键

             上、下、左、右键是二个字节的,getch()只读一个字节,所以用两次getch();

            //键盘上的上下左右按键的askII码表

           //上          //下           putchar(10);//换行        //左                           //右

#include<stdio.h>
#include<conio.h>
int main()
{
	char ch;
	//getchar();
	while(1)//死循环
	{
		ch=getch();//不需要按下enter键   上、下、左、右键是二个字节的,getch()只读一个字节
		if(ch!='\0')
			ch=getch();
		if(ch==72)
			printf("您按下的是上键\n");
		if(ch==80)
			printf("您按下的是下键\n");
	}
	return 0;
}*/

             stdio.h

            sprintf(s,"%d",a);//将数字a,转化为字符串s,头文件是stdio.h。

#include<stdio.h>
int main()
{
	char s[10];
	int a;
	scanf("%d",&a);
	sprintf(s,"%d",a);//将数字a,转化为字符串s,头文件是stdio.h。
	printf("转换成后的字符串为%s",s);//输出转换成的字符串
	
}
-----------
输入结果  
 字符串10

            graphics.h

          写一个简单例子

  1. 初始化窗口:initgraph(x, y);这是先创建一个窗口的函数,以左上角为(0,0),向右为x轴,向下为y轴,其中x表示长x个单位,y表示宽y个单位。
  2. 关闭图像窗口:closegraph();结束时用来关闭用的。
  3. 按任意键继续:为了防止以运行完就关了,这样能停顿一下,头文件是:conio.h
  4. 画线:line(x1, y1, x2, y2);在你创建的那么窗口里以(x1,y1)和(x2,y2)为两个端点画线。
  5. 画矩形:rectangle(x1,y1,x2,y2);以(x1,y1)和(x2,y2)为对角画一个矩形
  6. 画圆:circle(x,y,r);以(x,y)为圆点,r为半径画圆
  7. 颜色:setcolor(x);用来设置颜色的,其中x是你要设置的颜色,可以填这16种:黑 BLACK、蓝 BLUE、绿 GREEN、青 CYAN、红 RED、紫 MAGENTA、
#include<stdio.h>
#include<graphics.h>
#include<conio.h>
int main()
{
	
	
	 initgraph(700, 700); // 初始化绘图窗口 
	 setcolor(RED);//设置画笔的颜色
     circle(200, 200, 100); // 画圆,圆心(200, 200),半径 100
	 rectangle(200,200,400,400);//画矩形
	 line(200,200, 500, 500);
	 getch();
     closegraph(); // 关闭图形界面  


}

 

 

 

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wkflyj

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值