1、函数:当程序很小的时候,我们可以使用一个main函数就能搞定,但当程序变大的时候,就超出了人的大脑承受范围,逻辑不清了,这时候就需要把一个大程序分成许多小的模块来组织,于是就出现了函数概念;
函数是C语言代码的基本组成部分,它是一个小的模块,整个程序由很多个功能独立的模块(函数)组成。这就是程序设计的基本分化方法;
(1) 写一个函数的关键:
函数定义:函数的定义是这个函数的实现,函数定义中包含了函数体,函数体中的代码段决定了这个函数的功能;
函数声明:函数声明也称函数原型声明,函数的原型包含三部分:函数名,返回值类型,函数参数列表,函数的声明是告诉使用函数的人,这个函数使用时应该传递给他什么样的参数,
它会返回什么样类型的返回值。这些东西都是写函数的人在函数定义中规定好的,如果使用函数的人不参照这个原型来使用,就会出错,结果就会和你想的不一样;
函数调用:函数调用就是使用函数名来调用函数完成功能。调用时必须参照原型给函数传参,然后从函数得到适当的返回值作为结果;
(2) 函数的参数:函数调用的过程,其实就是实参传递给形参的一个过程。这个传递像是一次拷贝,实参(本质是一个变量)本身并没有进入到函数内,而是把自己的值复制了一份传给了函数中的形参,
在函数中参与运算,这种传参方法,就叫做传值调用;
形参:形式参数,在函数定义和函数声明中的参数列表中的参数都是形参;
实参:实际参数,函数调用中,实际传递的参数才是实参。
(3) 返回值(关键字return):当函数执行完之后,会给调用该函数的地方返回一个值。这个值的类型就是函数声明中返回值类型,这个值就是函数体中最后一句return xxx;返回的那个值;
(4) 函数名:取函数名要注意以下几点:
第一,起名字时候不能随意,要符合规则,而这个规则分别有两个层次,即第一层是合法,第二层是合理。合法就是符号C语言中变量名的命名规则,合理就是变量名起的好,
人一看就知道什么意思,一看就知道这个函数是干嘛的;
第二,C语言中,所有的符号都是区分大小写的;
第三,C语言函数名的命名习惯。这个没有固定的结论,有多种使用都很广泛的命名方式如下:
linux的命名习惯:student_age str_to_int
骆驼命名法:studentAge strToInt
注:想进一步了解可以参考林锐的《高质量程序设计指南》;
// 简单计算器
#include <stdio.h> int add(int a, int b);
int sub(int a, int b);
int mul(int a, int b);
int div(int a, int b); int main(void)
{
int a, b, c; a = ;
b = ; c = add(a, b);
//c = sub(a, b);
//c = mul(a, b);
//c = div(a, b); printf("c = %d.\n", c);
printf("a - b = %d.\n", sub(a, b)); return ;
} int add(int a, int b)
{
return a + b;
} int sub(int a, int b)
{
return a - b;
} int mul(int a, int b)
{
return a * b;
} int div(int a, int b)
{
return a / b;
}
2、数组:数组就是若干个数组成的一个组,数就是一个特定数据类型的变量,组就是说好多数放在了一起;
(1) 数组的定义:
int a[10]; 数组中元素类型 数组名[数组元素个数];
注:数组中的所有元素都是同一种数据类型,不可能在一个数组中出现两种数据类型的数。
(2) 数组的使用:数组定义的时候是作为一个整体来定义的,但是使用的时候不能作为一个整体来使用,使用时必须拆开使用数组中的各个元素;
如:数组int a[10],使用其中的十个元素,分别用a[0]……a[9],其中[]是数组的标志,[]中的数字叫做数组的下标(index,索引),下标是我们访问数组中各个元素的指引,
下标是0代表数组中第一个元素,下标是1代表数组第二个元素,以此类推,若数组长度为n,则下标中最后一个是n-1;
注:访问数组时要特别注意下标,下标是从0开始的,如果下标超出了n-1,会产生越界访问,结果是不可预期的;
(3) 数组的初始化:初始化是为了让对象有一个预定的初始状态,数组的初始化分两种:
第一种:完全初始化。依次赋值;
第二种:不完全初始化。初始化式中的值从a[0]开始,依次向后赋值,不足的默认用0填充赋值
(4) 不同数据类型的数组:
int a[3]; // 整型数组
float b[3]; // 单精度浮点型数组
double c[3]; // 双精度浮点型数组
char d[3]; // 字符型数组
(5) 字符数组:在C语言中引用一个单个字符时,应该用单引号''括起来,譬如'a';
字符数组的初始化:定义数组同时初始化,则可以省略数组定义时[]中的长度。C语言编译器会自动推论其长度,推论依据是初始化式中初始化元素的个数;
引用字符串:在C语言中引用一个字符串时,应该用""括起来,如"abcde",其中"abcde"实际上有6个字符,分别是'a' 'b' 'c' 'd' 'e' '\0';
'\0' 是C语言中定义的字符串的结尾标志,这个字符是ASCII码表中的第一个字符,它的编码值是0,对应的字符是空字符(不可见字符);
// 数组的演示
#include <stdio.h> int main(void)
{
int a[]; a[] = ;
a[] = ;
a[] = ;
a[] = ; printf("a[1] = %d, a[3]= %d.\n", a[], a[]); return ;
}
// 字符数组的演示
#include <stdio.h> int main(void)
{
/*
int i = 0;
//char a[5];
//char a[5] = {'a', 'b', 'c', 'd', 'e'};
//char a[5] = {97, 98, 99, 100, 101};
//char a[] = {97, 98, 99, 100, 101};
char a[] = "abcde"; for (i=0; i<5; i++)
{
printf("a[%d] = %d %c\n", i, a[i], a[i]);
}
*/ int i = ;
char a[] = {, , , , };
char b[] = "abcde"; printf("sizeof(a) = %d, sizeof(b) = %d.\n", sizeof(a), sizeof(b)); return ;
}
3、指针:全称是指针变量,其实质是C语言的一种变量。这种变量比较特殊,通常它的值会被赋值为某个变量的地址值(p = &a),然后我们可以使用*p这样的方式去间接访问p所指向的那个变量;
(1) 指针存在的意义:可以间接访问。有了指针之后,我们访问变量a不必只通过a这个变量名来访问。而可以通过p = &a; *p = xxx;这样的方式来间接访问变量a;
(2) 两个重要的运算符:&和*
&:取地址符,将它加在某个变量前面,则组合后的符号代表这个变量的地址值;
如: int a; int *p; p = &a; 则将变量a的地址值赋值给p
a 代表变量a本身
p 代表指针变量p本身
&a 代表变量a的地址值
*p 代表指针变量p所指向的那个变量,也就是变量a
&p 代表指针变量p本身的地址值,符号虽合法,但对题目无意义
*a 把a看作一个指针,*a表示这个指针所指向的变量,该符号不合法
*:指针符号。指针符号在指针定义和指针操作的时候,解析方法是不同的;
int *p; 定义指针变量p,这里的*p含义不是代表指针变量p所指向的那个变量,在定义时这里的*含义是告诉编译器p是一个指针
*p = 0x24; 使用指针的时候,*p则代表指针变量p所指向的那个变量
(3) 指针的定义和初始化:
第一种:先定义再赋值
int *p; // 定义指针变量p
p = &a; // 给p赋值
第二种:定义的同时初始化
int *p = &a; // 效果等同于上面的两句
(4) 各种不同类型的指针:指针变量本质上是一个变量,指针变量的类型属于指针类型。int *p;定义了一个指针类型的变量p,这个p所指向的那个变量是int型;
int *pInt; // pInt是指针变量,指向的变量是int类型
char *pChar; // pChar是指针类型,指向的变量是char类型
float *pFloat;
double *pDouble;
注:各种指针类型和它们所指向的变量类型必须匹配,否则结果不可预知;
(5) 指针定义的两种理解方法:
int *p;
第一种(推荐):首先看到p,这个是变量名;其次,p前面有个*,说明这个变量p是一个指针变量;最后,*p前面有一个int,说明这个指针变量p所指向的是一个int型数据;
第二种:首先看到p,这个是变量名;其次,看到p前面的int *,把int *作为一个整体来理解,int *是一种类型(复合类型),该类型表示一种指向int型数据的指针;
(6) 指针与数组的初步结合:
数组名:做右值时,数组名表示数组的首元素首地址,因此可以直接赋值给指针;
如:int a[10];其中a和&a[0]都表示数组首元素a[0]的首地址,而&a则表示数组的首地址;
注:数组首元素的首地址和数组的首地址是不同的,前者是数组元素的地址,而后者是数组整体的地址。两个东西的含义不同,但是数值上是相同的;
根据以上,我们知道可以用一个指针指向数组的第一个元素,这样就可以用间接访问的方式去逐个访问数组中的元素,这样访问数组就有了两种方式:
有 int a[5]; int *p; p = a;
数组的方式依次访问:a[0] a[1] a[2] a[3] a[4]
指针的方式依次访问:*p *(p+1) *(p+2) *(p+3) *(p+4)
(7) 指针与++ --符号进行运算:指针本身也是一种变量,因此也可以进行运算,但是因为指针变量本身存的是某个其他变量的地址值,因此该值进行* / %等运算是无意义的,
故两个指针变量相加本身也无意义,但相减有意义。指针变量+1,-1是有意义的,+1就代表指针所指向的格子向后挪一格,-1代表指针所指向的格子向前挪一格。
*p++的解析:++先跟p结合,但是因为++后置的时候,本身含义就是先运算后增加1(运算指的是p++整体与前面的*进行运算;增加1指的是p+1),所以实际上*p++符号整体对外表现的
值是*p的值,运算完成后p再加1;
*p++等同于:*p; p += 1;
*++p等同于:p += 1; *p;
(*p)++,使用()强制将*与p结合,只能先计算*p,然后对*p整体的值++
++(*p),先*p取值,再前置++,该值+1后作为整个表达式的值
// 指针的定义、赋值及初始化
#include <stdio.h> int main(void)
{
int a = ;
int *p = &a; *p = ; printf("a = %d\n", a); return ;
}
// 用指针去访问数组
#include <stdio.h> int main(void)
{
int a[] = {, , , , };
int *p; //p = &a;
//p = &a[0];
p = a; //p += 1; //printf("*p = %d.\n", *p); //printf("*p++ = %d.\n", *p++);
//printf("*++p = %d.\n", *++p);
//printf("(*p)++ = %d.\n", (*p)++);
printf("++(*p) = %d.\n", ++(*p)); return ;
}
4、补充:变量与数据类型的实质
(1) 程序在环境中运行时,需要一定的资源支持,而这些资源包括:CPU(运算能力)、内存等,这些资源一般由运行时环境(一般是操作系统)来提供,比如我们在linux系统上./a.out运行程序时,
linux系统为我们提供了运算能力和内存;
(2) 程序越庞大,运行时消耗的资源越多,比如说内存额定占用,如果越大的程序,占用的内存肯定越多,而占用内存的其中之一,就是我们在程序中定义的变量;
(3) C语言程序中,变量的实质就是内存中的一个格子。当我们定义了一个变量后,就相当于在内存中得到了一个格子,而这个格子的名字就是变量名,
以后访问这个内存格子就只用使用该变量名就行了,这就是变量的本质;
(4) 数据类型的实质是内存中格子的不同种类。比如在32位的机器上:
短整形格子(short) 占用2字节,即16位的空间
整形格子(int) 占用4字节,即32位的空间
单精度浮点型格子(float) 占用4字节,即32位的空间
双精度浮点型格子(double) 占用8字节,即64位的空间
字符型格子(char) 占用1字节,即8位的空间
(5) sizeof运算符:返回一个变量或者一个数据类型的内存占用长度,以字节为单位;
// sizeof运算符的演示
#include <stdio.h> int main(void)
{
int len; //len = sizeof(int);
//len = sizeof(float);
//len = sizeof(double);
//len = sizeof(char); //double d;
//len = sizeof(d); int a[];
//len = sizeof(a);
len = sizeof(a) / sizeof(a[]); printf("len = %d.\n", len); return ;
}
(以上所述内容为学习朱老师的嵌入式课程后复习笔记所得,目的是自己复习巩固知识,同时把自己学到的知识分享出来。能力有限,水平一般,如有错误,欢迎指正,谢谢!)
2017-02-26 22:43:15
C语言中的函数、数组与指针的更多相关文章
-
c语言中双维数组与指针的那点事儿
说起c语言的指针,估计对c语言只是一知半解的同志们可能都会很头疼,尤其它跟数组又无耻的联系到一起的时候,就更加淫荡了!!! 怎么说呢,就是有一点规定:(或准则) 数组名可以看成是指向数组头元素的指针, ...
-
c语言中多维数组和指针的关系
如图: 执行结果: 说明:由执行结果可知,三个输出的结果相等(可能在不同的平台执行结果不相同,但三个的结果是相等的),数组multi的地址与数组multi[0]的地址相同,都等于存储的第一个整数的地址 ...
-
C语言中的函数指针
C语言中的函数指针 函数指针的概念: 函数指针是一个指向位于代码段的函数代码的指针. 函数指针的使用: #include<stdio.h> typedef struct (*fun_t ...
-
利用C语言中的函数指针实现c++中的虚函数
C语言中的函数指针 #include<stdio.h> int fun1(int a) { return a*a; } int fun2(int a) { return a*a*a; } ...
-
js课程 3-10 js中字符串函数数组函数和其它语言中对应函数的区别和联系是什么
js课程 3-10 js中字符串函数数组函数和其它语言中对应函数的区别和联系是什么 一.总结 一句话总结:js中是对象点方法的形式,这些方法都是对象的方法,而在php.java中却不是这样. 1.j ...
-
C语言中的函数
C语言中的函数 目录 概述——对函数的理解 C语言中函数的定义和声明 函数允许的参数类型 函数允许的返回类型 递归 概述 由于有些代码段在编写程序的时候经常会用到,此时我们为了减少代码文件的长度和增加 ...
-
(待续)C#语言中的动态数组(ArrayList)模拟常用页面置换算法(FIFO、LRU、Optimal)
目录 00 简介 01 算法概述 02 公用方法与变量解释 03 先进先出置换算法(FIFO) 04 最近最久未使用(LRU)算法 05 最佳置换算法(OPT) 00 简介 页面置换算法主要是记录内存 ...
-
C语言中的函数与数学上的函数很类似
函数,是C语言编程中一个很重要的概念,重要到个人认为可以与指针并驾齐驱.好多教材.老师.学习资源都会专门挑出一章来讲函数.我今天也来说说函数,只不过我是从数学课上的函数来引申到C语言中的函数. 先来说 ...
-
想精度高,可以考虑用c语言中的函数gettimeofday
大家好: 在 win32 + bcb 时, 有个 GetTickCount() 返回第统启动到现在的 tick, 单位 ms.请问在 Linux + qt5 怎样实现呢? 如果用 QDateTime ...
随机推荐
-
BZOJ 3944 Sum
题目链接:Sum 嗯--不要在意--我发这篇博客只是为了保存一下杜教筛的板子的-- 你说你不会杜教筛?有一篇博客写的很好,看完应该就会了-- 这道题就是杜教筛板子题,也没什么好讲的-- 下面贴代码(不 ...
-
Linux下中文字符乱码的问题
来源:Linux社区 作者:frankfellow Linux下中文经常会出现乱码,有的是浏览网页出现乱码:有的是文本模式下显示中文出现乱码.下图显示的是我遇到的问题.我安装的是CentOS,x-w ...
-
bzoj 1036 Tree Count
题目大意:给出一棵树,每个点有一个权值,要求三种操作:1.修改某个点的权值,2.询问x到y路径上各点的权值最大值,3.询问x到y路径上各点的权值之和. #include <cstdio> ...
-
html5 canvas 鼠标绘制
<!doctype html> <html> <head> <meta charset="utf-8"> <title> ...
-
树莓派高级GPIO库,wiringpi2 for python使用笔记(四)实战DHT11解码
DHT11是一款有已校准数字信号输出的温湿度传感器. 精度湿度+-5%RH, 温度+-2℃,量程湿度20-90%RH, 温度0~50℃. 我买的封装好的模块,上边自带了上拉电阻,直接查到树莓派上即可灰 ...
-
Vue学习记录第一篇——Vue入门基础
前面的话 Vue中文文档写得很好,界面清爽,内容翔实.但文档毕竟不是教程,文档一上来出现了大量的新概念,对于新手而言,并不友好.个人还是比较喜欢类似于<JS高级程序设计>的风格,从浅入深, ...
-
查询优化--小表驱动大表(In,Exists区别)
Mysql 系列文章主页 =============== 本文将以真实例子来讲解小表驱动大表(In,Exists区别) 1 准备数据 1.1 创建表.函数.存储过程 参照 这篇(调用函数和存储过程批 ...
-
Xilinx Zynq ZC-702 开发(02)—— 软件程序调试方法
1.简介 本教程将指导您使用 SDK 调试应用程序项目,本教程中描述的调试步骤是非常基础的:有关更多信息,请参考 SDK 帮助中的调试任务. 在使用本教程之前,您应该已经创建了一个应用程序项目,并在工 ...
-
java json 转换
1.直接输出: 2.字符串 通过eval转换输出,里面涉及到一个转义问题,还要注意eval的用法里面需要加"("+ + ")" 3.
-
理解TCP序列号(Sequence Number)和确认号(Acknowledgment Number)
原文见:http://packetlife.net/blog/2010/jun/7/understanding-tcp-sequence-acknowledgment-numbers/ from:ht ...