[C/C++]指针解析,char * a, char ** a, char * a[], char a[][], char * a[][], char ** a[][], char * a [][][


不懂指针还敢说你在学习C?!


请先百度:“char * a, char ** a, char * a[], char a[][], char * a[][], char ** a[][], char * a [][][], and so on in memory ” (作者:德哥@Dig

这个图文并茂,解释的很详细.(就不放链接了,最近csdn老抽风,一放链接就提示:包含禁用的URL)


但看完信息量太大,先简单整理下:


1. 指针相关笔记

1> 指针中的" * "问题

如果前面有类型标识符(int. NSString...),此时" * "只是个标记,表明这是指针;

如果前面无类型标识符,此时" * " 表示取值操作符,它会把指针指向的地址中的内容 取出来或者赋值.

2> 指针的类型(int / float 等) 决定了 从(指针对应的)首地址下取几个字节的内容

3> 看字节数 用sizeof() 函数; 指针所占字节数: 32位 占4字节(byte), 64位 占8字节 (just remember it)

4> 给指针赋值,意味着给指针 重指向 (即 改变指针指向的地址)

5> 设定了函数变量为指针,则调用该函数时,需要使用地址符而非变量

否则会有错误:“Incompatible integer to pointer conversion 。。。”

e.g.   

void changeValue(int *number)

则:    

changeValue(a);  (错误:Incompatible integer to pointer conversion passing 'int' to paremeter of type 'int'… )

changeValue(&a);  (正确.)


2.  指针的输出格式及内容:

备注:以64位为例

2.1 

char* a="hello";

输出结果:

a %s : hello (输出a所指的地址的全部内容)

a %p :0x5310 (这个是指针a的内容/值,因为a指向的时地址,所以a的内容是地址0x5310)

&a %p:0xbfffed6c (指针a的地址)

*a %c : h (%c输出指针所指的地址的内容,a指的是首地址,所以内容是‘h’)

*a %d : 104 (输出整型,为何是104,还没搞懂。。2014-06-04 待续ing。。??)

*a %x : 68

2.2

char *b =&a;

*b 表示 b是一个指针, 然后char *则是告诉你b指向的是一个指针, 甭管是什么类型的指针,反正b指向的是一个指针, 一个指针占用8字节, 所以b+1就是加8个字节

那怎么样能让b+1结果是加1个字节呢?
这里要用到强制类型转换. (char *) b 就把b强制转成char *了.  所以 ((char *) b)+1 就是加1字节. *( ((char *) b)+1) 就是取这个地址的内容


3. char * a, char ** a, char * a[], char a[][], char * a[][], char ** a[][], char * a [][][],... in memory 

原文链接: http://blog by 德哥@Dig

3.1char **a : 
表示a是一个指针, 这个指针指向的地址存储的是 char * 类型的数据  指针的加减运算在这里的体现 :  a + 1 表示地址加8字节 .  
char * 也是一个指针,  用(*a)表示 指向的地址存储的是 char 类型的数据。 指针的加减运算在这里的体现 : (* a) + 1 表示地址加1字节 .  



3.2.  char *a[]
表示 a是数组, 数组中的元素是指针, 指向char类型. (数组里面所有的元素是连续的内存存放的).
需要特别注意 : 
数组名在C里面做了特殊处理 , 数组名用数组所占用内存区域的第一个字节的内存地址替代了。并且数组名a也表示指针.
如数组占用的内存区域是0x7fff5da3f550到0x7fff5da3f5a0, 那么a就被替换成0x7fff5da3f550.
所以a 并不表示a地址存储的内容, 而是a地址本身(这个从 a = &a 就能够体现出来). 这个一定要理解, 否则会无法进行下去. 
a+1 表示a的第二个元素的内存地址, 所以是加8字节.( 因为a的元素是char 指针, 所需要的空间为8字节(64位内存地址). )
*(a+1) 则表示a这个数组的第二个元素的内容 (是个char 类型的指针. 本例表示为world字符串的地址).
*(*(a+1)) 则表示a这个数组的第二个元素的内容(char指针)所指向的内容(w字符).
char * a[10] 表示限定这个数组最多可存放10个元素(char指针), 也就是说这个数组占用10*8 = 80字节.
如果存储超出数组的限额编译警告如下 : 
#include 

int main() {
  char *a[1] = {"abc","def"};
  fprintf(stdout, "a[1]:%s\n", a[1]);
  return 0;
}
结果 : 
[root@db-172-16-3-33 zzz]# gcc -O3 -Wall -Wextra -Werror -g ./b.c -o b && ./b
cc1: warnings being treated as errors
./b.c: In function ‘main’:
./b.c:4: warning: excess elements in array initializer  // 超出数组长度. 因为赋值时给了2个元素, 而限定只有1个元素.
./b.c:4: warning: (near initialization for ‘a’)



3.3 char [][]
char a[2][10] 表示一个二维数组, 存储在最底层的元素是char. 1维最多允许存储2个元素(char []), 2维最多允许存储10个元素(char).
超出将告警 :

#include 

int main() {
  char a[2][10] = {"hello", "world", "linux"};
  return 0;
}
结果 : 
[root@db-172-16-3-33 zzz]# gcc -O3 -Wall -Wextra -Werror -g ./b.c -o b && ./b
cc1: warnings being treated as errors
./b.c: In function ‘main’:
./b.c:4: warning: excess elements in array initializer  // 1维在赋值时给出了3个元素"hello" , "world" , "linux" 因此告警了, 可能导致内存溢出.
./b.c:4: warning: (near initialization for ‘a’)
./b.c:4: warning: unused variable ‘a’





【其他】
1. 当char []作为函数的参数时, 表示 char *. 当作为函数的参数传入时, 实际上是拷贝了数组的第一个元素的地址 . 
    所以 void test (char a[]) 等同于 void test ( char * a )
    char x[10] ; 然后调用 test(x) 则等同于把 x 的第一个元素的地址赋予给参数 a . 
2. char * a 和 char a[] 
相同点 : a都是指针,  指向char类型.
不同点 : char a[] 把内容存在stack . 
              char *a 则把指针存在stack,把内容存在constants. 
3. char * a[10] 和 char a[10][20]
相同点 : a 都是2级指针, *a 表示一级指针, **a 表示内存中存储的内容.
不同点 :  char * a[10], 数组由char * 类型的指针组成; 
               char a [10][20] 表示一位放10个元素, 二维放20个元素, 值存放地是一块连续的内存区域, 没有指针.

4. 小窍门 :  []和*的数量对应, 如 char a[][]的指针层数是2, 相当于char **a; char *a[]也是如此, 两层指针. 迷糊的时候数数到底有几个*几个[], 就知道什么情况下存储的是内容还是地址了? 如char a[][] 的情况里面: &a, a, *a 都是地址, **a 是内容.

你可能感兴趣的:(C/C++)