C语⾔中,为什么字符串可以赋值给字符指针变量
⼀、
C语⾔中,为什么字符串可以赋值给字符指针变量
char *p,a='5';
p=&a;                    //显然是正确的,
p="abcd";              //但为什么也可以这样赋值??
问:⼀直理解不了为什么可以将字串常量赋值给字符指针变量,请各位指点!
答:
双引号做了3件事:
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";
return 0;
}
error C2440: '=' : cannot convert from 'char [6]' to 'char [10]'
There is no context in which this conversion is possible
看到这样的错误提⽰,你是否会想到把char a[10]改成char a[6]呢
试⼀下,
error C2106: '=' : left operand must be l-value
运算符的左边应该是⼀个“左值”。所谓“左值”就是指在程序中占⽤内存空间、可以被修改的量,⽐如各种变量。
继续扩展问题:
在使⽤指针的时候,指针可以⾃增,⽽数组不能⾃增
编译器给数组分配了空间,数组a的地址就是⼀个常量了,让常量⾃增这肯定是不⾏的。
继续扩展:
在指针⾃增的时候,编译器会⾃动识别类型,⽐如指针是指向int型的,想获取下⼀个的地址时,指针直接p++就⾏了,不要多此⼀举的p+4了
特别需要注意的是,在void指针使⽤的时候,不能使⽤指针运算,应为void型编译器不能识别类型的长度(即指针所指对象的体
积),p++这样就是不合法的,即不能进⾏数学运算,也不能使⽤*取值操作,想使⽤必须转换为其它的类型
三、
标题:对字符数组,字符指针,字符串常量
1.以字符串形式出现的,编译器都会为该字符串⾃动添加⼀个0作为结束符,如在代码中写
"abc",那么编译器帮你存储的是"abc\0"
2."abc"是常量吗?答案是有时是,有时不是。
不是常量的情况:"abc"作为字符数组初始值的时候就不是,如
char str[] = "abc";
因为定义的是⼀个字符数组,所以就相当于定义了⼀些空间来存放"abc",⽽⼜因为
字符数组就是把字符⼀个⼀个地存放的,所以编译器把这个语句解析为
char str[3] = {'a','b','c'};
⼜根据上⾯的总结1,所以char str[] = "abc";的最终结果是
char str[4] = {'a','b','c','\0'};
做⼀下扩展,如果char str[] = "abc";是在函数内部写的话,那么这⾥
的"abc\0"因为不是常量,所以应该被放在栈上。
是常量的情况:  把"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\0"被
放在常量区中,但是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*。
四、
这⼏天搞Unix上的C程序,⾥⾯⽤到了很多字符数组和字符串指针,我记得在学完C语⾔后相当⼀段时间⾥,对指针这个东西还是模模糊糊,后来⼯作也没怎么⽤到过C,虽然⽹上这类的⽂章也有很多,还是决定⾃⼰在这做个⼩总结,也算加深下⾃⼰的印象,写了下⾯的测试程序:
#include <stdio.h>
int main(int argc, char *argv[])
{
char day[15] = "abcdefghijklmn";
char* strTmp = "opqrstuvwxyz";
printf("&day is %x\n",&day);
printf("&day[0] is %x\n",&day[0]);
printf("day is %x\n",day);
printf("\n&strTmp is %x\n",&strTmp);
printf("&strTmp[0] is %x\n",&strTmp[0]);
printf("strTmp is %x\n",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 %s\n",strTmp);//将字符串常量"abcd"的地址所隐含的内容转换成“string类型”
printf("strTmp is %d\n",strTmp);//将字符串常量"abcd"的地址转换成int类型,这⾥不同的机⼦不同的时间的运⾏结果可能会不⼀样,因为地址可能会发⽣变化
printf("strTmp is %c\n",strTmp);//将字符串常量"abcd"的地址转换成字符型,这⾥不同的机⼦不同的时间的运⾏结果可能会不⼀样,因为地址可能会发⽣变化
指针变量本身有地址吗printf("*strTmp is %c\n",*strTmp);//将字符串常量"abcd"的地址所隐含的内容转换成字符型,由下⾯注释的这句会抛出异常可知,这⾥并⽆截取字符串,*strTmp长度本⾝就是1
//printf("*strTmp is %s\n",*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赋值
以上四种⽅法都能定义⼀个字符串,同时通过字符串在内存中的分布可以清楚地知道是什么情况

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。