指针相关。。

来源:互联网 发布:淘宝网什么包包好卖 编辑:程序博客网 时间:2024/05/11 14:35

2.13 以下的初始化有什么区别?char a[] ="stringliteral"; char *p = "stringliteral"; 当我向 p[i] 赋值的时候, 我的程序崩溃了。

字符串常量有两种稍有区别的用法。用作数组初始值 (如同在 char a[] 的声明中), 它指明该数组中字符的初始值。其它情况下, 它会转化为一个无名的静态字符数组, 可能会存储在只读内存中, 这就是造成它不一定能被修改。在表达式环境中, 数组通常被立即转化为一个指针 (参见第 6 章), 因此第二个声明把 p 初始化成指向无名数组的第一个元素。

7.1 我在一个源文件中定义了 char a[6], 在另一个中声明了 extern char *a 。为什么不行 ?

你在一个源文件中定义了一个字符串, 而在另一个文件中定义了指向字符的指针。 extern char * 的申明不能和真正的定义匹配。 类型 T 的指针和类型 T 的数组并非同种类型。 请使用 extern char a[ ]。

7.2 可是我听说 char a[ ] 和 char *a 是一样的。

并非如此。(你所听说的应该跟函数的形式参数有关;参见问题 6.4) 数组不是指针。 数组定义 char a[6] 请求预留 6 个字符的位置, 并用名称 ``a" 表示。也就是说, 有一个称为 ``a" 的位置, 可以放入 6 个字符。 而指针申明 char *p, 请求一个位置放置一个指针, 用名称 ``p" 表示。 这个指针几乎可以指向任何位置: 任何字符和任何连续的字符, 或者哪里也不指(参见问题 5.1 和 1.10)。

一个图形胜过千言万语。声明

    char a[] = "hello";    char *p = "world";
将会初始化下图所示的数据结果:
       +---+---+---+---+---+---+    a: | h | e | l | l | o |\0 |       +---+---+---+---+---+---+       +-----+     +---+---+---+---+---+---+    p: |  *======> | w | o | r | l | d |\0 |       +-----+     +---+---+---+---+---+---+

根据 x 是数组还是指针, 类似 x[3] 这样的引用会生成不同的代码。认识到这一点大有裨益。以上面的声明为例, 当编译器看到表达式 a[3] 的时候, 它生成代码从 a 的位置开始跳过 3 个, 然后取出那个字符. 如果它看到 p[3], 它生成代码找到 ``p" 的位置, 取出其中的指针值, 在指针上加 3 然后取出指向的字符。换言之, a[3] 是名为 a 的对象 (的起始位置) 之后 3 个位置的值, 而 p[3] 是 p 指向的对象的 3 个位置之后的值. 在上例中, a[3] 和 p[3] 碰巧都是 'l' , 但是编译器到达那里的途径不尽相同。本质的区别在于类似 a 的数组和类似 p 的指针一旦在表达式中出现就会按照不同的方法计算, 不论它们是否有下标。下一问题继续深入解释。

7.6 现实地讲, 数组和指针地区别是什么 ?

数组自动分配空间, 但是不能重分配或改变大小。指针必须明确赋值以指向分配的空间 (可能使用 malloc), 但是可以随意重新赋值 (即, 指向不同的对象), 同时除了表示一个内存块的基址之外, 还有许多其它的用途。

由于数组和指针所谓的等价性(参见问题 6.3), 数组和指针经常看起来可以互换, 而事实上指向 malloc 分配的内存块的指针通常被看作一个真正的数组(也可以用 [ ] 引用)。



2.14 我总算弄清除函数指针的声明方法了, 但怎样才能初始化呢?

用下面这样的代码
extern int func();int (*fp)() = func;

当一个函数名出现在这样的表达式中时, 它就会 ``蜕变'' 成一个指针 (即, 隐式地取出了它的地址), 这有点类似数组名的行为。

通常函数的显示声明需要事先知道 (也许在一个头文件中)。因为此处并没有隐式的外部函数声明 (初始式中函数名并非一个函数调用的一部分)。


原创粉丝点击