学C语言的,有福了,

来源:互联网 发布:虎门淘宝培训班 编辑:程序博客网 时间:2024/06/02 15:01

本人在学c期间,做了大量的笔记,现在我将它给分享出来,如果你认为还好的话,可以借鉴,就继续分享下去,另外希望大家指正一些问题,大家一起学习。。谢谢!!!!




#include <stdio.h>

int main(int argc, char **argv) {

   printf("hello");

   return 0;

}

 

l  #include<stdio.h> :预处理指令。在编译之前执行的指令

l  系统自带的文件用<>,自己写的文件用""

l  .h成为头文件,用来声明一些常用的函数,假如想使用这些这些函数,就必须包含这个头文件

l  main函数(只能有一个),是c的程序入口

l  c语言中可以不写返回值,代表的是int main,如果是无返回值,则是void main

l  main()里面的参数可以不填写

l  如果无返回值,则不用”return0”

注意:c语言中的语言不严格

1.        一个项目中有多个.c的源文件,编译成功会产生与此对应的.obj目标

函数

l  主函数,main作为一个主函数,程序都是最先执行的,不管次函数放在代码的什么位置

l  自定义函数,开发人员自定义的,可有可无,数目不限

void test(){

        

}

l  C语言提供的库函数,比如:stdio.h中的printf(),输入函数scanf();

函数的声明和定义

虽然说c中的函数时类似于java中的方法,但在使用上还是有区别的

1、 Java中,每个方法的定义顺序没有限制,在前面定义的方法内部可以调用后面定义的方法

2、  在c语言中,如果要想在main()函数中调用方法,则需要先在main()方法前做一个”声明”

声明:函数名,函数接收的参数类型,函数的返回值

\n à换行

注意:一般不要写main主方法中写很多的内容,可以将需要“声明”的文件另外写为.h后缀的头文件,具体方法则写入到.c后缀的文件中,最后在main()方法中调用 #include “XXX.h” ;一定不能调用”XXX.c”à关于链接环境

printf和scanf函数

这两个函数都是在stdio.h中声明的一个函数,因此使用之前需要加入#include<stdio.h>

用法:

①  printf(字符串)

printf(“hello world”);

②  printf(字符串,格式符参数)

Printf(“My age is %d\n”,26);

printf("my name is %s ,sex is %c,height is %f,age is %d", "李春福", 'B', 1.73,20);

一个中文至少会占用两个字符用string 类型的

%.2f代表保留2位小数

%-5.2f表示的是保留两位小数的5位字符,如果为”-”,则右边空出,否则左边空出

常用的格式符及其含义

格式符

功能

%d

以带符号的十进制形式输出整数(但正数不输出正号+)

%o

以不带符号的八进制形式输出整数

%x

以不带符号的十六进制形式输出整数

%u

以不带符号的十进制形式输出整数

%c

输出一个字符

%s

输出一个或多个字符

%f

以小数形式输出单、双精度数,默认输出为6位小数

%e

以标准指数形式输出单、双精度数,数字部分小数位数为6位

基本数据类型和类型修饰符

l  基本类型图

l  变量

 c语言中用变量来存储计算过程使用的值,任何变量都必须先定义类型再使用。

  问题:为什么一定要先定义?

因为变量的类型决定了变量占用的存储空间,所以定义变量类型,就是为了给该变量分配适当的存储空间,以便存放数据。

类型

名称

存储空间(16位编译器)

int

整型

2个字节

float

单精度浮点型

4个字节

double

双精度浮点型

8个字节

char

字符型

1个字节

①  局部变量:在c语言中,未经过初始化的变量,也可以打印出来,值由系统随机分配

②  char的取值范围: ASCII码字符或 128~127的整数

③  char只能存储一个字符

l  类型修饰符

有4中修饰符:

1、 short  à短型

2、 long  à长型

3、  signed à 有符号型

4、  unsigned à无符号型

short int s1=1èshort s1=1

long int l1=2 èg l1=2

   

基本运算

l  循环语句(do 、while、for)

l  条件语句(if 、if-else、switch)

l  goto语句

c语言一共有34种运算

c语言中没有boolean类型,如果关系运算符为“真返回1就返回0;任何非0值都为真,只有0值才为假

陷阱①:判断先把常量写在前面,变量写在后面

Java 不可以直接写 a>bè boolean a>b,c语言比较弱,不严谨

陷阱②: a=8表示将8的值赋给aèa==8则不能赋值

逗号表达式主要用于连接表达式,整个表达式的值是最后一个表达式的值

值为30

值为3

数组(构造类型)

一维数组:* 初始化的一般形式是:类型 数组名[元素个数] = {元素1,元素2, ...};

   int a[10];

 

定义方式:类型说明符  数组名[常用表达式] ;二维数组:类型 数组名[行数][列数]

float a[3][4];

 

定义方式: 类型说明符  数组名[常用表达式] [常用表达式] ;

数组(变量)的地址是第一个元素的地址

数组名代表的就是数组的地址,也就是第0个元素的地址

  //查看每一个数组元素的地址

    int i;

    for(i=0;i<5;i++){

             printf("a[%d]的地址:%d\n",i,&a[i]);

    }

    return 0;

数组的初始化:3种方法

void init(){

         int b[3]={12,32};

        

int b[]={12,32};

 

         int b[3];

         b[0]=1;

         b[1]=3;

         b[2]=5;

}

字符串(字符数组)

          

         char c[]={'l'.'c','\0'};

          char c1[3]={'l','c','\0'};

          char  c3[]="lc";   è自动在末尾添加’\0’

          

          char c2[3]={'l','c'};

前面三种表示的是字符串初始化,后面的不是

puts()和printf()都是可以用于字符串,但是puts()一次性只能输出一个字符串

puts()可以自动换行。

stdio.h中有2个函数可以用来接收用户输入的字符串,分别是scanf和gets,建议不要用gets去输入数据,不安全

字符串数组

一维字符数组中存放一个字符串,比如一个名字char name[20] = "mj"

字符串数组的初始化

har names[2][10] = { {'J','a','y','\0'}, {'J','i','m','\0'} };

 

char names2[2][10] = { {"Jay"}, {"Jim"} };

 

char names3[2][10] = { "Jay", "Jim" };

可以把字符串数组看作是一维数组,它的元素是字符串。字符串数组names由字符串"Jay"和字符串"Jim"构成

字符和字符串处理函数

字符输出函数putchar

putchar(65); // A

putchar('A'); // A

int a = 65;

putchar(a); // A

 

上面的3种用法,输出的都是大写字母A

* putchar一次只能输出一个字符,而printf可以同时输出多个字符

printf("%c %c %c", 'A', 'B', 'a');

 

字符输入函数getchar

char c;

c = getchar();

getchar会将用户输入的字符赋值给变量c。

 

* getchar函数可以读入空格、TAB,直到遇到回车为止。scanf则不能读入空格和TAB。

 

* getchar一次只能读入一个字符。scanf则可以同时接收多个字符。

 

* getchar还能读入回车换行符,这时候你要敲2次回车键。第1次敲的回车换行符被getchar读入,第2次敲的回车键代表输入结束。

字符串处理函数包括在string.h文件中

strlen函数:测量一个字符串的字符数,非字符串长度

void test(){

         //测量字符串的字符长度(不包括\0这个字符)

         int len=strlen("lichunfu");

         printf("%d\n",len);

        

         int len1=strlen("李春福");

        

         printf("%d\n",len1);

        

         //测量字符串变量的字符长度

         char s[]="peter";

         printf("%d\n",strlen(s));

}

strcpy函数:将右边字符串中的内容copy到左边的字符串中

//strcpy:将右边字符串中的内容copy到左边的字符串中

void test1() {

         char left[10];

         strcpy(left,"peter");

         printf("%s", left);

}

strcat函数:把右边字符串添加到左边字符的后面

void test2(){

         char left[]={'l','c','f','\0'};

         strcat(left,"==>peter");

         printf("%s",left);

}

注意:遇到\0就结束字符串

strcmp函数:可以用来比较2个字符串的大小

两个字符串从左至右逐个字符比较(按照字符的ASCII码值的大小),直到字符不相同或者遇见'\0'为止。如果全部字符都相同,则返回值为0。如果不相同,则返回两个字符串中第一个不相同的字符ASCII码值的差。

即字符串1大于字符串2时函数返回值为正,否则为负

void test3(){

          int delta=strcmp("abc","Abc");

          printf("%d",delta);

}

返回的值为:1

strlwr函数:将字符串中大写字母转换成小写字母

strupr函数:将字符串中的小写字母转换为大写字母

指针

一个数据的“指针”就是它的地址,通过变量的地址能找到该变量在内存中的存储单元,从而能得到它的值

直接引用:就是通过变量名来直接引用变量,由系统自动完成变量名和其存储地址之间的转换;

间接引用:以变量a为例

首先将变量a的地址存放到另一个变量b中,然后通过变量b来间接引用变量a,间接读写变量a的值

用来存放变量地址的变量,就称为“指针变量“。

l  指针变量定义的形式: 类型标识符  *标识符

“标识符“就是指针变量的名字;

需要注意以下两点:

1、标识符前面的”*“,表示该变量为指针变量,比如: *person,其指针变量名是person,而不是*person

2、一个指针变量只能指向同一个类型的变量

常见的做法,以及错误写法

#include <stdio.h>

//错误做法一:

void worry1() {

         char *p;

         //应该在指针确定指向的变量后,再进行相应的操作

         p = 10;

}

//错误做法二:

void worry2() {

         char *p;

         //指针变量是用来存储变量地址的,不能随便赋值一个常数,除非你这个常数恰好是某个变量的地址

         p = 100;

}

 

int main(int argc, char **argv) {

         char a;

//a=10; 直接引用

//定义了一个指针变量b,而b只能指向char类型的变量

         char *b;

//让指针变量b指向a

         b = &a;

//这里的*b代表:访问b中存储的地址对应的存储空间(也就是变量a的存储空间)

//相当于a=10

         *b = 10;

         /**

          * char *b=&a

          * 相当于

          * char *b;

          * b=&a;

          */

         printf("%d\n", a);

//这里的*b相当于取出变量a的存储的值

         printf("%d\n", *b);

         return 0;

}

* 看下面的代码,利用指针p读取变量c的值

 

1 int i = 2;

2 char c = 1;

3

4 // 定义一个指向char类型的指针

5 char *p = &c;

6

7 // 取出

8 printf("%d", *p);

 

这个输出结果应该难不倒大家: ,是可以成功读取的。

* 如果我改一下第5行的代码,用一个本应该指向int类型变量的指针p,指向char类型的变量c

int *p = &c;

我们再来看一下输出: ,c的原值是1,现在取出来却是513,怎么回事呢?这个要根据内存来分析

根据变量的定义顺序,这些变量在内存中大致如下图排布:

其中,指针变量p和int类型变量i各占2个字节,char类型的c占一个字节,p指向c,因此p值就是c的地址

1> 最初的时候,我们用char *p指向变量c。当利用*p来获取变量c的值时,由于指针p知道变量c是char类型的,所以会从ffc3这个地址开始读取1个字节的数据:00000001,转为10进制就是1

2> 后来,我们用int *p指向变量c。当利用*p获取变量c的值时,由于指针p认为变量c是int类型的,所以会从ffc3这个地址开始读取2个字节的数据:00000010 0000 0001,转为10进制就是513

可见,给指针分类是多么重要的一件事,而且一种指针最好只指向一种类型的变量,那是最安全的。

指针与一维数组

指针变量可以指向整个数组,也可以指向数组元素

注意:C语言中规定p+1指向数组的下一个元素(而不是将p值简单地加1),而是增加的是该类型的字节数

a+1不一定代表着a值加2,究竟加多少,取决于数组的类型。a+i的计算方法与p+i相同。

其实,p+1不一定代表p的值加2,也可能是加1、加4或者加8。究竟加多少,这跟指针的类型有关。下图是在16位编译器环境下的情况。

聪明的你可能已经找到规律了,因为char类型的变量要占用1字节,所以p+1代表p的值加1float类型的变量占用4字节,所以p+1代表p的值加4。从这一点,也可以很好地说明为什么指针一定要分类型,不同类型的指针,p+1的含义是不一样的。

 

在遍历数组的过程中。如果*(p+i)则表示p的值没有改变过,如果是*(p++)则表示指针的值一直在改变

指针与数组的总结

p是指针,a是一个数组

1>如果p指向了一个数组元素,则p+1表示指向数组该元素的下一个元素。比如,假设p =&a[0],则p+1表示a[1]的地址

2>对于不同类型的数组元素,p值的改变是不同的。如果数组元素为int类型,p+1代表着p的值加上2(16位编译器环境下)

3>如果p的初值是&a[0],那么

·        p+ia+i都可以表示元素a[i]的地址,它们都指向数组的第i个元素。a代表数组首地址,a+i也是地址,它的计算方法与p+i相同

·        *(p+i)*(a+i)都表示数组元素a[i]

·        虽然p+ia+i都指向数组的第i个元素,但二者使用时还是有区别的。因为作为指针变量的p可以改变自身值,如p++,使p的值自增。而数组名a是一个代表数组首地址的常量,它的值是不能改变的,即a++是不合法的

4>引用一个数组元素可以有两种方法:

·        下标法:a[i]

·        指针法:*(p+i) *(a+i)

编译预处理

1.C语言在对源程序进行编译之前,会先对一些特殊的预处理指令作解释(比如之前使用的#include文件包含指令),产生一个新的源程序(这个过程称为编译预处理),之后再进行通常的编译

2.为了区分预处理指令和一般的C语句,所有预处理指令都以符号"#"开头,并且结尾不用分号

3.预处理指令可以出现在程序的任何位置,它的作用范围是从它出现的位置到文件尾。习惯上我们尽可能将预处理指令写在源程序开头,这种情况下,它的作用范围就是整个源程序文件

4.C语言提供的预处理指令主要有:宏定义文件包含条件编译

 

不带参数的宏定义   #define 标识符字符串

宏定义一般习惯用大写字母表示,以便与变量名区分。也可是使用小写字母表示

带参数的宏定义  #define 宏名(参数表)字符串

条件编译

在很多情况下,我们希望程序的其中一部分代码只有在满足一定条件时才进行编译,否则不参与编译(只有参与编译的代码最终才能被执行),这就是条件编译

#if 条件1

 ...code1...

#elif 条件2

 ...code2...

#else

 ...code3...

#endif

1> 如果条件1成立,那么编译器就会把#if与 #elif之间的code1代码编译进去(注意:是编译进去,不是执行,很平时用的if-else是不一样的)

2> 如果条件1不成立、条件2成立,那么编译器就会把#elif与 #else之间的code2代码编译进去

3> 如果条件1、2都不成立,那么编译器就会把#else与 #endif之间的code3编译进去

4> 注意,条件编译结束后,要在最后面加一个#endif,不然后果很严重(自己思考一下后果)

5> #if 和 #elif后面的条件一般是判断宏定义而不是判断变量,因为条件编译是在编译之前做的判断,宏定义也是编译之前定义的,而变量是在运行时才产生的、才有使用的意义

文件包含

一般形式:#include<文件名>     #include”文件名”

注意点:

1.#include指令允许嵌套包含,比如a.h包含b.h,b.h包含c.h,但是不允许递归包含,比如a.h 包含 b.h,b.h 包含 a.h。

2.使用#include指令可能导致多次包含同一个头文件,降低编译效率

使用此种写法可以提高效率

变量类型

C语言有丰富的数据类型和运算符,因此计算能力非常强大,计算过程中使用的值一般用变量来存储。变量也是有分类型的,不同类型的变量有不同的存储类型、不同的生命周期、不同的作用域,C语言也提供了一些关键字来设置变量的属性(比如设置存储类型、生命周期)。

变量的作用域

C语言根据变量作用域的不同,将变量分为局部变量和全局变量。

1.局部变量

1> 定义:在函数内部定义的变量,称为局部变量。形式参数也属于局部变量。

2> 作用域:局部变量只在定义它的函数内部有效,即局部变量只有在定义它的函数内部使用,其它函数不能使用它。

2.全局变量

1> 定义:在所有函数外部定义的变量,称为全局变量。

2> 作用域:全局变量的作用范围是从定义变量的位置开始到源程序结束,即全局变量可以被在其定义位置之后的其它函数所共享。

变量的存储类型

* 变量的存储类型就是指变量存储在什么地方。有3个地方可以用于存储变量:普通内存、运行时堆栈、硬件寄存器。变量的存储类型决定了变量何时创建、何时销毁以及它的值能保持多久,也就是决定了变量的生命周期。

 C语言根据变量的存储类型的不同,可以把变量分为:自动变量、静态变量、寄存器变量

自动变量

1> 定义:自动变量是存储在堆栈中的。

2> 哪些是自动变量:被关键字auto修饰的局部变量都是自动变量,但是极少使用这个关键字,基本上是废的,因为所有的局部变量在默认情况下都是自动变量。

3> 生命周期:在程序执行到声明自动变量的代码块(函数)时,自动变量才被创建;当自动变量所在的代码块(函数)执行完毕后,这些自动变量就会自行销毁。如果一个函数被重复调用,这些自动变量每次都会重新创建。

静态变量

1> 定义:静态变量是存储在静态内存中的,也就是不属于堆栈。

2> 哪些是静态变量:

  • 所有的全局变量都是静态变量
  • 被关键字static修饰的局部变量也是静态变量

3> 生命周期:静态变量在程序运行之前创建,在程序的整个运行期间始终存在,直到程序结束。

寄存器变量

1> 定义:存储在硬件寄存器中的变量,称为寄存器变量。寄存器变量比存储在内存中的变量访问效率更高(默认情况下,自动变量和静态变量都是放在内存中的)

2> 哪些变量是寄存器变量:

  • 被关键字register修饰的自动变量都是寄存器变量
  • 只有自动变量才可以是寄存器变量,全局变量和静态局部变量不行
  • 寄存器变量只限于int、char和指针类型变量使用

3> 生命周期:因为寄存器变量本身就是自动变量,所以函数中的寄存器变量在调用该函数时占用寄存器中存放的值,当函数结束时释放寄存器,变量消失。

4> 使用注意:

  • 由于计算机中寄存器数目有限,不能使用太多的寄存器变量。如果寄存器使用饱和时,程序将寄存器变量自动转换为自动变量处理
  • 为了提高运算速度,一般会将一些频繁使用的自动变量定义为寄存器变量,这样程序尽可能地为它分配寄存器存放,而不用内存

·        static 、extern与函数

两个概念

extern外部函数:如果在当前文件中定义的函数允许其他文件访问、调用,就称为外部函数。C语言规定,不允许有同名的外部函数。

static内部函数:如果在当前文件中定义的函数不允许其他文件访问、调用,只能在内部使用,就称为内部函数。

C语言规定不同的源文件可以有同名的内部函数,并且互不干扰

·        static、extern与函数的总结

1.static

* 在定义函数时,在函数的最左边加上static可以把该函数声明为内部函数(又叫静态函数),这样该函数就只能在其定义所在的文件中使用。如果在不同的文件中有同名的内部函数,则互不干扰。

* static也可以用来声明一个内部函数

2.extern

* 在定义函数时,如果在函数的最左边加上关键字extern,则表示此函数是外部函数,可供其他文件调用。

C语言规定,如果在定义函数时省略extern,则隐含为外部函数。

* 在一个文件中要调用其他文件中的外部函数,则需要在当前文件中用extern声明该外部函数,然后就可以使用,这里的extern也可以省略。

·        static和extern的总结

1.extern可以用来声明一个全局变量,但是不能用来定义变量

2.默认情况下,一个全局变量是可以供多个源文件共享的,也就说,多个源文件中同名的全局变量都代表着同一个变量

3.如果在定义全局变量的时候加上static关键字,此时static的作用在于限制该全局变量的作用域,只能在定义该全局变量的文件中才能使用,跟其他源文件中的同名变量互不干扰

结构体

二、结构体的定义

 

1.定义形式

 结构体内部的元素,也就是组成成分,我们一般称为"成员"。

 

结构体的一般定义形式为:

 struct 结构体名{         

 类型名1 成员名1;

         类型名2 成员名2;

           ……

         类型名n 成员名n;   

};

 

struct是关键字,是结构体类型的标志。

三种定义方式:

1.先定义结构体类型,再定义变量

struct Student {

     char *name;

    int age;

 };

 struct Student stu;

变量名为stu。struct和Student是连着使用的。 

2.定义结构体类型的同时定义变量

struct Student {

    char *name;

    int age;

} stu;

结构体变量名为stu

3.直接定义结构体类型变量,省略类型名

struct {

    char *name;

    int age;

} stu;

结构体变量名为stu

指向结构体的指针

 每个结构体变量都有自己的存储空间和地址,因此指针也可以指向结构体变量

* 结构体指针变量的定义形式:struct结构体名称 *指针变量名

* 有了指向结构体的指针,那么就有3种访问结构体成员的方式

结构体变量名.成员名

(*指针变量名).成员名

指针变量名->成员名

枚举enum

枚举是C语言中的一种基本数据类型,并不是构造类型,它可以用于声明一组常数。当一个变量有几个固定的可能取值时,可以将这个变量定义为枚举类型。

比如,你可以用一个枚举类型的变量来表示季节,因为季节只有4种可能的取值:春天、夏天、秋天、冬天。

·        枚举的定义:三种方式

1.先定义枚举类型,再定义枚举变量

enum Season {spring, summer, autumn, winter};

enum Season s;

 

2.  定义枚举类型的同时定义枚举变量

enum Season {spring, summer, autumn, winter} s;

3.省略枚举名称,直接定义枚举变量

enum {spring, summer, autumn, winter} s;

上面三种方式定义的都是枚举变量s

注意点:

1> C语言编译器会将枚举元素(spring、summer等)作为整型常量处理,称为枚举常量。

2> 枚举元素的值取决于定义时各枚举元素排列的先后顺序。默认情况下,第一个枚举元素的值为0,第二个为1,依次顺序加1。

enum Season {spring, summer, autumn, winter};

也就是说spring的值为0,summer的值为1,autumn的值为2,winter的值为3

3> 也可以在定义枚举类型时改变枚举元素的值

enum season {spring, summer=3, autumn, winter};

没有指定值的枚举元素,其值为前一元素加1。也就说spring的值为0,summer的值为3,autumn的值为4,winter的值为5

枚举的遍历

enum Season {spring, summer, autumn, winter} s;

// 遍历枚举元素

for (s = spring; s <= winter; s++) {

    printf("枚举元素:%d \n", s);

}

typedef

使用typedef关键字为各种数据类型定义一个新名字(别名)

也可以在别名的基础上再起一个别名

最后,如果对你有所帮助的话,就帮忙顶下吧!!!

0 0