欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

c笔记——重学c

程序员文章站 2022-06-07 19:15:23
...

        大二时候学过c了,谭浩强的那个版本,还有算法,数据结构(很厚的一本书,而且是英文的)等等。虽然我不是计算机专业的,却要学这些,实在辛苦。而且当时没电脑,其他各科课程也很难学,学这个更是打击我们的自信心,也真搞不懂学校的课程安排。—— 不过还好,这个激起了我对计算机的兴趣,虽然不是很好,但我还是考了个专业第二名的成绩。我自学数据库并参加通过的相关的计算机考试。更奇妙的是,我毕业后竟然鬼使神差的走上了程序员的这条“不归路” c笔记——重学c
            
    
    博客分类: c  

        毕业后就是一直做java方面的工作。主要是java、flex。因为都是外包项目,学到的东西确实很少。做了这么久,感觉实在郁闷:上班沉闷,加班多,成长少。最近考虑要不要继续搞java web了,于是捡起了当年的c来复习一下。下面为个人的一些c的非常基础的笔记,各位有经验的就不用看了。否则也是浪费时间。先记下,以后再整理。

 


1 c概述
1.1 背景
不同版本的C编译系统所实现的语言功能和语法规则又略有差别

1.2 特点
运算符丰富。34种运算符
具有结构化的控制语句 ,是完全模块化和结构化的语言
语法限制不太严格,程序设计*度大
允许直接访问物理地址,能进行位操作,能实现汇编语言的大部分功能,可直接对硬件进行操作。兼有高级和低级语言的特点
目标代码质量高,程序执行效率高。只比汇编程序生成的目标代码效率低10%-20%。
程序可移植性好(与汇编语言比)。基本上不做修改就能用于各种型号的计算机和各种操作系统
1.3 基本语法
每个C程序必须有一个主函数main ——C程序总是从main函数开始执行的,与main函数的位置无关
{ }是函数开始和结束的标志,不可省
每个C语句以分号结束
使用标准库函数时应在程序开头一行写:#include <stdio.h>

注释:/*……*/表示注释,或//……

C程序是由函数构成的。 这使得程序容易实现模块化
一个函数由两部分组成:  函数的首部;函数体--------- 在c主函数main中使用前必须先定义或声明


=======  编辑产生f.c —— 编译生成目标程序 —— f.obj —— 链接 库函数/其他目标程序 —— 生成可执行程序 f.exe

1.4 ide —— Turbo C ++ 、 Visual C++

 


2 算法

结构化程序设计方法
自顶向下
逐步细化
模块化设计
结构化编码

两种不同的方法:
自顶向下,逐步细化;
自下而上,逐步积累。

3.1 C的数据类型

A 基本类型: 注意其在内存中的存储方式
整型6种 int  short long 、再每种加上unsigned
字符型 char ———— 无字符串类型,虽然有字符串的概念
实型(浮点型) 单精float、双精double


B 构造类型:
数组类型
结构类型 struct
联合类型 union
枚举类型 enum

C 指针类型

D 空类型(无值类型) void

3.2 变量
变量代表内存中具有特定属性的一个存储单元,它用来存放数据,这就是变量的值,在程序运行期间,这些值是可以改变的。

变量名实际上是一个以一个名字对应代表一个地址,在对程序编译连接时由编译系统给每一个变量名分配对应的内存地址。
从变量中取值,实际上是通过变量名找到相应的内存地址,从该存储单元中读取数据。

与java不同的是,c的变量名不能包含$符号


如果在程序中定义了一个变量,在对程序进行编译时,系统就会给这个变量分配内存单元。


变量(复杂变量),其实就是对应一个内存地址—— c,java等语言,都是这样的!! (变量本身被藏在一个临时堆栈区?)

取变量值?在c中, 一般来说,有两种方式,
1、通过变量,再去获取其内存地址
2、如果已经直接知道内存地址(不是通过&v的方式),则直接获取。


变量v的内存地址
为了方便通过v获取其内存地址,我们规定变量 &v 即为v的内存地址。 作为一个标记

 


整型数据---内存中以二进制码存放
浮点型-----浮点型数据是按照指数形式存储的。系统把一个浮点型数据分成小数部分和指数部分,分别存放。指数部分采用规范化的指数形式。
char-------ASCII码
字符串 ----- C规定以字符’\0’作为字符串结束标志,,
"china"------它占内存单元不是5个字符,而是6个字符,最后一个字符为’\0’。但在输出时不输出’\0’。

u
int
u int?
l
d
f

一个字符数据
既可以以字符形式输出,也可
以以整数形式输出


基本类型变量不需声明(系统已经声明好了),使用时需要定义;

函数        需要声明,也需要定义,才能使用

=================================================变量的初始化================================================


整型(包括int,short,long)、浮点型(包括
float,double)可以混合运算。在进行运算时
,不同类型的数据要先转换成同一类型,然后
进行运算.

 

(9)求字节数运算符(sizeof)
(10)强制类型转换运算符( (类型) )
(11)分量运算符(.->)
(12)下标运算符([ ])
(13)其他 (如函数调用运算符())

 


hanno问题

 

========================  全局变量 ======================
在函数内定义的变量是局部变量,而在函数之外定义的变量称为外部变量,外部变量是全局变量(也称全程变量)。
全局变量可以为本文件中其他函数所共用。它的有效范围为从定义变量的位置开始到本源文件结束


===========  变量的存储类别 ====================
---------- 在C语言中每一个变量和函数有两个属性:数据类型和数据的存储类别
==========从变量值存在的时间(即生存期)角度来分,又可以分为静态存储方式和动态存储方式。
存储方式分为两大类:静态存储类和动态存储类。具体包含四种:自动的(auto),静态的(static),寄存器的(register),外部的(extern)


auto 默认为动态, 同java里面的类的普通属性
static  ---------- 同java的static    静态局部变量属于静态存储类别,在静态存储区内分配存储单元。在程序整个运行期间都不释放
register        C语言允许将局部变量的值放在CPU中的寄存器中,变量叫做寄存器变量
extern            用extern声明外部变量,扩展它在程序文件中的作用域------- 用于调用别的c源文件中定义的变量
   --- 外部变量也可以在本文件中定义, 也可以在别的文件中定义
   ---编译时将外部变量分配在静态存储区

 

 

 

 


表达式


4 c语句
printf()
scanf(“%d″,&n);----  把终端输入数据赋值到 变量n的地址里去----- 即使 n = 输入值


5 选择程序设计 --- 运算符的优先级


关系运算符的优先级低于算术运算符
关系运算符的优先级高于赋值运算符
!(非)->&&()->||()
逻辑运算符中的“&&”和“||”低于关系运算符,“!”高于算 术运算符


C语言中没有专用的逻辑值,1代表真,0代表假  ———— 任何非零的数值被认作“真”


6 循环


7 数组
定义: 是一组具有相同数据类型的数据的有序集合。

C语言中数组名代表该数组的起始地址


二维数组
如果对全部元素都赋初值,则定义数组时对第一维的长度可以不指定,但第二维的长度不能省

多维
在定义时也可以只对部分元素赋初值而省略第一维的长度,但应分行赋初值


字符数组:
如果在定义字符数组时不进行初始化,则数组中各元素的值是不可预料的

如果花括弧中提供的初值个数(即字符个数)大于数组长度,则按语法错误处理。

如果初值个数小于数组长度,则只将这些字符赋给数组中前面那些元素,其余的元素自动定为空字符(即′\0′)

如果提供的初值个数与预定的数组长度相同,在定义时可以省略数组长度,系统会自动根据初值个数确定数组长度

也可以定义和初始化一个二维字符数组


为了测定字符串的实际长度,C语言规定了一个“字符串结束标志”,以字符′\0′作为标志
系统对字符串常量也自动加一个′\0′作为结束符。


字符数组的输入输出可以有两种方法:
逐个字符输入输出。用格式符“%c”输入或输出一个字符。
将整个字符串一次输入或输出。用“%s”格式符,意思是对字符串的输入输出。


字符串处理函数
puts
gets

scanf
gets

strcat(字符数组1,字符数组2)
strcpy(字符数组1,字符串2) 字符数组1必须定义得足够大,以便容纳被复制的字符串。字符数组1的长度不应小于字符串2的长度。—————— 否则。。
 “字符数组1”必须写成数组名形式(如str1),“字符串2”可以是字符数组名,也可以是一个字符串常量
strcmp(字符串1,字符串2) 
 注意:对两个字符串比较,不能用以下形式:
  if(str1>str2) printf(″yes″);
 而只能用
  if(strcmp(str1,str2)>0) printf(″yes″);

strlen (字符数组)  函数的值为字符串中的实际长度(不包括′\0′在内)
strlwr (字符串)
strupr (字符串)

不能用赋值语句将一个字符串常量或字符数组直接给一个字符数组
而只能用strcpy函数将一个字符串复制到另一个字符数组中去

 

 

8 函数
所有函数都是平行的,即在定义函数时是分别进行的,是互相独立的。
一个函数并不从属于另一函数,即函数不能嵌套定义。
函数间可以互相调用,但不能调用main函数。main函数是系统调用的。


定义空函数的一般形式为:
类型标识符 函数名() { }


在定义函数时指定的函数类型一般应该和return语句中的表达式类型一致。———— 
在C语言中,凡不加类型说明的函数,自动按整型处理。例8.2中的max函数首行的函数类型int可以省写,用Turbo C 2.0编译程序时能通过,
但用Turbo C++ 3.0编译程序时不能通过,因为C++要求所有函数都必须指定函数类型。因此,建议在定义时对所有函数都指定函数类型。


如果使用库函数,还应该在本文件开头用#include命令将调用有关库函数时所需用到的信息“包含”到本文件中来。
如果使用用户自己定义的函数,而该函数的位置在调用它的函数(即主调函数)的后面(在同一个文件中),应该在主调函数中对被调用的函数作声明
如果  被调用函数的定义出现在主调函数之前,可以不必加以声明。因为编译系统已经先知道了已定义函数的有关情况,会根据函数首部提供的信息对函数的调用作正确性检查。

函数的“定义”和“声明”不是一回事


8.8 局部变量和全局变量
在一个函数内部定义的变量是内部变量,它只在本函数范围内有效,也就是说只有在本函数内才能使用它们,在此函数以外是不能使用这些变量的。这称为“局部变量”。
———— 形式参数也是局部变量
可以在复合语句中定义变量,这些变量只在本复合语句中有效 ———— “更局部的局部”


而在函数之外定义的变量称为外部变量,外部变量是全局变量(也称全程变量)。全局变量可以为本文件中其他函数所共用。它的有效范围为从定义变量的位置开始到本源文件结束。

 


那么从变量值存在的时间(即生存期)角度来分,又可以分为静态存储方式和动态存储方式。


====================  函数 ===========================

有参函数
无参函数

在定义函数时函数名后面括弧中的变量名称为“形式参数”(简称“形参”)-----只有在发生函数调用时,函数max中的形参才被分配内存单元
在主调函数中调用一个函数时,函数名后面括弧中的参数(可以是一个表达式)称为“实际参数”(简称“实参”)
---实参与形参的类型应相同或赋值兼容


---在C语言中,实参向对形参的数据传递是“值传递”,单向传递---------调用结束后,形参单元被释放,实参单元仍保留并维持原值


——对于不带回值的函数,应当用“void”定义函数为“无类型”(或称“空类型”)


void main() 的void可省去??

 

========对于函数调用 int i=2,p; p=f(i,++i);   p里面的i的求值顺序是不确定的,因c编译环境而已,应该避免这种写法!!!
如果使用用户自己定义的函数,而该函数的位置在调用它的函数(即主调函数)的   &&&&后面(在同一个文件中),&&&&
-----------应该在主调函数中对被调用的函数作声明。

 


8.10
函数本质上是全局的,因为一个函数要被另外的函数调用,但是,也可以指定函数不能被其他文件调用。根据函数能否被其他源文件调用,将函数区分为内部函数和外部函数。
在定义内部函数时,在函数名和函数类型的前面加static

在定义函数时,如果在函数首部的最左端加关键字extern,则表示此函数是外部函数,可供其他文件调用
C语言规定,如果在定义函数时省略extern,则隐含为外部函数
———— 在需要调用此函数的文件中,用extern对函数作声明,表示该函数是在其他文件中定义的外部函数

 

9 预处理命令

C提供的预处理功能主要有以下三种:
  1.宏定义  #define  #undef
  2.文件包含  #include
  3.条件编译
  (1) #ifdef 标识符
   程序段1
   #else
         程序段2
   #endif
(2) #ifndef 标识符
       程序段1
 #else
       程序段2
 #endif


(3) #if 表达式
        程序段1
  #else
        程序段2
  #endif


=============   格式宏做成头文件 

 


10 指针

指针,一个变量的地址称为该变量的“指针”
指针,一般简单的习惯的说,也就是 指针变量 ??————————————————————————
————————————————————————————————————————————“""""""""  在C语言中,指针是一种特殊的变量,它是存放地址的  """"""""”   专门仅仅用来存放地址的!!!

指针变量,指向内存地址的变量,其值永远都是一个类似 内存地址的数值,如类似 1122。————————————————————-  变量v所占用单元的起始地址
但是指针也有类型,与其所指的内存地址对应变量的类型 一致!!!

所以,指针类型变量的定义方式比较特别,我们通过 * 来 标识::: 基类型  *指针变量名

所以,它的定义方法 类似是: int *point_int;


使用方式:
因为它是用来 存放地址 的,所以,我们可以把一个对应的类型变量的地址 给它
如:
int inte = 12345;
int *point_int;
point_int = &inte;

那么point_int的值就是inte的地址了!!!!

 


使用场合???

 

作为定义/运算变量相关的  *和&  的区别

* 用于定义和运算!,运算的时候:::::通常是 * 后面跟一个地址,可表示一个变量,值为这个地址里面的值!!—————— 亦即表示一般常规变量
& 用于运算,不参与定义,与上相反!!!

a为int变量
*&a  与a等价,a可以为指针吗,可以;a可以是指针的指针类型吗?可以!
&*a  与a—— 假设a为指针,设普通变量v的地址:a=&v,则*a = v,&*a = &v = a ? —————— 前提是a必须是指针,否则运行时出错!

 

经验证,*&a  与a等价,但&*a  与a不一定,因为取址运算&的普遍可行的,而指向运算*只能针对指针类型变量

 

 

指向函数的指针
int  max(int,int);--- /* 函数声明 */
int (*p)();----------- 此即 指向函数的指针!!
int a,b,c;
p=max;
scanf(″%d,%d″,&a,&b);
c=(*p)(a,b);------- 指向函数的指针  的使用

 


返回指针值的函数
其概念与以前类似,只是带回的值的类型是指针类型而已

 

用指向函数的指针作函数参数
--- 指向函数的指针也可以作为参数,以实现函数地址的传递,这样就能够在被调用的函数中使用实参函数

 


指针数组
一个数组,若其元素均为指针类型数据,称为指针数组


指向指针的指针

 

指针的运算:

指针变量加(减)一个整数
。。。
。。。


假设int a = 1;int *p1; p1 = &a;
那么 *p1 = 2 使指向值为2的对应的内存地址??
不是。实际上 *p1 就是a, *p1 = 2 相当于 a=2 ,是给 a对应的内存地址的内容重新赋值!!!!!


假设p1,p2都为指针,p1 = &a ,p2 = &b; a = 1; b = 2;则:
*p1=*p2;

在这个过程中,先求出*p2的值(即b的值2),作为一个值存在,  然后求 *p1 作为一个变量 a存在,然后才是赋值 ,将2赋给a!!!!
表示 将b的值赋给a,------------  修改a的值,而不是它对应的地址,a对应的地址是永远不变的!!  —————————— a的值发生变量,b的值不变  !!!!

 

字符指针变量 ____  即字符数组!
----------
虽然用字符数组和字符指针变量都能实现字符串的存储和运算,但它们二者之间是有区别的,不应混为一谈,主要有以下几点

字符数组由若干个元素组成,每个元素中放一个字符,而字符指针变量中存放的是地址(字符串第1个字符的地址),决不是将字符串放到字符指针变量中。
赋值方式。对字符数组只能对各个元素赋值,不能用以下办法对字符数组赋值。
。。。

 


11 结构体与共用体


结构:struct
将不同类型的数据组合成一个有机的整体,以便于引用,相当于java里面的class


声明一个结构体类型的一般形式为:
 struct    结构体名
{成员表列};


定义结构体类型变量的方法,有3种,分别是:
1 先声明,后定义。---- 搞清声明、定义的区别—————— 定义是要分配内存的!

2 在声明类型的同时定义变量

3 直接定义结构体类型变量
其一般形式为:
      struct
        {
       成员表列
      }变量名表列;
即不出现结构体名。

枚举

typedef

typedef的使用
http://www.cnblogs.com/obama/archive/2013/03/14/2958983.html


① 结构体变量.成员名
②(*p).成员名
p->成员名

 

共用体的概念
  使几个不同的变量共占同一段内存的结构称为
“共用体”类型的结构.

定义共用体类型变量的一般形式为:
union 共用体名

 成员表列
}变量表列;

 

 

对于编译器而言,遇到宏是直接替换而不会做任何其它动作的。此题中Area(R) pi*R*R, 而R赋值为r1-r2, 所以预编译后的结果为:
   pi*r1-r2*r1-r2, 计算结果为3.700000

 

12 位运算


13  文件

============    文件    ============

存放格式?和后缀?什么关系呢?
存放格式 有哪些呢
ASCII文件

 

总结
------------------  要深刻 理解 “=”就是赋值运算的 含义 !!  对右边(常量也好,表达式也好,值也好,,,等等 )求值,赋给左边变量 !
------------------  左边不能是常量,值为常量的表达式!只能是变量、值为变量的表达式  !!!
(a=3*5)=4*3

左值 (lvalue) : 赋值运算符左侧的标识符
变量可以作为左值;
而表达式就不能作为左值(如a+b);
常变量也不能作为左值, 

右值 (lvalue) :出现在赋值运算符右侧的表达式
     左值也可以出现在赋值运算符右侧,因而左值
  都可以作为右值。

 

一个普通变量、指针类型变量对应的地址是永远不变的, 变化的永远只是其里面的 值!!!  普通变量、指针都是这样!!! 指针是这样吗?还有点疑问

 

一个结构类型变量如果不给其进行赋值操作,它的地址也是不会变的!

内存区的每一个字节有一个编号,这就是“地址” 。

 

重点难点当然就是在于指针。时而理解了,时而又迷糊了。其实指针变量取值也就是比普通变量多了个 寻址的步骤: 普通变量寻址一次,指针变量寻址两次,正是* 表示了第二次的寻址操作

*符号大量出现于c文件中,一定要搞清楚,而且有一个烦人的易搞错重载的乘号“ * ” 应该注意*到底是表示指针还是乘法!