C Hello World Again
本文是我给地空学院的学生的C语言讲座的讲稿
Hello World Again
[TOC]
指针与数组
a[i]=*(a+i)=i[a]
int (*x)[10]
与int *x[10]
的区别
前者是指向一个长度为10的整型数组的指针
后者是一个长度为10的(指向整型变量的指针)的数组
指针与数组的互换
1for(int i=0;i<10;++i)
2{
3 a[i]=0;
4}
5
6for (int *p = a; p != (a + 10); ++p)
7{
8 printf("%d\n", *p);
9}
10
C风格的字符串处理
字符串的表示
1char s[100]="Hello";
1char *s="Hello";
2// 这是一个特殊的行为
3// 注意到int *x=2是完全错误的
4// 但这个语句是对的
5// 编译器会开辟一块内存来存放"Hello"并用s指向它
6// 但注意:这个"Hello"是不可更改的
7// 例如下面的语句会出现错误
8s[1]='a';
1printf("%c\n", "abc"[2]);//输出c
2printf("%s\n", "abc"+1); //输出bc
3//此处的"abc"会被解释为指向char数组{'a','b','c','\0'}的指针
1char s[100]={'a','b','c'};
1char *s = (char *)malloc(sizeof(char) * 10);
2*s++ = 'a';
3*s++ = 'b';
4*s++ = 'c';
5printf("%s", s - 2); //输出bc
6printf("%s", s - 1); //输出c
7free(s - 3); //释放掉用malloc申请的内存
8
字符串拷贝
1void strcpy1(char *a, char *b) //把b赋给a
2{
3 while (*b)
4 {
5 *a++ = *b++;
6 }
7 while (*a)
8 {
9 *a++ = '\0';
10 }
11}
12
13int main()
14{
15 char a[100];
16 char b[100];
17 while (1)
18 {
19 scanf("%s", b);
20 strcpy1(a, b);
21 printf("%s\n", a);
22 }
23}
求值顺序
1printf("%c%c%c\n",getchar(),getchar(),getchar());
该语句在gcc编译器下的作用是:读入三个字符并倒序输出。 因为gcc编译器的实现方法是从右向左求值
变量作用域
1{
2 int x=2;
3}
4printf("%d",x); //不会输出
1int x=8;
2{
3 int x=3;
4 printf("%d",x);// 输出3
5}
用宏实现max函数
#define MAX(x,y) x > y ? x : y
但考虑MAX(1!=2,3)为1 != 2 > 3 ? 1 != 2 : 3
由于!=
的优先级小于>
因此上式为1 != (2>3) ? 1!=2 : 3
为(1 != 0) ? 1!=2 : 3
为1 ? 1 : 3
为1
而该式应该是MAX(1,3)=3
因此加括号为
#define MAX(x,y) (x) > (y) ? (x) : (y)
但考虑3+ MAX(1,2)
为3 + 1 > 2 ? 1 : 2
为4 > 2 ? 1 : 2
为1 ? 1 : 2
为1
而实际上应该是5
因此我们继续修改这个宏
#define MAX(x,y) ((x) > (y) ? (x) : (y))
但考虑MAX(i++,j++)
展开后为i++ > j++ ? i++ : j++
这会使得i与j都自增两次
为此考虑这么定义宏
1#define MAX(x,y)({ \
2 int _x = x; \
3 int _y = y; \
4 _x > _y ? _x : _y; \
5})
该宏会重新定义两个变量_x与_y来进行比较,从而使得MAX(i++,j++)符合要求。
函数与数组的相似点与共同点
相似点: 数组声明:int x[10] 函数声明:int sum(int,int) 数组类型:int [10] 函数类型:int (int,int) 数组指针:int (x)[10] 函数指针:int (sum)(int,int) 数组指针类型:int ()[10] 函数指针类型:int ()(int,int)
数组、函数共同点: 1.数组、函数都不可拷贝。
2.因为第1点,数组、函数不可以做函数的返回值,但函数可以返回数组的指针或函数的指针。
3.数组、函数可用于函数形参,但因为第1点,编译器会对其做处理。如果形参类型为数组,实际形参类型会转换成元素类型的指针,例如voidfun(int arr[5])等价于void fun(int arr*)。如果形参类型为函数,实际形参类型会转换成对应的函数指针类型,例如void fun (int test())等价于voidfun( int (*test)())
如何返回一个数组
用结构体包装一下
1#include <stdio.h>
2
3#define MAXNUM 1000
4
5struct Array
6{
7 int a[MAXNUM];
8};
9
10struct Array DoubleIt(struct Array x)
11{
12 struct Array y;
13 for (int i = 0; i < MAXNUM; ++i)
14 {
15 y.a[i] = (x.a[i] << 1); //移位运算符的优先级非常低,应该在可能的情况下加上括号
16 }
17 return y;
18}
19
20int main()
21{
22 struct Array a = {1, 2, 3, 4, 5};
23 struct Array b = DoubleIt(a);
24 for (int i = 0; i < 5; ++i)
25 {
26 printf("%d\n", b.a[i]);
27 }
28}
29
推荐阅读书目:
《C专家编程》 《C陷阱与缺陷》 《征服C指针》 以上三本在图书馆应该都能借到,特别推荐《征服C指针》,是日本最受欢迎的C语言书籍之一,写的很好
C学习经验
- 多写一些简单的程序做实验,验证自己的想法。从实践中学习。
- 多写代码,多写代码,多写代码。
- 找一些好书看,不要看谭浩强啥的。。 比如《C与指针》,《C专家编程》,《C陷阱与缺陷》,《明解C指针》。
- 学会使用搜索引擎。
- 不要害怕写代码,其实真的不难。。这个属于技术活,写的越多越熟练。
- C其实是比较偏向底层的语言,如果有对于计算机硬件底层相关的知识可能会更好理解。