您的位置:首页 > 编程语言 > C语言/C++

非典型性C语言教程-1.4 指针,字符串,数组

2007-07-06 11:11 351 查看
指针应该是C语言中比较难的一个概念,也是C语言之所以被称为中级语言而不是高级语言的原因。程序离不开内存,程序本身的代码也是在内存中,程序要处理的 数据也是在内存中。内存是有地址的,目前大多数计算机的内存都是以8bits也就是一个byte为单位编排地址的。指针就是一个内存地址,C语言中所有在 内存中有地址的东西都有相应的指针。

首先是指针的类型。一种类型的指针可以定义为type * p;的形式。虽然可以定义各种指向不同类型变量的指针,但是指针就是内存的一个地址,也就是一个无符号的整数。需要注意的是不同的机器上指针的大小是不一 样的。比如在16位机器上一个sizeof(p)是2个字节,32位机器上则是4个字节,而在64位机器上可能是8个字节。但是有一个一般性的规律,就是 指针的代销一般是和long类型的大小一样,也就是sizeof(*p)=sizeof(long)。由于指针本身在内存中也是一个无符号的整数,所以也 有指向指针的指针,比如int** p。但是只要记住指针是一个地址它和一个无符号整数类似。清楚了基本概念就好理解。

你会说既然指向每 种类型的指针都是一样的,那么为什么要定义那么多种类型的指针呢?区别在于不同类型的指针做加减运算时的行为是不一样的。指针可以做加减运算,比如p+ +, p=p+2等等,如果p是这么定义的type* p;那么p+n的解释成(long)p+sizeof(type)*n。也就是说指针加减的运算以指向内容的大小为基础,以保证*(p+1)指向的应该还 是一个正确的类型,而不会指向变量的一半内容。有一种特殊类型的指针就是void* p,这种指针没有指向内容的具体类型,可以指向任意的内存地址,这种指针是不能进行加减运算的,因为sizoof(void)什么也求不出来。

C语言是没有数组这种类型的。你可以定义数组char ee[20];但是没有数组类型,比如你不能定义一个函数返回数组类型。C语言的数组其实只是指针的一个简单的变化。比如
char ee[20];//定义了一个数组
ee[0]=0;
ee[2]=2;
定义数组ee的时候ee的实际类型是char* const,即是一个常量指针,不能修改的指针。引用数组元素ee[2]实际变成了*(ee+2)这样的形式。注意ee+2是合法的表达式,但是ee=ee+2就不合法了,因为ee是一个常量指针。有时候可能遇到诸如
void foo(char[] x);
这样的函数定义,这个函数定义和
void foo(char*x);
是没有区别的,关于数组大小的信息不能传递到函数里面去。所以正确的定义方式应该是
void foo(char*x, unsigned int num);
然后调用的时候传递参数
foo(ee, sizeof(ee)/sizoef(char));
这样就把数组元素的个数专递进去了。

还有一个概念是字符串,比如
char*p ="Hello world!";
但 是和数组一样,C语言同样没有字符串这种类型。字符串是一种字符 char类型的数组,但是以0结尾。上面这种写法实质是在内存的常量区域分配了一个字符数组的空间是13个元素(别忘了结尾还有一个0),然后在栈上分配 了一个指针的空间,让这个指针指向常量区域的那个字符数组。printf("hello world!/n");这句话实质上的过程是一样的,只是没有明确的定义出p,隐含的把p当作参数传递给了printf函数。结尾的那个隐含的0是非常重要的。C 语言中所有的操作字符串的标准函数比如strlen,strcpy, 还有printf的%s,都依赖于结尾隐含的0,0表示字符串的结束。如果没有找到这个0,会一直找到内存中的0位置,这一般不是我们要的结果。英文叫 Null-Terminated Strings。我曾今见过一个错误就是没有注意结尾的0造成的。

原本的意思是分配一块足够大的char数组,然后通过拷贝把3个字符串连接到一起。代码是这样写的
memcpy(buff, "hello world!", sizeof("hello world!"));
buff+=sizeof("hello world!");
memcpy(buff, "sttony!", sizeof("sttony"));
.........
这段代码有点丑陋但是也可以完成工作出问题的是 sizeof("hello world!")。sizeof("hello world!")会得出长度是13。结果在buff数组里面成了这样的内存布局:
hello world!/0sttony/0
然后后来用printf("%s", buff);怎么也打不出后面的字符串,只能打出第一个。
正确的做法应该是
strlen("hello world!");
这样就能得到长度是12。

指针也是一种变量,变量也分为全局,局部,和堆变量。指针也可以,也应该是指向一个变量的,指向的变量可能是全局,局部或堆变量。
char* p;
*p='a';
这种代码就是指针没有指向任何变量,黑话叫"野指针"。这种是很低级的错误了,比较隐晦的错误是
char* foo()
{
char a='a';
return &a;
}
.....
char*p =foo();
p指向foo局部变量a。但是函数的栈变量(局部变量)在函数结束的时候就属于未知的内存了,p也成一个野指针。还有这样的错误
char*p= (char*)malloc(250*sizeof(char));
........
free(p);
......
*p='d';
同样的,p指向的是堆上分配的堆变量空间,但是free之后,堆变量已经输入未知状态了。p也已经成了一个野指针。

下一回讲最复杂的函数指针。 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  语言 c byte 工作