目录
Hexadecimal representation 十六进制表示法
Pointers 指针
Numeral Systems 进制
数字系统…用数字或其它符号表示数字的系统。
大多数文化都发展了十进制decimal system(以10为基础)
对于计算机来说,使用二进制binary(以2为基数)或十六进制hexadecimal system(以16为基数)是很方便的
Decimal representation 十进制表示法
- Base is 10; digits 0 - 9
- Example: decimal number 4705 can be interpreted as
4· + 7· + 0· + 5·
Binary representation 二进制表示法
- Base is 2; digits 0 and 1
- Example: binary number 1101 can be interpreted as
1· + 1· + 0· + 1·
Hexadecimal representation 十六进制表示法
- The base is 16; digits 0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F
- Example: hexadecimal number 3AF1 can be interpreted as
3· + 10· + 15· + 1·
❖ Exercise: Conversion Between Different Numeral Systems |
- Convert
74
to base 2- Convert
0x2D
to base 10 // 16进制- Convert
0b1011111000101001
to base 16 Hint:1011111000101001 //二进制
- Convert
0x12D
to base 2
Memory 存储
char
… 1 byteint,float
… 4 bytesdouble
… 8 bytes
如果我们声明一个名为k变量,存储k的位置用&k表示,也称为k的地址
用十六进制表示法打印内存地址很方便
int k;
int m;
printf("address of k is %p\n", &k);
printf("address of m is %p\n", &m);
output: address of k is BFFFFB80 address of m is BFFFFB84
这意味着
k占用从bfffb80到bfffb83的四个字节
m占用从bfffb84到bfffb87的四个字节
注意使用%p作为地址的占位符(“指针”值)
int array[5];
for (i = 0; i < 5; i++) {
printf("address of array[%d] is %p\n", i, &array[i]);
}
output: address of array[0] is BFFFFB60 address of array[1] is BFFFFB64 address of array[2] is BFFFFB68 address of array[3] is BFFFFB6C address of array[4] is BFFFFB70
❖ Application: Input Using |
#include <stdio.h>
…
int answer;
printf("Enter your answer: ");
scanf("%d", &answer);
float e;
printf("Enter e: ");
scanf("%f", &e);
❖ Exercise: Using |
写一个程序
输入数字,检查是否是正数,将Collatz的过程应用于数字
#include <stdio.h>
void collatz(int n) {
printf("%d\n", n);
while (n != 1) {
if (n % 2 == 0)
n = n / 2;
else
n = 3*n + 1;
printf("%d\n", n);
}
}
int main(void) {
int n;
printf("Enter a positive number: ");
if (scanf("%d", &n) == 1 && (n > 0)) /* test if scanf successful
and returns positive number */
collatz(n);
return 0;
}
Pointers 指针
指针是一种特殊类型的变量,用来存储另一个变量的地址(内存位置)
指针的值是一个地址
指针占用内存空间,就像任何其他特定类型的变量一样
指针所需的内存单元数取决于计算机的体系结构:
旧电脑或只有64KB可寻址内存的手持设备:
2个存储单元(即16位),用于保存从0x0000到0xFFFF(=65535)的任何地址
具有4GB可寻址内存的台式机
4个存储单元(即32位),用于保存从0x00000000到0xffffff(=4294967295)的任何地址
现代64位计算机
8个内存单元(可以寻址264字节,但实际上内存量受到CPU的限制)
定义方式
*p = 'T'; // sets the value of c to 'T'
// a potential pointer to any object of type char char *s; // a potential pointer to any object of type int int *p;
❖ Examples of Pointers |
int *p; int *q; // this is how pointers are declared int a[5]; int x = 10, y; p = &x; // p now points to x *p = 20; // whatever p points to is now equal to 20 y = *p; // y is now equal to whatever p points to p = &a[2]; // p points to an element of array a[] q = p; // q and p now point to the same thing
❖ Exercise: Pointers |
output: 1 #include <stdio.h> 2 3 int main(void) { 4 int *ptr1, *ptr2; 5 int i = 10, j = 20; 6 7 ptr1 = &i; 8 ptr2 = &j; 9 10 *ptr1 = *ptr1 + *ptr2; 11 ptr2 = ptr1; 12 *ptr2 = 2 * (*ptr2); //ptr2=ptr1=60 13 printf("Val = %d\n", *ptr1 + *ptr2); 14 return 0; 15 }
Can we write a function to "swap" two variables?
The wrong way:
void swap(int a, int b) {
int temp = a; // only local "copies" of a and b will swap
a = b;
b = temp;
}
int main(void) {
int a = 5, b = 7;
swap(a, b);
printf("a = %d, b = %d\n", a, b); // a and b still have their original values
return 0;
}
只改变了function里面的值 函数不能直接改变主函数里定义的变量的值
在C语言中,参数是“按值调用”
对参数值所做的更改不会影响原始值
函数swap()尝试交换a和b的值,但失败了,因为它只交换副本,而不交换main()中的实际变量
我们可以通过传递指针作为参数来实现“引用模拟调用”
这允许函数更改变量的“实际”值
void swap(int *p, int *q) {
int temp = *p; // change the actual values of a and b
*p = *q;
*q = temp;
}
int main(void) {
int a = 5, b = 7;
swap(&a, &b);
printf("a = %d, b = %d\n", a, b); // a and b now successfully swapped
return 0;
}
Pointer Arithmetic 指针算法
指针变量包含一个地址值。
C知道所指向的对象的类型
它知道那个项目的大小
它可以计算下一个/上一个对象的位置
int a[6]; // assume array starts at address 0x1000 int *p; p = &a[0]; // p contains 0x1000 p = p + 1; // p now contains 0x1004
对于声明为T*p的指针(其中T是一个类型)
如果指针最初包含地址
执行p=p+k(其中k是常数)
将p中的值更改为A+k*sizeof(T)
k的值可以是正的,也可以是负的。
int a[6]; (addr 0x1000) char s[10]; (addr 0x2000) int *p; (p == ?) char *q; (q == ?) p = &a[0]; (p == 0x1000) q = &s[0]; (q == 0x2000) p = p + 2; (p == 0x1008) q++;
Pointers and Arrays 指针和数组
通过数组进行迭代的另一种方法:
确定数组中第一个元素的地址
确定数组中最后一个元素的地址
设置指针变量以引用第一个元素
使用指针算法在元素之间移动
当地址超过最后一个元素时终止循环
int a[6];
int *p;
p = &a[0];
while (p <= &a[5]) {
printf("%2d ", *p);
p++;
}
Arrays of Strings 字符串数组
一种常见的指针/数组组合是命令行参数
这些是运行程序时指定的0个或多个字符串
假设您有一个名为seqq的可执行程序。如果在终端中运行此命令:
./seqq 10 20
然后seqq将得到2个命令行参数:“10”,“20”
argv[]的每个元素都是
指向字符数组开头的指针(char*)
包含以\0结尾的字符串
argv
is represented:
./seqq 5 20
如果要访问命令行参数,main()需要不同的原型:
int main(int argc, char *argv[]) { ...
main(int argc,char *argv[ ])
1.argc为整数
2.argv为指针的指针(可理解为:char **argv or: char *argv[] or: char argv[][] ,argv是一个指针数组)
注:main()括号内是固定的写法。
argc…存储命令行参数的数目+1 如果没有命令行参数,则argc==1
argv[]…存储程序名+命令行参数
argv[0]始终包含程序名
argv[1]、argv[2]、…是命令行参数(如果提供)
<stdlib.h>定义用于转换字符串的有用函数:
atoi(char *s)
将字符串转换为int
atof(char *s)
将字符串转换为double(也可以指定给float变量)
❖ Exercise: Command Line Arguments |
写一个程序
检查单个命令行参数
如果不是,则输出失败消息并退出
将此参数转换为数字并检查它是否为正数
将Collatz的过程(练习3,第1周的习题集)应用于数字
#include <stdio.h>
#include <stdlib.h>
void collatz(int n) {
printf("%d\n", n);
while (n != 1) {
if (n % 2 == 0)
n = n / 2;
else
n = 3*n + 1;
printf("%d\n", n);
}
int main(int argc, char *argv[]) {
if (argc != 2) {
printf("Usage: %s number\n", argv[0]);
return 1;
}
int n = atoi(argv[1]);
if (n > 0)
collatz(n);
return 0;
}
argv可以看作双指针(指向指针的指针)
⇒ main()的替代原型:
int main(int argc, char **argv) { ...
argv[0]
,
argv[1]
, …