一,
在c语言中,为什么字符串被分配给字符指针变量?
char *p,a='5';
p=a; //显然是正确的
p='abcd '; //但是为什么也可以这样赋值呢?
问:无法理解为什么可以将字符串常量分配给字符指针变量。 请告诉我。
答案:
双引号做了三件事:
1 .申请了空间(常数区域),保存了字符串
2 .字符串末尾加上“/0”
3 .返回地址
你那里回来的地址分配给了p
二、char *p=“hello”
上面的公式为什么能做,不能把p换成数组再赋值
说明:
如果字符串“hello”显示在表达式中,则“hello”表达式中使用的值是包含字符的地址,而不是字符本身。
因此,可以将字符串指定给指向字符的指针p,而不是将字符串指定给字符数组。
char a [ 10 ]=“hello”//这样就可以了。 在这种情况下,c语言初始化支持
写char a[10]的话
还有a=“hello”,这样是错误的。
在同一个a数组中,char a[10]=“hello”这是数组的初始化,与a [0]=‘h’a [1]=‘e’…的道理相同
但改为char a [10]
而且,a="hello "不行。 " hello "代入的值是地址。 另一方面,a也有地址,但这和指针不同。 指针的值是地址,数组的值也是地址,但因为是常数,所以不能将值代入常数。
代码测试
#include stdio.h
int main () )
{
char *p='hello ';
printf('%s ',p );
char a[10];
a='hello ';
返回0;
}
errorc 2440: '=' : cannotconvertfrom ' char [6] ' to ' char [ 10 ] '
thereisnocontextinwhichthisconversionispossible
看到这样的错误提示,是否考虑将char a[10]改为char a[6]
请试一下,
errorc 2106: '=' : leftoperandmustbel-value
运算符的左侧必须是“左侧值”。 “左值”是指程序中可以占用和更改内存空间的量,如各种变量。
继续扩大问题:
使用指针时,指针可以自增加,但数组不能自增加
编译器为数组分配空间,数组a的地址是常量。 递增常数是绝对不行的。
继续扩展:
指针递增时,编译器自动识别类型。 例如,如果指针指向int类型,并且想要获取下一个地址,则指针可以保持原样,p。 请不要多加p 4
特别需要注意的是,在void指针使用的时候,不能使用指针运算,应为void型编译器不能识别类型的长度(即指针所指对象的体积),p++这样就是不合法的,即不能进行数学运算,也不能使用*取值操作,想使用必须转换为其它的类型
三、标题:对字符数组,字符指针,字符串常量
1 .如果它以字符串的形式出现,编译器会像在代码中那样自动将0作为结束符添加到该字符串中
" abc ",编译器保存的是" abc "
2.'abc”是常数吗? 答案有时是,有时不是。
不是常数的情况。 ' abc '作为字符数组初始值的时候就不是
char str[]='abc ';
由于定义了字符数组,因此定义了用于存储“abc”的空间,其原因是
字符数组是一个个地存储字符的,所以编译器把这个句子
char str[3]={'a '、' b '、' c'};
另外根据上面的总结1,char str[]='abc '; 最终结果是
char str[4]={'a '、' b '、' c '、' '};
扩展,char str[]='abc '; 如果在函数内部书写,那么这里
的"abc "因为不是常量,所以应该被放在
栈上。是常量的情况: 把"abc"赋给一个字符指针变量时,如
char* ptr = "abc";
因为定义的是一个普通字符指针,并没有定义空间来存放"abc",所以编译器得帮我们
找地方来放"abc",显然,把这里的"abc"当成常量并把它放到程序的常量区是编译器
最合适的选择。所以尽管ptr的类型不是const char*,并且ptr[0] = 'x';也能编译
通过,但是执行ptr[0] = 'x';就会发生运行时异常,因为这个语句试图去修改程序
常量区中的东西。
记得哪本书中曾经说过char* ptr = "abc";这种写法原来在c++标准中是不允许的,
但是因为这种写法在c中实在是太多了,为了兼容c,不允许也得允许。虽然允许,
但是建议的写法应该是const char* ptr = "abc";这样如果后面写ptr[0] = 'x'的
话编译器就不会让它编译通过,也就避免了上面说的运行时异常。
又扩展一下,如果char* ptr = "abc";写在函数体内,那么虽然这里的"abc "被
放在常量区中,但是ptr本身只是一个普通的指针变量,所以ptr是被放在栈上的,
只不过是它所指向的东西被放在常量区罢了。
3.数组的类型是由该数组所存放的东西的类型以及数组本身的大小决定的。
如char s1[3]和char s2[4],s1的类型就是char[3],s2的类型就是char[4],
也就是说尽管s1和s2都是字符数组,但两者的类型却是不同的。
4.字符串常量的类型可以理解为相应字符常量数组的类型,
如"abcdef"的类型就可以看成是const char[7]
5.sizeof是用来求类型的字节数的。如int a;那么无论sizeof(int)或者是sizeof(a)都
是等于4,因为sizeof(a)其实就是sizeof(type of a)
6.对于函数参数列表中的以数组类型书写的形式参数,编译器把其解释为普通
的指针类型,如对于void func(char sa[100],int ia[20],char *p)
则sa的类型为char*,ia的类型为int*,p的类型为char*
7.根据上面的总结,来实战一下:
对于char str[] = "abcdef";就有sizeof(str) == 7,因为str的类型是char[7],
也有sizeof("abcdef") == 7,因为"abcdef"的类型是const char[7]。
对于char *ptr = "abcdef";就有sizeof(ptr) == 4,因为ptr的类型是char*。
对于char str2[10] = "abcdef";就有sizeof(str2) == 10,因为str2的类型是char[10]。
对于void func(char sa[100],int ia[20],char *p);
就有sizeof(sa) == sizeof(ia) == sizeof(p) == 4,
因为sa的类型是char*, ia的类型是int*,p的类型是char*。
四、
C语言中字符数组和字符串指针分析,该贴原址:http://www.cnblogs.com/gigikouyi/archive/2006/08/01/464737.html
这几天搞Unix上的C程序,里面用到了很多字符数组和字符串指针,我记得在学完C语言后相当一段时间里,对指针这个东西还是模模糊糊,后来工作也没怎么用到过C,虽然网上这类的文章也有很多,还是决定自己在这做个小总结,也算加深下自己的印象,写了下面的测试程序:
#include <stdio.h>
int main(int argc, char *argv[])
{
char day[15] = "abcdefghijklmn";
char* strTmp = "opqrstuvwxyz";
printf("&day is %xn",&day);
printf("&day[0] is %xn",&day[0]);
printf("day is %xn",day);
printf("n&strTmp is %xn",&strTmp);
printf("&strTmp[0] is %xn",&strTmp[0]);
printf("strTmp is %xn",strTmp);
getchar();
return 0;
}
运行后屏幕上得到如下结果:
其实看到结果估计很多东西就好明白了,
先看看前三个输出也就是关于变量day的,在 char day[15] = "abcdefghijklmn"; 这个语句执行的时候,系统就分配了一段长15的内存,并把这段内存起名为day,里面的值为"abcdefghijklmn",如下图所示:
再看程序,第一个输出,&day,&号是地址运算符,也就是day这个变量的内存地址,很明显,在最前面,也就是a字符所在字节的地址;
对于第二个输出也就好理解了,&day[0],就是day数组中第一个变量(也就是a)的地址,因此他们两个是一样的;
第三个输出是day,对于数组变量,可以使用变量名来索引变量中的内容,其实这里的day可以理解成数组变量退化的指针,并且指向数组的开头,既然把它理解成指针,那么它的值肯定是地址了,所以他的值和上面两个也一样。
再看看后面三个输出,关于字符串指针strTmp,在执行char* strTmp = "opqrstuvwxyz";后,内存的图示如下:
如图所示,内存分配了两段内存,一个名为strTmp,类型是一个字符指针,另外一段是一个字符串常量,且strTmp里面存放着字符常量的首地址,注意这里无法通过strTmp修改这段字符串,因为是常量;于是程序中的后面三个输出就好理解了;
&strTmp:strTmp这个字符指针的地址
&strTmp[0]:strTmp所指字符常量第一个字符的地址
strTmp:strTmp这个字符指针的值,即字符常量的首地址
因此,最后两个的值是一样的。
指针可以这样理解,指针这种类型,和int,char,double等等是一样的,只是它用来保存地址值的,而int变量保存整数,char变量保存字符,仅此而已,就char型指针或者int指针,本质是一样的,都是存放的地址,只不过那个地址所里面的变量类型不同而已,还有一种void型指针,就是可以放任何类型变量的地址。
五、个人代码以及注释,纯属个人理解,定有不妥之处,望批评指正:
#include <stdio.h>
int main(int argc, char *argv[])
{
char* strTmp = "abcd";
printf("strTmp is %sn",strTmp);//将字符串常量"abcd"的地址所隐含的内容转换成“string类型”
printf("strTmp is %dn",strTmp);//将字符串常量"abcd"的地址转换成int类型,这里不同的机子不同的时间的运行结果可能会不一样,因为地址可能会发生变化
printf("strTmp is %cn",strTmp);//将字符串常量"abcd"的地址转换成字符型,这里不同的机子不同的时间的运行结果可能会不一样,因为地址可能会发生变化
printf("*strTmp is %cn",*strTmp);//将字符串常量"abcd"的地址所隐含的内容转换成字符型,由下面注释的这句会抛出异常可知,这里并无截取字符串,*strTmp长度本身就是1
//printf("*strTmp is %sn",*strTmp);//不能将字符转换成字符串型
getchar();
return 0;
}
六、后来又有看到下面这样的说法可供读者参考:
1. C语言中没有字符串类型,只有用字符数组来表示。这和c++中string是有区别的,C++中string是可以直接赋值如string s;s="Hello world";但是C语言中的字符数组却不能这样。所以,这里的strTmp可以理解为字符数组的首地址,也可以用它代表整个字符数组,所以能输出所有字符数组中的内容。
2.字符串就是字符数组或者是指针。 内存实现都一样的。 数组名字就是一个指针。
char ch[100] ;
char *p;
p =ch;
3.定义的字符串方式举例:
字符串定义其实很简单在c/c++语言中定义一个字符串可以使用如下的语法:
char *s1=“string1”;//定义字符串常量,指针形式
char s2[]=“string2”;//定义字符串常量,数组形式
char *s3=new char[10];//定义字符串变量并分配内存 指针形式
strcpy(s3,"string3");//为s3赋值
char s4[10];//定义字符串变量,数组形式
strcpy(s4,"string4");//为s4赋值
以上四种方法都能定义一个字符串,同时通过字符串在内存中的分布可以清楚地知道是什么情况
4. C语言中字符串赋值方法strcpy(char*d,char*s)其中s代表是源字符串,d代表目标字符串,也就是你要赋值的字符串。
5.c语言中的字符串跟java或c++中的字符串不同。如char *p;其中p是一个指针,p中存储一个内存缓冲区的首地址。所谓的内存缓冲区就是一段连续的内存地址,里面存放了一系列的字符。那系统又是如何判断在哪里结束呢。那就是根据符号‘ ’。这个字符占一个字节,8位,每位的值都是0。