目录
Pointers 指针
Numeral Systems 进制
Decimal representation 十进制表示法
Binary representation 二进制表示法
Hexadecimal representation 十六进制表示法
Memory 存储
Pointers 指针
Pointer Arithmetic 指针算法
Pointers and Arrays 指针和数组
Arrays of Strings 字符串数组
数字系统…用数字或其它符号表示数字的系统。
大多数文化都发展了十进制decimal system(以10为基础)
对于计算机来说,使用二进制binary(以2为基数)或十六进制hexadecimal system(以16为基数)是很方便的
❖ 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
char
… 1 byte int,float
… 4 bytes double
… 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
…
int answer;
printf("Enter your answer: ");
scanf("%d", &answer);
float e;
printf("Enter e: ");
scanf("%f", &e);
❖ Exercise: Using |
写一个程序
输入数字,检查是否是正数,将Collatz的过程应用于数字
#include
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;
}
指针是一种特殊类型的变量,用来存储另一个变量的地址(内存位置)
指针的值是一个地址
指针占用内存空间,就像任何其他特定类型的变量一样
指针所需的内存单元数取决于计算机的体系结构:
旧电脑或只有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
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;
}
指针变量包含一个地址值。
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++;
通过数组进行迭代的另一种方法:
确定数组中第一个元素的地址
确定数组中最后一个元素的地址
设置指针变量以引用第一个元素
使用指针算法在元素之间移动
当地址超过最后一个元素时终止循环
一种常见的指针/数组组合是命令行参数
这些是运行程序时指定的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]、…是命令行参数(如果提供)
atoi(char *s)
将字符串转换为int
atof(char *s)
将字符串转换为double(也可以指定给float变量)
❖ Exercise: Command Line Arguments |
写一个程序
检查单个命令行参数
如果不是,则输出失败消息并退出
将此参数转换为数字并检查它是否为正数
将Collatz的过程(练习3,第1周的习题集)应用于数字
#include
#include
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]
, …