第三夜:指针和数组

今晚复习C语言的指针和数组。

指针

指针:指向一个变量的地址。

声明方式:

1
2
int *p;
char *q;

C语言ptr变量名的含义:pts就是**Pointer Recod(er)**的简写

指针的使用:定义指针变量、把变量地址赋值给指针、访问指针变量指向的地址的值。

空指针:指向0x0,啥也不是。

指针的值:指针的值的类型都是一样的,长度等于一个单位地址的长度的16进制数值(32位、64位等)

指针的类型:指针指向的数据类型必须是一个有效的 C 数据类型。

例如,在32位系统中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>

int main (){
int *p;
char *t;
printf("Length of p: %d\n", sizeof(p));
printf("Length of t: %d\n", sizeof(t));
printf("Length of *p: %d\n", sizeof(*p));
printf("Length of *t: %d\n", sizeof(*t));
}

/*
执行结果:
Length of p: 4
Length of t: 4
Length of *p: 4
Length of *t: 1
*/

指针的算数运算

指针可以进行++、--、+、-等运算。

例:指针递增

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>

const int MAX = 3;

int main (){
int var[] = {10, 100, 200};
int i, *ptr;

/* 指针中的数组地址 */
ptr = var;
for ( i = 0; i < MAX; i++) {

printf("存储地址:var[%d] = %x\n", i, ptr );
printf("存储值:var[%d] = %d\n", i, *ptr );

/* 移动到下一个位置 */
ptr++;
}
return 0;
}

指针数组

可以通过指针来声明数组

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>

int main (){
const char *names[4] = { "Tom", "Bob", "Tony", "Jack" };

int i = 0;
while ( i < 4 ) {
printf("Value of names[%d] = %s\n", i, names[i] );
i++;
}
return 0;
}

指向指针的指针

指向指针的指针是一种多级间接寻址的形式,或者说是一个指针链。通常,一个指针包含一个变量的地址。当我们定义一个指向指针的指针时,第一个指针包含了第二个指针的地址,第二个指针指向包含实际值的位置。

例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <stdio.h>

int main (){
int var;
int *ptr;
int **pptr;

var = 3000;

ptr = &var; // 取var的地址作为指针ptr的值

pptr = &ptr; // 取ptr的地址作为pptr的值

printf("&var(%x) => var(%d)\n", &var, var );
printf("&ptr(%x) => ptr(%x) => *ptr(%d)\n", &ptr, ptr,*ptr );
printf("&pptr(%x) => pptr(%x) => **pptr(%d)\n", &pptr, pptr, **pptr);

return 0;
}

/*
执行结果:
&var(ffe3b11c) => var(3000)
&ptr(ffe3b118) => ptr(ffe3b11c) => *ptr(3000)
&pptr(ffe3b114) => pptr(ffe3b118) => **pptr(3000)
*/

指针作为函数参数

当指针(地址)作为函数参数时,函数可以在执行过程中改变指针所指向值:
例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <stdio.h>
#include <time.h>

void getSeconds(unsigned long *par);

int main (){
unsigned long sec;
printf("[main] &sec(%x)=>sec(%ld): \n", &sec,sec);
getSeconds( &sec );
printf("[main] sec: %ld\n", sec );
return 0;
}

void getSeconds(unsigned long *par){
printf("[getSeconds] &par(%x)=>par(%x): \n", &par, par);
/* 获取当前的秒数 */
*par = time( NULL );
return;
}

指针作为函数返回值

指针作为函数返回值时,调用方可以直接访问这个地址:
例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <stdio.h>

int * getList();

int main (){
int * i;
int j;
printf("[main] &i(%x) => i(%x)\n", &i,i);
i = getList();
printf("[main] &i(%x) => i(%x)\n", &i,i);
//for(j=0;j<5;j++)
// printf("%d\t", i[j]);
return 0;
}

int * getList(){
static int list[5]={1,2,3,4,5};
printf("[getList] &list(%x) => list(%x)\n", &list,list);
return list;
}

/*
执行结果:
[main] &i(ff94f03c) => i(5661b25b)
[getList] &list(5661e01c) => list(5661e01c)
[main] &i(ff94f03c) => i(5661e01c)
*/

数组

一维数组

1
2
int arr[] = {1,2,3,4,5};
char list[] = {"Tom", "Tony"};

多维数组

多维数组可以通过在括号内为每行指定值来进行初始化:

1
2
3
4
5
6
7
8
9
10
int a[3][4] = {  
{0, 1, 2, 3} , /* 初始化索引号为 0 的行 */
{4, 5, 6, 7} , /* 初始化索引号为 1 的行 */
{8, 9, 10, 11} /* 初始化索引号为 2 的行 */
};

// Or

int a[3][4] = {0,1,2,3,4,5,6,7,8,9,10,11};

多维数组的访问:

1
int val = a[2][3]; //获取数组中第2行第3个元素

数组作为函数参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <stdio.h>

/* 函数声明 */
double getAverage(int arr[], int size);

int main (){
/* 带有 5 个元素的整型数组 */
int balance[5] = {1000, 2, 3, 17, 50};
double avg;

/* 传递一个指向数组的指针作为参数 */
avg = getAverage( balance, 5 ) ;

/* 输出返回值 */
printf( "平均值是: %f ", avg );

return 0;
}

double getAverage(int arr[], int size){
int i;
double avg;
double sum=0;

for (i = 0; i < size; ++i) {
sum += arr[i];
}

avg = sum / size;

return avg;
}

数组作为函数返回值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

/* 要生成和返回随机数的函数 */
int * getRandom(){
static int r[10];
int i;

/* 设置种子 */
srand( (unsigned)time( NULL ) );
for ( i = 0; i < 10; ++i){
r[i] = rand();
printf( "r[%d] = %d\n", i, r[i]);
}

return r;
}

/* 要调用上面定义函数的主函数 */
int main (){
/* 一个指向整数的指针 */
int *p;
int i;

p = getRandom();
for ( i = 0; i < 10; i++ ) {
printf( "*(p + %d) : %d\n", i, *(p + i));
}

return 0;
}

指针和数组的关系

在C语言中,数组名是一个指向数组中第一个元素的常量指针,例如

1
double balance[50];

这个数组中,balance是一个指向&balance[0] 的指针,即数组 balance 的第一个元素的地址。

因此,把 p 赋值为 balance 的第一个元素的地址:

1
2
3
4
double *p;
double balance[10];

p = balance;

使用数组名作为常量指针是合法的,反之亦然。因此,*(balance + 4) 是一种访问 balance[4] 数据的合法方式。

把第一个元素的地址存储在 p 中,就可以使用 *p、*(p+1)、*(p+2) 等来访问数组元素(也等同于*list+1)。

第四夜:存储类型、结构体、链表 第二夜:函数、作用域、预处理和头文件
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×