大一上C语言基础笔记
C语言知识点整理
一、 C语言简介
1、 特点
- ·结构化的程序语言(函数、程序的分割)
- ·有丰富的数据类型(44种运算符)
- ·结构紧凑,使用方便(语法限制不大严格,自由度高)
- ·具有自我扩充的能力(函数库的扩充)
- ·有低级语言功能(可直接访问物理地址)
- ·可移植性强(可在不同系统间运行)
- ·面向过程(C++面向对象)
2、 历史:CPL>>BCPL>>B>>C>>C#
3、 关键字(保留字):类型说明(int等)、语句定义(if等)、储存说明(static等)、sizeof(长度运算符)
4、 标识符:用户自定义的各类对象(变量、函数等)的名称
规则:·由字母、下划线及数字组成,且必须由前二者开头
·不能与关键字或已定义函数同名
·大小写敏感(区分大小写)
·要求顾名知义
·不易混淆
5、 运行与调试
- ·不带调试的运行(空心三角;Ctrl+F5):运行到最后暂停(按任意键退出)
- ·带调试的运行(实心三角;F5):在断点和出错时暂停(shift+F5退出调试,F5继续调试),可在暂停时查看局部变量的值
- ·生成文件的运行(文件夹Debug中的EXE文件,遇错强退,运行至最后不暂停)
类型 |
关键字 |
字节数 |
表示范围 |
整型 |
short |
2 |
-32768~32767 |
int |
4 |
(-231 ~ 231-1) |
|
long int |
4 |
(-231 ~ 231-1) |
|
实型 |
float |
4 |
-3.4×10-38 ~ 3.4×1038 |
double |
8 |
-1.7×10-308 ~ 1.7×10308 |
|
long double |
8 |
-1.7×10-308 ~ 1.7×10308 |
|
字符类型 |
char |
1 |
-128~127 |
6、 注释(//以后的本行内容或/*与*/之间的内容)
- ·注释不被程序执行,方便读程序用;
- ·复杂的程序应当养成写注释的习惯;
二、 数据类型
1、 数据类型
- ·分类:基本类型(整型、实型、字符类型)、构造类型(数组、结构体、共用体、枚举类型)、指针类型与空类型
- ·字符类型(char)只能储存单字符
- ·基本类型及其储存字节数和表示范围(右图,VS2010)
拓:机器字长:CPU一次能处理数据的位数,通常与CPU的寄存器位数有关。
存储字长:存储器中一个存储单元(存储地址)所存储的二进制代码的位数,
指令字长:计算机指令字的位数。
数据字长:计算机数据存储所占用的位数。
存储字长取决于机器字长
- ·整型和字符类型存在无符号(unsigned)形式,即记录储存非负数
- ·除表中列举外,实型还有一类为指数型
指数形式是浮点数的一种表示方法;
指数形式,即科学计数法。其形式为:aEb;
代表a乘10的b次幂。 E也可以是小写,b必须为整数;
指数形式在输出的时候,可以指定浮点数输出为指数形式,格式为%e或%E,
区别为输出的指数形式浮点数E为小写或者大写;
如printf(“%e”, 100000.0),会输出1.000000e+05。
- ·数组即为某一类变量的有序集合,如name[10]就表示10个(0到9)同型变量
- ·特别的,char型的数组即为字符串
- ·结构体为不同类型变量的集合
- ·指针保存的是地址,其类型名表示其保存地址对应的变量的类型
- ·不同数据类型的变量溢出后,都会在其变量取值内循环,而不是报错
2、 变量的定义
- ·基本格式:类型名 变量名(=初值)(如int sum=3)
(不能int x1=x2=0; 但可以int x1,x2; x1=x2=0;)
- ·用逗号可以同时定义多个同型变量,但改变变量类型时需用分号
- ·定义变量时可不赋初值,则变量初始值不定(VS2010中为-858993460)
- ·数组定义:类型名 变量名[长度](={······} 或 “xxxxx”)
- ·数组长度可使用整形常量或整形常量表达式,但不能使用变量
- ·一维数组定义时若赋初值则可不规定长度,以输入数的个数为数组长度
- ·一维数组定义时若同时规定长度和赋初值,则顺序赋值,不足的赋为0
·引用越界的数组数(如int x[10] = { 1,2,3,4 }; printf(“%d”, x[10]);)
编译时不报错,运行时出错,x[10]是一个随机数(即上一次栈遗留的数或者未初始化的数)
- ·C语言只能单个引用数组元素而不能一次引用整个数组(待定,答案认为正确,实际讨论结果认为错误)
- ·数组内存大小取决于数据类型和定义的元素个数(不是已赋值的元素个数)
- ·高维数组的长度规定方式为[lenth1][lenth2]···其初值赋值方式有{A}和{{B},{C}··}两种。以二维数组array[2][5]为例,前者按[0][0] , [0][1]···[0][4] , [1][0]···[1][4]的行顺序赋值,后者{B}赋给array[0],{C}赋给array[1]。
- ·高维数组的赋值省略规则同一维数组,但只有[lenth1]可省略
- ·结构体定义:struct+结构名{类型名+成员名(=初值); 类型名+成员名(=初值);}
- ·结构体中的成员可以是任何类型的变量(包括结构体变量)
例:struct student {char name[10]; long number; float score;}
- ·同一函数内同一变量名不能重复定义,但可以与全局变量重名
3、 变量的调用与范围
- ·普通变量直接调用(auto int)
- ·数组:数组名[lenth1][lenth2]···
- ·结构体:结构名.成员名
- ·指针见后文
- ·变量的调用必须在变量的定义语句后
按作用域分:
- ·局部变量(函数内定义)只能在本函数初内被调用/修改
- ·全局变量(函数外定义)可以在所有函数内被调用/修改
生存期是从定义该变量的位置开始至源文件结束。
- ·全局变量与局部变量重名时局部变量优先
按存储方式分:
- ·自动变量(auto):
- ·静态变量(static):在整个程序运行过程中仅赋值一次
ü 静态局部变量:保存在全局数据区,而不是保存在栈中,每次的值保持到下一次调用,直到下次赋新值。 静态局部变量的用途有许多:可以使用它确定某函数是否被调用过。 C语言中静态变量只能被初始化一次,下次即使程序执行到初始化语句也会忽略
ü 静态全局变量:使得该变量成为定义该变量的源文件所独享。(非静态全局变量是如果在一个文件中使用extern关键字来声明另一个文件中存在的全局变量,那么这个文件可以使用这个数据。)
寄存器变量(register):存储在CPU中,容量小,速度快
4、 常量(#define)
- ·实质是预编译语句而非C语句,确定的是替换关系
- ·有全局常量和局部常量之分,与变量规则相同
- ·常量可在其范围内被调用,但不能在此过程中被修改
- ·常量使用的优点:方便修改程序参数
5、 数据的输入
- ·十进制数整型:正常输入
- ·八进制数整型:以0开头,后接八进制数(注意:是零,下同)
- ·十六进制数整型:以0x或0X开头,后接十六进制数(大小写不敏感)(最大为f)
- ·长整型:后缀L或l,可以是以上三种进制整型数
- ·无符号整型:后缀U或u,可以是以上三种进制及长整型(LU)
- ·实型(浮点数)小数形式:有小数点才算实型,小数点前后可省略至多一处
- ·实型指数形式:即科学计数法,E代表×10,前置十进制数,后置十进制整数
- ·(单)字符常量:’ ’内接单个普通字符或转义字符
- ·字符串常量:” ”内接单或多个普通字符或转义字符
- ·合法转义字符(ASCII码):
·:退格(8)
·
:换行(10)
·f:换页
·:回车
· :水平制表
·v:垂直制表
·’:单引号
·”:双引号
·?:问号
· :反斜线(92)
·ddd:1至3位八进制数对应的字符(特别的,代表空字符,即终止符)
·xhh:1至2位十六进制数对应的字符(如:x41即101,表示A)
·%的输出为’%%’
6、 数据类型的转换
- ·显式转换(强制转换):(类型名)表达式,类型名的括号不可省略
- ·隐式转换:非显式转换,包括运算转换、赋值转换(转换为左值类型)、输出转换、函数调用转换(如sqrt、pow函数返回值是double)
- ·显式转换可能导致精度丢失,如由实型到整型时会导致小数点丢失(不四舍五入)。值得注意的是:向char型后保留的是0到255内的数(先取整再对256取余)
- ·隐式转换的规则:(short int、char)int–>unsigned int–>long–>double(float)其中括号内必然向外转换,其他从左向右转换
三、 运算符与表达式
优先级 |
结合性 |
名称 |
符号或关键字 |
输入值(左) |
输入值(右) |
返回值 |
1 |
左 |
圆括号 |
() |
|
|
|
下标 |
[] |
|
|
|
||
2 |
右 |
逻辑非 |
! |
|
常量或表达式 |
!0=1;!(其他)=0 |
负号 |
– |
|
常量或表达式 |
相反数 |
||
自增/减(A) |
++ — |
变量 |
|
|||
强制类型转换 |
(类型名) |
|
常量或表达式 |
规定类型对应数 |
||
间接引用 |
* |
|
地址 |
对应的值 |
||
取地址符 |
& |
|
变量或数组名 |
对应的地址 |
||
长度运算符 |
Sizeof |
|
类型名 |
类型长度 |
||
3 |
左 |
算术运算符(B) |
* / %(取余) |
常量或表达式 |
常量或表达式 |
数学运算值 |
+ – |
常量 或表达式 |
常量或表达式 |
数学运算值 |
|||
4 |
左 |
关系运算符 |
< <= > >= |
常量或表达式 |
常量或表达式 |
真即1,假即0 |
5 |
左 |
== != |
常量或表达式 |
常量或表达式 |
真即1,假即0 |
|
6 |
左 |
逻辑运算符(C) |
&&(逻辑与) |
常量或表达式 |
常量或表达式 |
一假则假,同真为真 |
7 |
左 |
||(逻辑或) |
常量或表达式 |
常量或表达式 |
一真则真,同假为假 |
|
8 |
右 |
条件运算符 |
(条件)?(选择1):(选择2) |
常量或表达式 |
常量或表达式 |
真取左,假取右 |
9 |
右 |
赋值运算符(D) |
= 及其扩展 (复合运算符) |
常量或表达式 |
常量或表达式 |
修改后的左值 |
10 |
左 |
逗号运算符 |
, |
常量或表达式 |
常量或表达式 |
最右边表达式的值 |
1、 常用运算符:
(计算时先进行高优先级计算,同优先级计算顺序由结合性决定)
A、变量在左则执行计算后自增/减,反之先自增/减后执行计算
B、取余要求两边均为整型,除号两侧均为整数则执行整除
C、自增自减整型实型变量皆可。
C、&&左为假则不执行右侧表达式,||左为真亦不执行右侧表达式
D、运算符=及其拓展要求左值可修改(不能是表达式、常量、数组名等),
=的拓展即为+=等,x+=b即为x=x+b
2、 表达式:变量、常量以及运算符的组合,按上述规律运算
拓:逗号表达式:从左往右一次执行语句,以逗号作为分界,最后返回最后一个语句的值
3、 表达式语句:在表达式后加分号构成语句
4、 表达式的真值:0为假,非零为真(!!-1=1)
5、 易错:表示a不等于0的关系是!a(×),是a(√)
6、 尤其注意‘=’和‘==’!它们的返回值不同
四、 常用函数及其头文件
头文件 |
名称 |
函数名 |
形参格式(a, b··) |
返回值格式 |
功能 |
返回值 |
|
stdio .h |
格式化输入 |
scanf |
char*等 |
int |
按格式输入 |
成功赋值的个数 |
|
格式化输出 |
printf |
char*等 |
int |
按格式输出 |
输出的字符数 |
||
单字符输入 |
getchar |
|
int |
输入单个字符 |
输入字符的ASCII |
||
单字符输出 |
putchar |
Char |
int |
输出单个字符 |
输出字符的ASCII |
||
字符串输入 |
gets |
char* |
char* |
输入字符串 |
输入的字符串 |
||
字符串输出 |
puts |
char* |
int |
输出字符串 |
是否成功输出 |
||
math .h |
取绝对值 |
(f)abs |
double/int |
double/int |
求a的绝对值 |
见左 |
|
取算数平方根 |
sqrt |
double |
double |
求a的算数平方根 |
见左 |
||
取n次方值 |
pow |
double, double |
double |
求a的b次方 |
见左 |
||
string .h |
字符串连接 |
strcat |
char*, char* |
char* |
连接并保存在前者 |
修改后的前形参 |
|
字符串复制 |
strcpy |
char*, char* |
char* |
将后者拷贝到前者 |
修改后的前形参 |
||
字符串比较 |
strcmp |
char*, char* |
int |
比较两字符串 |
异±1同0 |
||
字符串长度 |
strlen |
char* |
int |
求字符串长度 (不包括’’,sizeof包括)’’】 |
见左 |
||
小写字符串 |
strlwr |
char* |
char* |
将字母全小写 |
修改后的形参 |
||
大写字符串 |
strupr |
char* |
char* |
将字母全大写 |
修改后的形参 |
||
stdlib .h |
随机数函数 |
rand |
int |
随机生成0到32767的整数 |
见左 |
||
1、 格式字符(%)
- ·%d:十进制带符号整数输入/出
- ·%ld:十进制带符号长整数输入/出
- ·%u:十进制无符号整数输入/出
- ·%o:八进制无符号整数输入/出(注意:是字母o)
- ·%x(X):十六进制无符号整数输入/出(字母大小写与x大小写一致)
- ·%f:以小数形式输入/出实型数
- ·%e(E):以指数形式输入/出实型数(指数符号大小写与e一致)
- ·%g(G):输入或以上述两种方式中较短宽度的方式输出整型数(大小写与g一致)
- ·%c:单个字符输入/出
- ·%s:字符串输入/出
2、 修饰符
- ·m:整数m规定了数据的最小输出长度和最大输入长度
- ·.n:整数n规定了输出的小数位数(实型)或截取的字符串字符个数(字符串)
(先取小数,四舍五入;再看整数,如果整数位数+小数点(也算一位)+小数位数小于总位数,则补空格,若此时加上整数位数超了,则以实际位数为准)
(若n=0,则表示不要小数部分)
- ·0:输出时空位以0补齐(反之为默认补空格)
- ·-:输出时左对齐(反之为默认右对齐)
- ·l(L):按长整型输出或按长整型(双精度)输入
- ·h:按短整型输入
- ·*:跳过该项不进行赋值 (%*d)
3、 格式化输入输出
- ·格式化输入(scanf)基本格式:scanf(“%c, %3s, %f”, &c, s, p);//char c, s[10]; float *p
注:scanf()不能指定浮点数的精度,如 %5.2f错误。
n 对scanf() 函数输入时要看前面占位符之间有无逗号,有则输入时也要加,无则别加否则结果错误。
n scanf()是以删除的方式从缓冲区读取字符(根据字符宽度),遇到非目标类型字符则跳转至下一占位符,读取后根据数据字节舍弃字符。
ü 如scanf_s(“%1c%2c%3c”,&m,&n,&p) 输入1_22_333,则会依次读取1、_ 2、2_3,然后受限于字符字节,m、n、p分别为第一位1、_、2
ü 又如scanf_s(“%2d”,&a);输入字符2a3,只读取到2就停止, 然后由于字符宽度,最终输出_2。
ü 总结:根据输入数据类型要求(优先考虑)和字符宽度(数据类型相同时考虑)要求读取,根据字节长度舍弃,再根据输出字符宽度要求补全。
n 数据分隔符:空格、Enter、Tab
n 对于高版本的VS,使用scanf_s读入%c或%s的时候必须多传入一个参数用来指定读取的长度,否则会出错
- ·scanf中%c将无差别读入任何字符
- ·scanf中%s遇空格、Tab、回车或非法输入会结束(gets同)
(scanf不会读取空格、Tab、回车)
- ·scanf中串用类型会导致严重错误(不要玩弄scanf)
- ·scanf中必须在对应位置原样输入普通字符和转义字符才能正常赋值
- ·scanf中可以规定输入长度,但无法规定输入精度(小数点后长度)
- ·格式化输出(printf)基本格式:printf(“%-07.2f, %s
”,123.456, s); //char s[10]
l (字符串输入的时候,有首地址就够了)
l printf占位符赋值是从右到左执行,输出是从左到右
l Printf返回的是输出字符的个数
- ·printf中普通字符原样输出,转义字符对应输出
- ·printf语句中串用输出形式可能会导致出错,现列举如下:
%d, float/ (long) double: 0
%d, char: ASCII码值
%c, int: 该数对256取余后对应的字符
%c, float/ (long) double:空字符
%f, char/ int: 0.000000
- ·特别的,对于printf(“%d”,1e3);其输出为0(实型包含指数型)
- ·C语言本身没有输入输出语句,依赖库函数
- ·getchar()是stdio.h中的库函数,它的作用是从stdin流中读入一个字符,也就是说,第一次调用getchar()时,确实需要人工的输入,但是如果你输了多个字符,(并以回车为结束标志,回车也放在了缓冲区),以后的getchar()再执行时就会直接从缓冲区中读取了。
4、 表中math.h下的函数double型均可替换为float或long double型,且保持一致
五、 选择结构
1、 特点/功能:根据不同情况做出不同选择
2、 表达式的真值:返回值不为0即为真,反之为假
3、 条件运算符(?:):基本形式x=(exp1)? (exp2):(exp3);exp1为真则x=exp2,反之x=exp3
4、 if语句:基本形式:if(exp) sentence; exp为真时执行sentence反之不执行
- ·如果要执行多条语句,则须使用if(exp){body;}
5、 else语句:基本形式:if(exp) sts1; else sts2; exp为真时执行sts1,反之执行sts2
- ·else语句会向上与最近的同级别未配对的if语句配对
- ·注意if(exp) sts与else间不能加入语句
- ·若if与else语句数量不对等,则建议使用花括号建立配对关系
- ·注意:不要在if(exp)或else后直接加分号,否则将会被认为管辖空语句
6、 if语句的嵌套结构
- ·嵌套结构:某种结构内部套用其同类型结构
- ·if语句的嵌套结构可表现为if(exp1){if(exp2) sts1;else sts2;} else sts3;
7、 else if语句
- ·基本形式:if(exp1) sts1;else if(exp2) sts2;else sts3;
- ·其本质上也是一种嵌套结构
8、 switch语句
- ·基本结构:switch(exp){case exp1:sts1;case exp2:sts2;}
- ·switch后接的表达式返回值必须为整型,case必须后接常量表达式(不能是变量表达式)
- ·当switch后接的表达式返回值与某一case后接的表达式的值相同,将开始执行该case之后的语句。且若无break语句,将顺序执行完{}内所有语句
(无视后面遇到的case值,直至遇到break停止)
(default在结尾则可以不加break,在中间要加)
9、 break语句:用于跳出switch语句或循环结构,详情见后
六、 循环结构
1、 特点/功能:重复相似语句,提高程序效率
2、 while循环:基本形式:while(exp) sts; exp为真时执行sts并返回while语句继续判断
- ·多语句应使用{},视情况决定在while(exp)后是否直接加分号
- ·死循环:反复执行循环体语句而不退出循环
- ·若使用循环变量,则应注意在循环体语句中改变循环变量的值以避免死循环
3、 do-while循环:基本形式:do{body;} while(exp);先执行一次然后同上
- ·注意此处的while(exp)后的分号不能省略
While循环后的while()后没有分号,do-while循环后的while后一定有个分号。
4、 for循环:基本形式:for(exp1;exp2;exp3){body;}从exp1进入;然后紧接着就判断exp2,若为真执行body,反之离开循环;执行完body后再经过exp3重新判断exp2,循环
- ·顺序简记(12b 32b 32b 32)
- ·注意不要漏掉for()内的分号
- ·exp允许使用逗号表达式,特别的,exp2只根据最后一个表达式的值判断
- ·多语句应使用{},视情况决定for(exp1;exp2;exp3)后是否直接加分号
5、 continue语句:用于循环结构中跳过本次循环回到判断语句
- ·在while或do-while循环结构里,continue跳回到while语句
- ·在for循环结构里,continue跳回到for语句并从exp3开始执行
6、 break语句:离开循环体结构,若存在嵌套结构,则仅跳出当前所在循环体
易错:break语句不能用于循环语句和switch语句外的任何其它语句(√)
7、 goto语句:在存在标签(形式为name:)的情况下,使用goto name可以直接移动到标签所在位置并顺序执行语句
- ·goto语句在某些场合可能有奇效,但由于其可能出现数据混乱应限制使用
七、 数组与字符串
数组:一系列相互关联的变量之间的有序集合与统一定义
·下标(方括号[]):在定义的时候规定数列长度,在调用的时候表明序数
·调用时下标内可以是常量或变量表达式(方便了与循环的结合)
·(大部分知识点见上文 数据类型)
字符串:字符形式的数列,其赋初值方式可以是”xxx”或{‘x’, ’x’, ’x’, 0},二者等效
·字符串必须以终止符()结尾,否则不能成为完整结构的字符串
·字符串从第一个字符读到终止符结束,和数组长度有异(定义长度时应长一点)
·单字符输入和格式化输入都不会带上终止符,而gets会自动添加
·终止符:’’或’00’,即ASCII为0的字符(NULL)
·终止符的输出结果类似空格,但不是空格(space,32)
八、 自定义函数
1、 函数:函数是程序的组成单位,执行某一功能的模块。main函数是程序的主函数
2、 函数分类:
- ·函数形式:无参函数(无形参,通常用来执行固定操作)、有参函数(有形参)
- ·用户使用角度:标准函数(库函数,如上表列举)、用户自定义函数
3、 自定义函数
基本格式:类型名 函数名(形参列表){body;}
- ·若为无参函数,则无需形参列表
- ·作为声明时,格式为:类型名 函数名(形参列表);//分号不可省略//可以只有形参类型double fun(double,double);
- ·若为void则调用函数时不能用一个值去接收返回值,这种调用是错误的
- ·若无类型名则默认为int,return返回值类型取决于函数类型,而不取决于return的变量的类型
- ·若函数类型需要一个返回值而没有return语句,则函数自动返回一个不确定的值。
4、 实参与形参
- ·形参:定义函数时规定的形式参数,是一种特殊的局部变量
- ·实参:主调函数向被调函数传递的按形参规定的常量,称为实际参数
(可以是赋值了的变量,也可以是常量,还可以是有返回值的函数调用表达式,但不能是语句(语句带了;没有返回值))
- ·形参规定了实参的格式类型
5、 return语句
- ·函数在遇到return语句后即结束,并将return语句后的值作为函数带回的值
- ·return的值应与函数的类型相一致/匹配
- ·void函数无return语句
- ·非void函数有至少一句return函数,但理应有且只会有一句会被执行
6、 主调函数与被调函数的关联
- ·参数形式(主调函数向被调函数)
- ·返回值(被调函数向主调函数)
- ·全局变量(双向)
- ·地址作为形参(双向):可以是指针和数组等
7、 函数的递归调用:在函数中调用自身,从而实现迭代等功能,是一种高级的循环
·分类:直接递归调用就是在函数a(或过程)中直接引用(调用)函数a本身
间接递归调用就是在函数a(或过程)中调用另外一个函数b,而该函数 b又引用(调用)了函数
- ·函数递归调用的时候要注意终止条件和返回值接收
- ·要注意输出语句的执行顺序
- ·终止条件可由参数形式或静态变量来实现
8、 内部函数与外部函数:根据函数能否被其他源文件调用,将函数区分为内部函数和外部函数。
内部函数 static int fun(int a,int b)
外部函数(extern) int fun (int a, int b)
一般默认为外部函数
在需要调用此函数的文件中,用extern声明所用的函数是外部函数。
九、 指针
1、 指针变量是一类储存地址而非值的变量,以间接访问的方式读取值
2、 指针变量的定义:类型名 *变量名(对于char *a, b; 只有a是指针变量)
3、 只有指针变量能储存地址,而指针变量也只能储存地址
4、 指针变量的值变为0(NULL)时表示不指向任何变量
5、 对指针变量的赋值可以使用取地址符&,或是直接使用数组名或字符串名(本质是地址)
6、 对于int i=3, *p=&i; *p等价于i而不是3,故后置语句*p=4不会报错,而会将4赋值给普通整型变量i;
7、 要先对指针变量进行初始化才能解引用(*)
8、 对指针类型变量p,p+n的意义为p后的第n个有效地址,而不是简单加上n,至于相邻地址的间隔,与变量的类型等有关;
9、 数组a[2][2]地址顺序为&a[0][0],&a[0][1],&a[1][0],&a[1][1];
10、 注意:使用指针的时候应时刻注意指针指向对象
11、 特殊指针类型:
u 指针数组:char *arr[4]; arr先跟[]结合成为一个数组,再跟*结合成指针,即为指针数组。
u 数组指针:char (*pa)[4];
拓:既然pa是一个指针,存放一个数组的地址,那么在我们定义一个数组时,数组名称就是这个数组的首地址,那么这二者有什么区别和联系呢?
char a[4];,
a是一个长度为4的字符数组,a是这个数组的首元素首地址。既然a是地址,pa是指向数组的指针,那么能将a赋值给pa吗?答案是不行的!因为a是数组首元素首地址,pa存放的却是数组首地址,a是char 类型,a+1,a的值会实实在在的加1,而pa是char[4]类型的,pa+1,pa则会加4,虽然数组的首地址和首元素首地址的值相同,但是两者操作不同,所以类型不匹配不能直接赋值,但是可以这样:pa = &a,pa相当与二维数组的行指针,现在它指向a[4]的地址。
二维数组的指针:行指针常用数组指针表示,如char x[3][4];char(*p)[4]=x;(表示指向它行首元素,p+1则移动到下一行,*(p+1)表示整个第二行的元素,但放到表达式中自动转化为第二行首个元素的地址,如*(p+1)+1表示第二行第二个元素的地址,*(*(p+1)+1)表示第二行第二个元素的值,**p表示数组首行首元素的值)
l 函数的指针:如int max(int a, int b);
l 对应的函数指针为 int (*pmax)(int, int) = max;
l //也可以写作int (*pmax)(int a, int b);(=max是对其进行初始化)
12、 指针相减
指针相减=(地址1-地址2)/sizeof(类型) ——定律 ,记牢。
指针相减得出的结果就是两个元素相差的单元,地址1和地址2以%d求出结果,不要用十六进制,要用十进制。在同一个数组中,相邻元素相差1个单元,这一个单元不一定是一个字节,具体多少字节,看你当初是怎么分配的。
十、 字符串
1、 赋值:1)逐字符赋值
char c[20]={“c”, ” “, “p”, “r”, “o”, “g”, “r”, “a”,”m”}; // 给部分数组元素赋值//剩下的自动初始化为’’
char d[]={“c”, ” “, “p”, “r”, “o”, “g”, “r”, “a”, “m” }; //对全体元素赋值时可以省去长度//存储的时候没有’’
char str[4]; str[0] = “a”; str[1] = “b”; str[2] = “c”;str[3]=’’;//逐元素赋值要手动添加’’
2)字符串直接赋值(’’也被存入数组中)
char str[30] = {“c.biancheng.net”};
char str[30] = “c.biancheng.net”;
char str[] = {“c.biancheng.net”};
char str[] = “c.biancheng.net”;
注意:字符数组只有在定义时才能将整个字符串一次性地赋值给它,一旦定义完了,就只能一个字符一个字符地赋值了。如char str[7]; str = “abc123”; //错误
str[3] = “1”; str[4] = “2”; str[5] = “3”; //正确
2、 输入
3、 输出
易错总结:
- 注意符号,如分号(;)、逗号(,),等号(=/==)
- 注意关键字,如break
- 注意0和‘0’和‘’