C语言复习总结:
这个文件是在学习完C语言的基本用法后,回顾C语言的一些语法和易错,不易理解的一下内容,可能会存在内容不连续的情况.
本文内容,有参考自 M了个J的博客 根据自身的学习进行了部分的摘抄和扩写
原文请参考:http://www.cnblogs.com/mjios/tag/objective-c/default.html?page=1
函数:
1.任何一个函数在使用之前都必须进行定义
2、调用函数时传递的实参个数 必须和 函数的形参个数必须保持一致
3.当使用基本数据类型(char、int、float等)作为实参时,实参和形参之间只是值传递,修改形参的值并不影响到实参
4.函数可以没有形参
5.返回值就是函数调用完后,返回给函数调用者的结果,用return关键字进行返回。定义函数时,要指明函数的返回值类型
6、一个函数可以没有返回值,如果没有返回值,应该用void表示返回值类型
7、如果一个函数没有返回值,最后面的return语句可以省略
8、如果一个函数没有明确写出返回值类型,那么代表这个函数的返回值类型是int
9、return语句可以在函数内部返回一个值给函数调用者
10、一个函数内部可以多次使用return语句,使用了return语句后,函数就会马上停止执行,return语句后面的代码就不再被执行
函数定义的注意:
1.函数名不能重复
2.每一个函数都应该独立定义,不能嵌套定义
Scanf函数的使用注意:
// 逗号,
scanf("%d,%d,%d", &a, &b, &c); // 输入格式:10,14,20
// 井号#
scanf("%d#%d#%d", &a, &b, &c); // 输入格式:10#14#20
// 字母x
scanf("%dx%dx%d", &a, &b, &c); // 输入格式:10x14x20
数组:
类型 数组名[元素个数]
1、[]只能放在数组名的后面
2、[]里面的个数必须是一个固定值,可以是常量(比如6、8)、常量表达式(比如3+4、5*7)。绝对不能使用变量或者变量表达式来表示元素个数,大多数情况下不要省略元素个数(当数组作为函数的形参和数组初始化时除外)
int a[3];
其实a不算是变量,是个常量,它代表着数组的地址
数组名代表着整个数组的地址,也就是数组的起始地址
第一个元素的地址就是整个数组的地址
C语言中编译器是不会对数组下标越界进行检查的,所以自己访问数组元素时要小心
数组作为形参,参与运算的两种情况
1、维数组的元素作为函数实参,与同类型的简单变量作为实参一样,是单向的值传递,即数组元素的值传给形参,形参的改变不影响实参
// b是test函数的形参(形式参数)
void test(int b) {
b = 9;
}
int main()
{
int a[3];
a[0] = 10;
printf("函数调用前的a[0]:%d\n", a[0]);
test(a[0]); // a[0]是test函数的实参(实际参数)
printf("函数调用后的a[0]:%d", a[0]);
return 0;
}
2、如果一维数组的名字作为函数实参,传递的是整个数组,即形参数组和实参数组完全等同,是存放在同一存储空间的同一个数组。这样形参数组修改时,实参数组也同时被修改了。形参数组的元素个数可以省略。
// b是test函数的形参(形式参数)
void test(int b[]) { // 也可以写int b[3]
b[0] = 9;
}
int main()
{
int a[3];
a[0] = 10;
printf("函数调用前的a[0]:%d\n", a[0]);
test(a); // a是test函数的实参(实际参数)
printf("函数调用后的a[0]:%d", a[0]);
return 0;
}
二维数组在内存中的存放:
1> 数组a的地址是ffc1,数组a[0]的地址也是ffc1,即a = a[0];
2> 元素a[0][0]的地址是ffc1,所以数组a[0]的地址和元素a[0][0]的地址相同,即a[0] = &a[0][0];
3> 最终可以得出结论:a = a[0] = &a[0][0],以此类推,可以得出a[1] = &a[1][0]
字符串:
C语言中没有String这种类型。其实字符串就是字符序列,由多个字符组成,所以在C语言中,我们可以用字符数组来存储字符串
字符串在内存中存储
尾部有个'\0',如果没有这个结束标记,说明这个字符数组存储的并不是字符串
字符串的输出:
1、printf函数
char a[3] = {'m', 'j', '\0'}; //一定要加’\0’
printf("%s", a);
如果没有加’\0’
1 char a[3] = {'m', 'j', '\0'}; // 添加了结束符\0
2
3 char b[] = {'i', 's'}; // 假设忘记添加结束符\0
4
5 printf("字符串a:%s", a); // 输出字符串a
6
7 printf("\n"); // 换行
8
9 printf("字符串b:%s", b); // 输出字符串b
那么输出结果是:
原因:这两个字符数组在内存中的存储是相邻的 没有添加‘\0’表示 这个字符串没有结束因此会继续向下读取数据 因此会读到字符串a中得数据
2.puts函数
1 char a[] = "mj";
2 puts(a);
3
4 puts("lmj");
输出结果为:
有输出的结果还可以看出,puts函数输出一个字符串后会自动换行
字符串的输入:
1.scanf函数
char a[10];
scanf("%s", a)
scanf函数会从a的首地址开始存放用户输入的字符,存放完毕后,系统会自动在尾部加上一个结束标记\0
注意,不要写成scanf("%s", &a),因为a已经代表了数组的地址,没必要再加上&这个地址运算符。
2.gets函数
char a[10];
gets(a);
从a的首地址开始存放用户输入的字符,存放完毕后,系统会自动在尾部加上一个结束标记\0
二者的对比:
gets一次只能读取一个字符串,scanf则可以同时读取多个字符串
* gets可以读入包含空格、tab的字符串,直到遇到回车为止;scanf不能用来读取空格、tab
字符串数组
* 一维字符数组中存放一个字符串,比如一个名字char name[20] = "mj"
* 如果要存储多个字符串,比如一个班所有学生的名字,则需要二维字符数组,char names[15][20]可以存放15个学生的姓名(假设姓名不超过20字符)
* 如果要存储两个班的学生姓名,那么可以用三维字符数组char names[2][15][20]
char names[2][10] = { {'J','a','y','\0'}, {'J','i','m','\0'} };
char names2[2][10] = { {"Jay"}, {"Jim"} };
char names3[2][10] = { "Jay", "Jim" };
字符处理函数:
1.字符输出函数putchar
putchar('A');
putchar一次只能输出一个字符,而printf可以同时输出多个字符
2.字符输入函数getchar
char c;
c = getchar();
getchar会将用户输入的字符赋值给变量c。
* getchar函数可以读入空格、TAB,直到遇到回车为止。scanf则不能读入空格和TAB。
* getchar一次只能读入一个字符。scanf则可以同时接收多个字符。
* getchar还能读入回车换行符,这时候你要敲2次回车键。第1次敲的回车换行符被getchar读入,第2次敲的回车键代表输入结束。
字符串处理函数
1、strlen函数
用来测量字符串的字符个数,不包括\0
int size = strlen("mj"); // 长度为2
2.strcpy函数
char s[10];
2 strcpy(s, "lmj");
strcpy函数会将右边的"lmj"字符串拷贝到字符数组s中。从s的首地址开始,逐个字符拷贝,直到拷贝到\0为止。当然,在s的尾部肯定会保留一个\0。
假设右边的字符串中有好几个\0,strcpy函数只会拷贝第1个\0之前的内容,后面的内容不拷贝
1 char s[10];
2 char c[] = {'m', 'j', '\0', 'l', 'm', 'j', '\0'};
3 strcpy(s, c);
最后字符串s中的内容为:mj
3.strcat函数
char s1[30] = "LOVE";
strcat(s1, "OC");
strcat函数会将右边的"OC"字符串拼接到s1的尾部,最后s1的内容就变成了"LOVEOC" 第一个字符串中得’\0’会被第二个的覆盖
* 注意下面的情况
1 char s1[30] = {'L', 'm', 'j', '\0', 'L', 'o', 'v', 'e', '\0'};
2 strcat(s1, "OC");
3 printf("%s", s1);
第1行初始化的s1有2个\0,经过第2行的strcat函数后,输出结果:
4.strcmp函数
这个函数可以用来比较2个字符串的大小,调用形式为:strcmp(字符串1, 字符串2)
如果全部字符都相同,则返回值为0。如果不相同,则返回两个字符串中第一个不相同的字符ASCII码值的差。即字符串1大于字符串2时函数返回值为正,否则为负。