关于字符串与指针

  1. C/C++程序占用的内存分类:
  2. 申请方式
  3. 获取方式
  4. char ** 与char * a[ ]

过去有人曾对我说,“一个人爱上小溪,是因为没有见过大海。”而如今我终于可以说,“我已见过银河,但我仍只爱你一颗星。”

C语言程序中声明字符串有两种方式

1
2
3
char *s = "string";

char s[] = "string";

这两种方式看起来都是声明了一个内容为string的字符串,其实从内存的角度来看是有区别的。

当你运行

1
*s = 'a';

时,第一个语句的程序就死掉了,第二个语句的程序却可以正确运行。

C/C++程序占用的内存分类:

1、栈区(stack)—由编译器自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。

2、堆区(heap)—一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。注意它与数据结构中的堆是两回事,分配方式类似于链表。

3、全局区(静态区)(static)—全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后由系统释放。

4、文字常量区—常量字符串就是放在这里的。程序结束后由系统释放。

5、程序代码区

解释一下:

我们在程序中所声明的全局变量和静态变量(static修饰)的就是存放在全局区。

动态分配的变量则存放在堆区。

字符串常量储存在文字常量区。

而一些普通的变量比如函数参数,指针之类的也就存在于栈区。

申请方式

栈(stack):
由系统自动分配。例如,声明在函数中一个局部变量int b;系统自动在栈中为b开辟空间

堆(heap):
需要程序员自己申请,并指明大小,在c中malloc函数

如p1=(char)malloc(10);
在C++中用new运算符
如p2=(char
)malloc(10);
但是注意p1、p2本身是在栈中的

获取方式

char s1[]=”aaaaaaaaaaaaaaa”;

char *s2=”bbbbbbbbbbbbbbbbb”;

aaaaaaaaaaa是在运行时刻赋值的;

而bbbbbbbbbbb是在编译时就确定的;

char *c1 = “abc”;实际上先是在文字常量区分配了一块内存放”abc”,然后在栈上分配一地址给c1并指向
这块地址,然后改变常量”abc”自然会崩溃

然而char c2[] = “abc”,实际上abc分配内存的地方和上者并不一样,可以从

4199056

2293624 看出,完全是两块地方,推断4199056处于常量区,而2293624处于栈区

2293628

2293624

2293620 这段输出看出三个指针分配的区域为栈区,而且是从高地址到低地址

2293620 4199056 abc 看出编译器将c3优化指向常量区的”abc”

char ** 与char * a[ ]

由于[ ]的优先级高于* 所以a先和 [ ]结合,它还是一个数组,数组中的元素才是char * ,前面讲到char * 是一个变量,保存的是字符串的地址。

那么看一下这个语句

1
char *arr[] = {"aaaaa","bbbbb","ccccc"};

如果你输出sizeof(arr)的话答案并不是6 * 3 = 18,而是3 * 4 = 12;

因为数组arr中的元素是char *指针,指针占四个字节。

如果我在写一个

1
char **s  = arr;

运行会发现是正确的,因为arr也就是&arr[0]。s则是指向char *的指针。

1
2
3
printf("%s",*s);  
printf("%s",arr[0]);
printf("%s",*arr);

由此上面三条语句的输出结果是一样的。

还有一个问题

1
2
char **s;
*s = "hallo";

这个语句也会导致程序崩溃。

因为s是一个无效的指针,*s的操作是UB,所以在执行上述语句需要这么做

1
2
3
char **s;
s = (char **) malloc(sizeof(char**));
*s = "Hallo";
script>