CS1010 Advanced Placement Test 注意事项

Preface

其实就是一些 C 里面容易犯的错误或者细节

Case 1: 对未初始化的结构体指针里的成员进行操作

1
2
3
4
5
6
typedef struct Customer{
int id;
char lname[25];
}customer;

customer *this1;

假设我们有这么一段代码,那么以下代码段是错误的

1
2
this1->id = 19260817;
scanf("%s", this1->lname);

原因是我们还没有给结构体指针变量赋予一个有效的结构体变量地址,相当于一个野指针

下列代码是正确的:

1
2
3
4
5
customer tmp;
customer *this1 = &tmp;
...
this1->id = 19260817;
scanf("%s", this1->lname);

Case 2: 指针作为函数参数

下面一段代码

1
2
3
4
5
6
7
void foo(char *str){
str = "lbwnb";
return ;
}
...
char *p = NULL;
foo(p);

函数调用之后如果输出p ,我们会发现它依旧是 NULL 而不是 lbwnb

因为这个指针是作为函数形参,它原本指向的内存地址不会受函数的影响

如果我们想修改 *p 的值呢?有两种方法

1
2
3
4
5
6
7
char *foo(char *str){
str = "lbwnb";
return str;
}
...
char *p = NULL;
p = foo(p);
1
2
3
4
5
6
void foo(char **str){
*str = "lbwnb";
return ;
}
char *p = NULL;
foo(&p);

第二种方法可能理解起来有点抽象,我们可以这么想,p 是一个指针,它指向的值是NULL的地址,而它(也就是这个指针 p)的内存地址假设是 1926. 然后我们把一个指向这个内存地址 1926 的指针 str 传进一个函数里,然后 *str = "lbwnb" 也就是说,这个内存地址( 1926 )指向的值的地址变成 lbwnb 的地址。

这时函数调用结束, p 的内存地址还是1926, 但是它指向的地址已经变成 lbwnb 的地址,所以 *p = "lbwnb"

Case 3: 字符指针与字符数组区别

字符数组并不能等于一个字符指针(反之亦然);只是在一些情况下能认为是一样的,比如他们作为函数参数进行传递时。但是还是有很多不同

1
2
3
4
5
/*声明赋值方式不一样*/
char a[] = "abc";

char *a;
a = "abc“

上面代码所展现是正确的方法,并不能在声明 char a[] 之后利用 a = "abc" 来进行赋值

1
2
3
char a[] = "abc";
char b[] = "cde";
a=b;

上面的代码是错误的,数组作为l-value 不能进行这样的运算

1
2
3
char *a = "abc";
char *b;
b = a;

上面的代码是正确的

1
2
3
4
5
6
7
8
9
/*这是正确的*/
char a[] = "abc";
char *b;
b = a;

/*这是错误的*/
char a[5];
char *b = "abcde";
a = b;

这篇博客 还看到了一个之前没有注意过的细节

1
2
3
4
5
6
7
8
9
10
11
void foo(char *str){
*(str) = 'd';
strcpy(str, "def");
return ;
}
int main(){
char p[] = "abc";
foo(p);
printf("%s\n", p);
return ;
}

这段代码编译运行没有任何问题 (本地环境 gcc 4.8.1) 奇怪的是在 ideone.com 里运行虽然会有运行结果但显示 Runtime Error

但是下面的代码无论是本地还是 ideone.com 都不会输出运行结果并且显示运行时错误

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>
#include <string.h>
void foo(char *str){
*(str) = 'd';
strcpy(str, "def");
return ;
}
int main(){
char *p = "abc";
foo(p);
printf("%s\n", p);
return ;
}

原因是“ 字符指针指向的是一个常量存储区地址,是不允许修改的 ”。函数的参数是 const 类型的

Case 4: 字符串终止符的打印

\0 如果以_字符串_形式打印出来啥都没有,但是如果以_字符_ 形式打印出来是一个空格

(在 WSL上的gcc 5.4.0Visual C++ 上是这样的,但是 gcc 4.8.1 两者都不会有任何打印结果

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

char *str;
char ptr;
int main(){
str = "\0";
ptr = '\0';
printf("-%c- -%c- -%s-",ptr,*str, str);
return 0;
}