Question 1

1)Please explain why modern computers adopt binary systems? (5 marks)

2)What`s the difference when storing an integer 1 and a character ’1’? (5 marks)

Answer:

1)Binary numbers are ideal for machines because they require only two digits, which can easily be represented by the on and off states of a switch. When computers became electronic, the binary system was particularly appropriate because an electrical circuit is either on or off.

https://www.britannica.com/technology/computer/History-of-computing

这是一个技术问题,不是科学问题,原则上什么进制都可以。

旋钮开关也是开关,只是on/off双态开关更容易实现、可靠性更高。还有一点就是,它能表达一切!

关键是开关电路和逻辑运算之间的联系才导致了现代计算机采用二进制系统。

题外话:1,据说Knuth有意设计十进制计算机系统;2,据说从信息论角度看e(自然对数的底)进制是信息密度最高的进制。3比2更靠近\(e\),不知道3态开关如何设计?

分数构成

学期开始就告知大家,本课程最终成绩由平时成绩(2次机考),期中考试、和期末考试组成。

其中:平时成绩占40%、期中考试占20%、期末考试占40%。这个比例不变。

  • 平时成绩,由两次机考构成(原本计划4次机考,后受疫情影响合并成2次),每次按排名计分,两次的平均分即为平时成绩的分。
    • 排名转换百分制:第1名100分,后续名次的分计算方法:
      • s[i] = s[i - 1] - (i < 10 ? 0.1 : (i < 25 ? 0.2 : (i < 35 ? 0.3 : (i < 45 ? 0.4 : (i < 50 ? 0.5 : (i < 60 ? 0.6 : 0.8))))));
      • 允许并列,最后的分会取整。
      • 及格线的划定:第一次机考100分,第二次机考120分。低于及格线不按排名记得分,而是以机考分数除以2计分。
  • 期中考试成绩,按卷面得分计(实际作了适当调整)。
  • 期末考试成绩,按卷面得分计。

关于复习的几点建议:

计算机计算的技术原理是什么?读程序、写程序。

导论如何复习?看crash course吧,想想为什么!

凡事要了解背后的原理。。。WHAT是最简单的,还是需要学会问问WHY,然后HOW去做

  • 计算机为什么能计算、如何做计算?
    • 计算机诞生过程中的硬件技术发展,为什么?
    • 计算机软件技术的发展,比如:操作系统中关注什么样的问题,为什么?
    • 输入字符串是任意一个四则运算表达式,比如:\(13 + (4 - (32 + 8)) \times 7 + 23 / (8 -2)\),你会算吧?不要到网上查任何资料,你也可以编写代码求解字符串所代表的表达式的值。试试看吧。
    • 学会Abstraction
  • 现代计算机的体系结构,von Neumann结构
  • 数据结构+算法=程序、
  • 计算的效率如何?算法的复杂度、问题的复杂度。
  • 测试用例(可以用来了解你的程序的intention)、调试。

通常函数值是唯一的。

但是,函数的定义域(domain)和陪域(codomain)都可以是复杂的集合。

$$f:X\times Y \times Z \rightarrow W \times U \times V$$

  1. 在计算机语言中,就用结构体来支持。也就是可以把想要返回的数据打包在一起以结构体的形式返回。
  2. 另一个办法是:采用地址参数的方式让函数修改调用函数中的多个变量。
struct account {
   int account_number;
   char *first_name;
   char *last_name;
   float balance;
};
struct account {
   int account_number;
   char *first_name;
   char *last_name;
   float balance;
} Account[20];
   int account_number[20];
   char *first_name[20];
   char *last_name[20];
   float balance[20];

Which is better?

从逻辑上来思考问题。

In C, array indexing is formally defined in terms of pointer arithmetic. We CAN create an array by using pointer only.

Note: This program may cause segmentation fault in some systems.

/* Desc: Using only pointer to create variable and array.
	some system may not work, because of segmentation fault.

Author: Liutong XU
*/
#include<stdio.h>
 
int main()
{
	int a;
	int *p=&a+1;		//p point a's neibough
				//some system may cause segmentation fault

	for (*p=0;*p<10;(*p)++)        //*p used as a loop variable
		scanf("%d",&p[10+*p]); //p+10~p+19 used as an integer array
 
	for (p[0]=0;p[0]<10;p[0]++)    //p[0] is same as *p
		printf("%d\t",p[10+p[0]]); 
 
	return 0;
}

stdin

1 2 3 4 5 6 7 8 9 0

stdout

1   2   3   4   5   6   7   8   9   0

Dynaminc Memory Allocation

Segmentation fault normally is caused by invalid pointer reference, because p+20 may violate other variables.

If we have enough valid memory segment for pointer, then no violation will occur.

/* Desc: Dynamic memory allocation

    dynamically allocated memory may be used as variable or array, 
    but with no common names

Author: Liutong XU
*/
#include<stdio.h>
#include<stdlib.h>
int main()
{
	int *p;        
	p = malloc(20);			//p points to a 20-byte memory

	for (*p=0;*p<10;(*p)++)		//*p used as a loop variable
		scanf("%d",&p[10+*p]);	//p+10~p+19 used as an integer array
 
	for (p[0]=0;p[0]<10;p[0]++)	//p[0] is same as *p
		printf("%d\t",p[10+p[0]]); 
 
	free(p);
	return 0;
}

stdin

1 2 3 4 5 6 7 8 9 0

stdout

1   2   3   4   5   6   7   8   9   0

赋值与传函数参数:

  • 普通变量,char、int、double之类的,直接赋值;

a = b;

变量b中的值就会复制到变量a中,a中的值和b中的值相等。

  • 地址变量的赋值,本质上和普通变量一样,需要注意的是:复制的是地址值,而非地址指向的值。

p1 = p2;

  • 如果想要针对地址指向的值做操作,就需要解引用:(地址也可以理解为句柄,用句柄可以抓住另一个具体的数据。)

*p1 = *p2;

  • 数组变量,比较特殊,数组名是地址,所以,不能直接用赋值语句来复制整个数组。作为函数参数时,就是传地址,复制一份地址值。
  • 结构体变量,可以当作普通变量看待,可以直接赋值。作为函数参数时,就是传值,复制一份结构体的值(内容)。

函数返回

  • void 函数,没有返回值,函数体内也不需要return语句。
  • 函数返回普通类型,程序运行中,会把该类型的值,如a+b,返回给主调函数,以函数调用的方式表达,如add(a, b)。注意该值并不位于被调函数的stack frame中,因此,主调函数可见。
  • 函数返回地址类型,此时需要特别注意的是:该地址指向的内存区域必须是主调函数可见的,即或者是主调函数中变量的地址、或者是动态分配的heap中内存地址,而绝不能是被调函数的局部变量的地址。

指针的句柄作用

动态分配的内存单元的首地址,必须赋值给某个指针(地址)变量。指针可以抓住该内存单元,即通过该指针来访问该内存单元。这就是指针的句柄作用。否则,所分配的内存单元就会消失,内存单元物理存在,但是程序中已经不可见了。

char str[10];

printf("%c", str[5]);

printf("%s", &str[5]);

scanf("%c", &str[5]);

scanf("%s", &str[5]);

分别是指什么?

string is an array of char, it contains a string, while string pointer is just a pointer, which points to a string, And, string literal cannot been overwritten.

/*Desc: string and string pointer
	string is an array of char, it contains a string
	string pointer is just a pointer, which points to a string
	And, string literal cannot been overwritten.

Author: Liutong XU
*/
#include <stdio.h>
#include<string.h>
main()
{ 
	char s[81]={"Hello"};
	char *sp1,*sp2;
	printf("s = %s\n",s);
	sp1 = "Hello World!";	
//OK, sp1 points to a string literal "Hello World!" sp2 = sp1; //OK, sp2 points to same string as sp1 does printf("sp1 points to: %s\n",sp1); printf("sp2 points to: %s\n",sp2); //s = "Hi"; //Not valid strcpy(s,"Hi"); //OK printf("s = %s\n",s); //strcpy(sp1,"Bye"); //Not valid; sp1 is just a pointer sp1 = s; printf("sp1 points to: %s\n",sp1); strcpy(sp1,"ByeBye"); //OK now, because sp1 points to s. printf("sp1 points to: %s\n",sp1); printf("s = %s\n",s); return 0; }

stdout

s = Hello
sp1 points to: Hello World!
sp2 points to: Hello World!
s = Hi
sp1 points to: Hi
sp1 points to: ByeBye
s = ByeBye

指针数组

int a[10];

int *ap[10]; 

数组指针

int (*ap)[10];

int a[5][10];

ap = &a[0];             // ap 指向 a[0]

ap++;                         // ap 指向 a[1]

数组定义的详细说明:

指针的指针

int **ap;