The C Programming language (一)基本概念与运算符

首先从起源helloworld开始

# include<stdio.h>
int main()
{
printf("hello,world\n");
}

每一个C程序,无论大小,都由函数和变量组成。函数中包含若干用于指定要做的计算操作语句;而变量用于在计算过程中存储有关值。一般而言,可以给函数任意命名,但是main是一个特殊的函数,每一个程序都从名为main的函数起点开始执行,即意味着每一个程序都必须包含一个main函数。而main函数通常要调用其他函数,调用的函数可以自己编写,也可以由系统函数库提供。
例如:#include<stdio.h>本程序中包含标准输入输出库的有关信息。

函数之间的数据通信的一种方法是让调用函数向被调用函数提供一串变元的值;函数名后的圆括号将变元括起来;如本例中:main函数不需要任何变元,即用空括号即可。
而函数中的语句用一对花括号括起来,当要调用一个函数时,先要给出这个函数的名字,再紧跟用一对圆括号括住的变元。用双引号括住的字符序列叫做字符串或字符串常量。

#include<stdio.h>
void main()
{
int b;
//float a,b;
int a=0,upper=300,step=20;
	while(a<=upper)
	{
		
		b=5*(a-32)/9;
		printf("%d\t%d\n",a,b);//只要在 p r i n t f语句的第一个变元的 % 中指明打印长度,则打印的数字会在打印区域内右对齐。
		//右对齐可以用printf("%3d %6d\n",a,b);
		//使用浮点数printf("%3.0f %6.1f\n",a,b);此时为浮点数操作不需要修改b的语句
		a=a+step;
	}
	}
//数据类型
//char 至少是8位,short类型至少16位,long类型至少32位,int类型可以是16位,也可以是32位,float类型一般是32位,double类型一般是64位
#include<stdio.h>
void main()
{
int b;
int a,upper=300,step=20;
	for(a=0;a<=upper;a = a + step)
	{
		b=5 * (a-32) / 9;
		printf("%3d %6d\n",a,b);
	}
}

在c语言中,所有变量都必须先说明后使用,说明用于声明变量的性质,由一个类型名与若干个说明的变量组成。
在语句b=5*(a-32)/9中,之所以把表达式写成先乘 5然后再除以 9而不直接写成 5 / 9,是因为在 C语言及其他许多语言中,整数除法要进行截取:结果中的小数部分被丢弃。由于 5和9都是整数, 5 / 9相除后所截取得的结果为 0,故这样所求得的所有摄氏温度都变成 0。
printf函数第1个变元中的各个 %分别对应于第 2个、第3个… 第n个变元,它们在数目和类型上都必须匹配,否则将出现错误。
在这里插入图片描述
同时在循环中还需要注意表达式的先后,不同顺序的表达式输出是不同的。

符号常量:用#define指令将符号名字(符号常量)定义为一特定的字符串
#define 名字 替换文本(#define指令行的末尾没有分号)

字符输入输出
标准库中有几个函数用于控制一次读写一个字符,其中最简单的是 getchar和putchar这两个函数。getchar 函数在被调用时从文本流中读入下一个输入字符并将其作为结果值返回。p u t c h a r函数在调用时将打印一个字符,通常是显示在屏幕上。

#include<stdio.h>
void main()
{
int b;
while((b=getchar())!=EOF)
putchar(b);
}

getchar函数在没有输入时返回一个特殊值,这个特殊值不能与任何实际字符相混淆。这个值叫做E O F(End Of File,文件结束),之所以不能将c说明为char类型,是因为bc必须大到除了能存储任何可能的字符外还要能存储文件结束符 E O F。
在w h i l e条件中用于括住赋值表达式的圆括号不能省略。不等运算符 ! =的优先级要比赋值运算符=的优先级高,这就是说,在不使用圆括号时关系测试 ! =将在赋值=之前执行。

统计行数、单词数、字符数

#include<stdio.h>
#define out 0
#define in 1
void main()
{
	int wc=0,wl=0,ww=0;
	int c,state=out;
	while((c=getchar())!=EOF)
	{
		wc=wc+1;
		if(c=='\n')
		wl=wl+1;
		if(c=='\n'||c=='\t'||c==' ')
		state=in;
		else if(state==in)
		{
			state=out;
			ww=ww+1;
		}
	}
printf("%d %d %d\n",wc,wl,ww);
}

函数
函数为计算的封装提供了一种简便的方法,在其他地方使用函数时不需要考虑它是如何实现的。在使用正确设计的函数时不需要考虑它是怎么做的,只需要知道它是做什么的就够了。C语言使用了简单、方便、有效的函数,我们将会经常看到一些只定义和调用了一次的短函数,这样使用函数使某些代码段更易于理解。
例:编写一个power(m,n)函数计算整数m的正整数次幂
函数定义的一般形式:
返回值类型 函数名
{
说明序列
语句序列
}
The definition void main( ) { // } is not and never has been C++, nor has it even been C.

#include<stdio.h>
int main()//用int main()
{
int i;
int power(int n,int m);//函数原型,表明p o w e r是一个有两个 i n t类型的变元并返回一个 i n t类型的值的函数。与p o w e r函数的定义和使用相一致。如果该函数的定义和使用与这一函数原型不一致,那么就是错误的
for(i=0;i<10;i++)
	{
	printf("%d %d\n",power(2,i),power(-1,i));
	}
	return 0//
}
int power(int n,int m)//函数的定义,函数原型与函数说明中参数的名字不要求相同。更确切地说,函数原型中的参数名是可有可无的。
{
int i;
int p=1;
for(i=0;i<m;i++)
	{
	p=p*n;
	}
	return p;
}

power的参数名只能在power内部使用,在其他函数中不可见;在其他函数中可以使用与之相同的参数名而不会发生冲突。对变量 i与p亦如此:power函数中的i与main函数中的i无关。一般而言,把在函数定义中用圆括号括住的表中命名的变量叫做参数,而把函数调用中与参数对应的值叫做变元。
power函数计算得的值由return语句返回给main函数。关键词return可以后跟任何表达式;
函数不一定都返回一个值。不含表达式的return语句用于使控制返回调用者(但不返回有用的值),如同在达到函数的终结右花括号时“脱离函数”一样。调用函数也可以忽略(不用)一个函数所返回的值。
而在 main函数末尾有一个return语句。由于main本身也是一个函数,它也就可以向其调用者返回一个值,这个调用者实际上就是程序的执行环境。一般而言,返回值为0表示正常返回,返回值非 0则引发异常或错误终止条件。

变量名:名字由字母与数字组成,但其第一个字符必须为字母。下划线_也被看做是字母,它有时可用于命名比较长的变量名以提高可读性。由于库函数通常使用以下划线开头的名字,因此不要将这类名字用做变量名。大写字母与小写字母是有区别的, x与X是两个不同的名字,一般把由大写字母组成的名字用做符号常量。

扫描二维码关注公众号,回复: 8555045 查看本文章

常量:例如1234一类的整数常量是int常量,long常量以字母l或L结尾,如123456789L。无符号常量以字母u或者U结尾,后缀UL或ul用于表示unsigned long常量。

  • 浮点常量:必须包含一个小数点(如123.4)或指数(1e-2),在没有后缀类型为double,后缀f或F指定Float常量,而后缀l或L用于指定long double常量。
    整数值除了用十进制表示外,还可以用八进制或十六进制表示。如果一个整数常量的第一个数字为0,那么这个数就是八进制数;如果第一个数字为 0 x或0 X,那么这个数就是十六进制数。
    例如,十进制数3 1可以写成八进制数 0 3 7,也可以写成十六进制数 0 x 1 f或0 X 1 F。
  • 字符常量:是一个整数,写成用单引号括住单个字符的的形式,如 ’ x '。字符常量的值是该字符在机器字符集中的数值。例如,在 A S C I I字符集中,字符 ‘0’ 的值为4 8,与数值0没有关系。
  • 字符串常量:也叫字符串字面值,是用双引号括住的由 0个或多个字符组成的字符序列。从技术角度看,字符串常量就是字符数组。在内部表示字符串时要用一个空字符 ‘\0’ 来结尾,故用于存储字符串的物理存储单元数比括在双引号中的字符数多一个。
    请仔细区分字符常量与只包含一个字符的字符串的区别: ’ x '与 " x "不相同。前者是一个整数,用于产生字母 x在机器字符集中的数值(内部表示值)。后者是一个只包含一个字符(即字母 x)与一个 ’ \ 0 '的字符数组
  • 转义字符
    在这里插入图片描述
    字符常量 ‘\0’ 表示其值为0的字符,即空字符。我们用 ‘\0’ 来代替0,以在某些表达式中强调字符的性质,但其数字值就是 0。
  • 枚举常量
    除非指定了显式值,如果不是所有值都指定,那么未指定名字的值根据最后一个指定值向后递增:
enum escapes { BELL = '\a', BACKSPACE = '\b', TAB = '\t',
NEWLINE = '\n', VTAB = '\v', RETURN = '\r' };

enum months { JAN = 1, FEB, MAR, APR, MAY, JUN,
JUL, AUG, SEP, OCT, NOV, DEC };
/* FEB的值为2, MAR的值为3,等等。 */

不同的枚举中的名字必须各不相同,同一枚举中各个名字的值不要求相同。

**说明:**除了某些可以通过上下文做的隐式说明外,所有变量都必须先说明后使用。在说明的同时可以进行初始化,如果所说明的变量名后跟一个等号与一个表达式,那么这个表达式被作为初始化符。
如果所涉及的变量不是自动变量,那么只初始化一次,且初始化符必须为常量表达式。显示初始化的自动变量每当进入其所在的函数或分程序时就进行一次初始化,其初始化符可以是任何表达式。
外部变量与静态变量的缺省初值为0。未经显式初始化的自动变量的值为未定义值
在变量说明中可以用 const限定符限定,该限定符用于指定该变量的值不能改变。对于数组,const限定符使数组所有元素的值都不能改变。

(一)算术运算符
二元算术运算符包括 +、 -、 *、 /以及取模运算符 %。整数除法要截取掉结果的小数部分。
取模运算符 %不能作用于f l o a t或d o u b l e对象。在有负的运算分量时,整数除法截取的方向以及取模运算结果的符号于具体机器,在出现上溢或下溢时所要采取的动作也取决于具体机。
(二)关系运算符
关系运算符有如下几个:> >= < <=
所有关系运算符具有相同的优先级。优先级正好比它们低一级的是相等运算符:== !=
关系运算符的优先级比算术运算符低。
(三)类型转换
当一个运算符的几个运算分量的类型不相同时,要根据一些规则把它们转换成某个共同的类型。一般而言,只能把“比较窄的”运算分量自动转换成“比较宽的”运算分量,这样才能不丢失信息。
可能丢失信息的表达式可能会招来警告信息,如把较长整数类型的值赋给较短整数类型的变量,把浮点类型赋给整数类型,等等,但不是非法表达式。
由于C语言没有指定char类型变量是无符号量还是有符号量,当把一个char类型的值转换成int类型的值时,结果视机器的不同而有所变化,反映了不同机器结构之间的区别。在某些机器上,如果字符的最左一位为 1,那
么就被转换成负整数(称做“符号扩展”)。在另一些机器上,采取的是提升的方法,通过在最左边加上0把字符提升为整数,这样转换的结果总是正的。为了保证程序的可移植性,如果要在char变量中存储非字符数据,那么最好指定signed 或unsigned限定符。
注意,在表达式中 f l o a t类型的运算分量不自动转换成 d o u b l e类型,这与原来的定义不同。一般而言,数学函数(如定义在标准头文件 < m a t h . h >中的函数)要使用双精度。使用 f l o a t类型的主要原因是为了在使用较大的数组时节省存储单元,有时也为了节省机器执行时间(双精度算术运算特别费时)。
最后,在任何表达式中都可以进行显式类型转换(即所谓的“强制转换”),这时要使用一个叫做强制转换的一元运算符。
(类型名)表达式
例如,库函数 s q r t需要一个d o u b l e类型的变元,但如果在其他地方作了不适当的处理,那么就会产生无意义的结果(s q r t是在< m a t h . h >中说明的一个函数)。可以用sqrt ( (double) n)
(四)加一与减一运算符
加一运算符 + +用于使其运算分量加 1,减一运算符 - -用于使其运算分量减1。
表达式++n:在n的值被使用之前先使n加1,而表达式n++:在n的值被使用之后再使n加1。
加一与减一运算符只能作用于变量,例如(i+j)++一类的表达式是非法的。

void squeeze(char s[],int c)
{int i,j;
	for(i=0,j=0;s[i]!='\0';i++)
	{if(s[i]!= c)
		s[j++]=s[i];//每当出现一个不等于 c的字符时,就把它拷贝到 j的当前值所指向的位置,并将 j的值加1,以准备处理下一个字符。
	}		

(五)按位运算符
C语言提供了六个用于位操作的运算符,这些运算符只能作用于整数分量,即只能作用于有符号或无符号的c h a r、 s h o r t、 i n t与l o n g类型:& 按位与(AND)| 按位或(OR)^ 按位异或(XOR)<< 左移>> 右移
~ 求反码(一元运算符)
其中按位与运算符&经常用于屏蔽某些位;按位或运算符 | 用于打开某些位
必须将按位运算符 &和 | 同逻辑运算符 & &和 || 区分开来,例如,如果 x的值为1, y的值为2,那么, x & y 的结果是0,而x && y的值则为1。
(六)赋值运算符
在一个赋值表达式中,如果赋值运算符左边的变量在右边紧接着又要重复一次,可以将这种表达式改写成更精简的形式:大多数二元运算符(即有左右两个运算分量的运算符)都有一个对应的赋值运算符 o p=, o p
是下面这些运算符中的一个:+ - * / % << >> & ^ |
表达式1 op= 表达式2
等价于
表达式1 = 表达式1 op 表达式2
(七)条件表达式
即三目运算符表达式1? 表达式2: 表达式3
在这里插入图片描述
注意,按位运算符 &、 ^ 与 | 的优先级比相等运算符 == 与 != 低。这意味着,在诸如if ( (x & MASK) == 0)中,位测试表达式必须用圆括号括起来,才能得到正确的结果。
而C语言没有指定同一运算符的几个运算分量的计算次序,例如x= f() +g();f()可以在g()之前计算,也可以在g()之后计算。同样,在函数调用中各个变元的求值次序也是未指定的。
因而

printf("%d %d\n",++n,power(2,n));

对于不同的编译程序可能产生不同的结果(视n加一是在power调用之前还是之后)
可以将语句改写成

++n;
	printf("%d %d\n",n,power(2,n));

函数调用、嵌套的赋值语句、加1与减1运算符都有可能引起“副作用”-作为表达式的副产品,改变了某些变量的值,在涉及到副作用的表达式中,对作为表达式一部分的本来的求值次序存在微妙的依赖关系。

发布了54 篇原创文章 · 获赞 4 · 访问量 1018

猜你喜欢

转载自blog.csdn.net/buzhiquxiang/article/details/103774901