一、简单介绍
C语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。它有以下特点:简洁紧凑、灵活方便、运算符丰富、数据类型丰富、表达方式灵活实用、允许直接访问物理地址,对硬件进行操作、生成目标代码质量高,程序执行效率高、可移植性好、表达力强;但同时封装性及语法严格限制的情况不如其他语言好。 个人认为,在进行算法的练习和设计时,c语言是一个不错的选择,占用内存少,更接近于底层,也很容易实现各种数据结构。
二、基础知识
1.基本输入输出
scanf函数
定义在头文件stdio.h中,它是格式输入函数,即按用户指定的格式从键盘上把数据输入到指定的变量之中。
函数原型:
int scanf(const char *format,...);
其调用形式为: scanf("<格式说明字符串>",<变量地址>);变量地址要求有效,并且与格式说明的次序一致。
scanf()函数返回成功赋值的数据项数,读到文件末尾出错时则返回EOF。
如:
scanf("%d %d",&a,&b);
如果a和b都被成功读入,那么scanf的返回值就是2。
格式说明符
转换字符(就是%后跟的部分)
c 读单字符
d 读十进制整数
i 读十进制、八进制、十六进制整数
e 读浮点数
E 读浮点数
f 读浮点数
g 读浮点数
G 读浮点数
o 读八进制数
s 读字符串
x 读十六进制数
X 读十六进制数
p 读指针值
n 至此已读入值的等价字符数
u 读无符号十进制整数
[ ] 扫描字符集合
% 读 % 符号(百分号)
附加格式说明字符表修饰符说明
L/l 长度修饰符 输入"长"数据
h 长度修饰符 输入"短"数据
W 整型常数 指定输入数据所占宽度
* 表示本输入项在读入后不赋值给相应的变量
选择性的扫描输入例子:
#include<stdlib.h> #include<stdio.h> int main(){ int a,b,c; scanf("%d,%d,%d",a,b,c); //输入格式为a,b,c printf("%d %d %d",a,b,c); //输出格式为a b c(中间有空格) return 0; }
printf函数
printf()函数是格式化输出函数, 一般用于向标准输出设备按规定格式输出信息。
printf()函数的调用格式为: printf("<格式化字符串>", <参量表>)。
参数使用方法与scanf函数类似
2.for循环
编写for循环时,需要注意先声明初始变量,再在括号内使用(与c++中不同),可采用以下形式
int i; for(i=0;i<size;i++){ // TO DO }
使用下面这种形式会出错:
3.常用头文件
#include<stdlib.h> //stdlib 头文件即standard library标准库头文件。
stdlib.h里面定义了五种类型、一些宏和通用工具函数。 类型例如size_t、wchar_t、div_t、ldiv_t和lldiv_t; 宏例如EXIT_FAILURE、EXIT_SUCCESS、RAND_MAX和MB_CUR_MAX等等; 常用的函数如malloc()、calloc()、realloc()、free()、system()、atoi()、atol()、rand()、srand()、exit()等等。 具体的内容你自己可以打开编译器的include目录里面的stdlib.h头文件看看。
#include<stdio.h> // 包含了一些输入输出函数,如scanf,printf等
4.字符串
可以用字符数组来表示字符串,如
#include<stdlib.h> #include<stdio.h> int main(){ char str[30]="Hello World"; // 仅在初始化时使用 printf(str); return 0; }
可以用strcp函数来复制获取输入的字符串
#include <stdio.h> #include <string.h> int main () { char str1[12] = "Hello"; char str2[12] = "World"; char str3[12]; int len ; /* copy str1 into str3 */ strcpy(str3, str1); printf("strcpy( str3, str1) : %s\n", str3 ); /* concatenates str1 and str2 */ strcat( str1, str2); printf("strcat( str1, str2): %s\n", str1 ); /* total lenghth of str1 after concatenation */ len = strlen(str1); printf("strlen(str1) : %d\n", len ); return 0; }
输出
strcpy( str3, str1) : Hello strcat( str1, str2): HelloWorld strlen(str1) : 10
将数字转化为字符串
a.能将整数转换为字符串而且与ANSI标准兼容的方法是使用sprintf()函数
#include<stdio.h> # include <stdlib. h> void main (void); void main (void) { int num = 100; char str[25]; sprintf(str, " %d" , num); printf ("The number ‘num‘ is %d and the string ‘str‘ is %s. \n" , num, str); }
b.用fcvt()函数将浮点型值转换为字符串的一个例子:
# include <stdio. h> # include <stdlib. h> void main (void); void main (void) { double num = 12345.678; char * sir; int dec_pl, sign, ndigits = 3; /* Keep 3 digits of precision. * / str = fcvt(num, ndigits, &dec-pl, &sign); /* Convert the float to a string. * / printf("Original number; %f\n" , num) ; /* Print the original floating-point value. * / printf ("Converted string; %s\n",str); /* Print the converted string‘s value. * / printf ("Decimal place: %d\n" , dec-pi) ; /* Print the location of the decimal point. * / printf ("Sign: %d\n" , sign) ; /* Print the sign. 0 = positive, 1 = negative. * / }
fcvt()函数和itoa()函数有数大的差别。fcvt()函数有4个参数:第一个参数是要转换的浮点型值;第二个参数是转换结果中十进制小数点右侧的位数;第三个参数是指向一个整数的指针,该整数用来返回转换结果中十进制小数点的位置;第四个参数也是指向一个整数的指针,该整数用来返回转换结果的符号(0对应于正值,1对应于负值)。
5.数组,如何使用二维或高维数组,如何用它来表示矩阵,如何用它来表示图
1、二维数组的概念
在C语言中,二维数组实际上是一种特殊的一维数组,它的每个元素也是一个一维数组。因此,二维数组下标形式正确写法如下:int arrays[i][j]。数组元素是按照行顺序存储的,因此当按存储顺序访问树时,最右边的数组下标(列)变化的最快。
2、二维数组作为函数参数
规定:如果将二维数组作为参数传递给函数,那么在函数的参数声明中必须指明数组的列数,数组的行数没有太大关系,可以指定也可以不指定。因为函数调用时传递的是一个指针,它指向由行向量够成的一维数组。因此二维数组作为函数参数正确写法如下所示:
void Func(int array[3][10]);
void Func(int array[ ][10]);
因为数组的行数无关紧要,所以还可以写成如下形式:
void Func(int (*array)[10]); 注意*array需要用括号括起来。
这种形式的声明参数是一个指针,它指向具有10个元素的一维数组。因为[]的优先级比*的优先级高,故*array必须用括号括起来,否则变成了
void Func(int *array[10]);
这时候参数相当于是声明了一个数组,该数组有10个元素,其中每个元素都是一个指向整型对象的指针。
但是不能把第二维或者更高维的大小省略,如下面的定义是不合法的:
void Func(int array[ ][ ]);
因为从实参传递来的是数组的起始地址,在内存中按数组排列规则存放(按行存放),而并不区分行和列,如果在形参中不说明列数,则系统无法决定应为多少行多 少列,不能只指定一维而不指定第二维,下面写法是错误的:
void Func(int array[3][ ]);
实参数组维数可以大于形参数组,例如形参数组定义为:
void Func(int array[3][10]);
代码示例:
容易出现的错误写法:
#include <cstdio> void print(int *arr[3]) { printf("%d\n",arr[0][0]); } int main() { int arr[2][3] = {1,2,3,4,5,6}; print(arr); return 0; }
正确写法:
1 #include <cstdio> 2 void print(int (*arr)[3]) //用括号将指针括起来 3 { 4 printf("%d\n",arr[0][0]); 5 } 6 7 int main() 8 { 9 int arr[2][3] = {1,2,3,4,5,6}; 10 print(arr); 11 return 0; 12 }
6.动态分配空间问题,如何分配,是否需要指定大小
动态数组:
int *arr=(int *)malloc(size*sizeof(int)) ; //其中size是一个数值大小,你可以根据实际需要的大小而定
7.应注意与c++有哪些不同
不能在c++中编译的c程序
7.1 在c++中,在函数声明前调用该函数会产生编译错误。但在c中,可能会正常编译。
#include<stdio.h> int main() { foo(); // foo() is called before its declaration/definition } int foo() { printf("Hello"); return 0; }
7.2 在c++中,将常指针指向一个常量会产生编译错误,但在c中是允许的。
#include <stdio.h> int main(void) { int const j = 20; /* The below assignment is invalid in C++, results in error In C, the compiler *may* throw a warning, but casting is implicitly allowed */ int *ptr = &j; // A normal pointer points to const printf("*ptr: %d\n", *ptr); return 0; }
7.3 在c中,void 指针可以直接赋值给其他类型指针,如int *, char *;但在c++中是不允许的。
#include <stdio.h> int main() { void *vptr; int *iptr = vptr; //In C++, it must be replaced with int *iptr=(int *)vptr; return 0; }
7.4 在c++中常量必须要被初始化,但在c中是可选的。
#include <stdio.h> int main() { const int a; // LINE 4 return 0; }
7.5 c++特定的关键字在c中是允许的。虽然这样,但实际编程过程中,应尽量避免这些问题。
#include <stdio.h> int main(void) { int new = 5; // new is a keyword in C++, but not in C printf("%d", new); }
7.6 c++有更严格的类型检查。例如,下面的程序在c中可以通过,但不能在c++中编译。
#include <stdio.h> int main() { char *c = 333; printf("c = %u", c); return 0; }