C语言字符串 字符串"ab\108g"在内存中占用多少字节

我们熟悉的ASCII码全称是美国国家信息交换标准码,它起源于20世纪50年代末,并于1967年最终定型。ASCIIS码使用7位(bit)的宽度,有26个小写字母,26个大写字母,10个数字,32个符号,33个控制码,一个空格码,共128个代码。ASCII的使用相当普及,是一种非常可靠的标准。但是,ASCII是一个真正的美国标准,它甚至满足不了其他英语国家的需求,例如,ASCII码并没有英镑符号。

我们知道,一些语言文字系统(例如中国的汉字)的字符集有非常多的符号,但一个字节最多只能表示256个符号,这是远远不够的。为了支持这些文字系统,双字节字符集(doube-byte character set, DBCS)应运而生。在双字节字符集中,一个字符由1个或2个字节组成。对程序员来说,和双字节字符集打交道就如同一场噩梦,因为程序员需要判断每个字节是否双字节的前导字节。

我们知道,C语言用char数据类型来表示一个8位ANSI字符。当在代码中声明一个字符串时,C编译器会把字符串中的字符转换成由8位char数据类型组成的数组。例如,

可以定义一个指向字符串的指针:

由于windows是一个32位的系统,指针变量p需要4个字节的存储空间。也可以定义并初始化一个指向字符串的指针:

变量p和之前一样,也只是需要4个字节的空间。字符串存储在静态内存中并使用7个字节来存储——其中6个字节存储字符串,另一个字节存储结束的'\0'。

声明Unicode字符和字符串的方法如下:

字符串前面的大写字母L通知编译器该字符串应当编译为一个Unicode字符串。当编译器将此字符串放入程序的数据段时,会使用UTF-16来编码每个字符。

为了与C语言有一些区分,Windows开发团队希望定义自己的数据类型。于是,他们定义了以下数据类型:

除此之外,Windows还定义了一系列为我们提供方便的数据类型,可以用它们来处理字符指针和字符串指针:

// 指向8位字符(串)的指针

// 指向16位的字符(串)指针

在写代码的时候,可以使用ANSI 或Unicode字符/字符串。为使其能通过编译,windows定义了以下的类型的宏:

利用这些类型和宏,无论使用ANSI还是Unicode,都可以通过编译。

// 若定义了UNICODE,则作用16位的字符,否则使用8位的字符

// 若定义了UNICODE,则作用16位的字符串,否则使用8位的字符串

如果一个Windows函数的参数列表中有字符串,则该函数通常有两个版本。例如MessageBox函数,它有两个入口点,一个名为MessageBoxA接受ANSI字符串,一个名为MessageBoxW接受Unicode字符串。

注意第二第三个参数分别指向8位和16位的字符串。

在C运行库中,strlen是一个返回ANSI字符串长度的函数,与之对应的是wcslen函数,它返回的是Unicode字符串的长度。

为方便使用,定义了以下的宏:

这样,只需要代码中使用_tcslen,即可以获得字符串的长度。

六、推荐的字符和字符串处理方式

1. 将文本字符串想象为字符的数组,而不是char或者字节的数组

2. 使用通用的数据类型(如TCHAR/PTSTR)来表示文本字符和字符串

3. 用明确的数据类型(如BYTE或PBYTE)表未字节,字节指针和数据缓冲区

4. 用TEXT或_T宏来表示字面常字符和字符串,但为了保持一致,请避免混用

7. 修改有关字符串的计算。例如,函数经常希望传给它的是缓冲区大小的字符数,而不是字节数,这时应使用_countof(szBuffer),而不是sizeof(szBuffer)。如果要为一个字符串分配内存块,那么请记住内存是以字节来分配的。这意味着需使用malloc(nCharacters *

篇二 : C语言中,为什么字符串可以赋值给字符指针变量

本文是通过几篇转帖的文章整理而成的,内容稍有修改:

C语言中,为什么字符串可以赋值给字符指针变量

p="abcd";//但为什么也可以这样赋值??

问:一直理解不了为什么可以将字串常量赋值给字符指针变量,请各位指点!

1.申请了空间(在常量区),存放了字符串

2. 在字符串尾加上了'/0'

你这里就是 返回的地址赋值给了p

上边的表达式为什么可以,而把p换成数组,然后再赋值就不行了

字符串常量"hello"出现在一个表达式中时,"hello"表达式使用的值就是这些字符所存储的地址(在常量区),而不是这些字符本身。(]

所以,可以把字符串赋值给指向字符的指针p,而不能把字符串赋值给一个字符数组。

然后a = “hello”就不行了 “hello”赋值的值是一个地址,而a虽然也有地址,但是这与指针是不一样的,指针的值是地址,而数组的值虽然也是地址,但是却是一个常量,所以不能给常量赋值。

看到这样的错误提示,你是否会想到把char a[10]改成char a[6]呢

运算符的左边应该是一个“左值”。所谓“左值”就是指在程序中占用内存空间、可以被修改的量,比如各种变量。

在使用指针的时候,指针可以自增,而数组不能自增

编译器给数组分配了空间,数组a的地址就是一个常量了,让常量自增这肯定是不行的。

在指针自增的时候,编译器会自动识别类型,比如指针是指向int型的,想获取下一个的地址时,指针直接p++就行了,不要多此一举的p+4了

特别需要注意的是,在void指针使用的时候,不能使用指针运算,应为void型编译器不能识别类型的长度(即指针所指对象的体积),p++这样就是不合法的,即不能进行数学运算,也不能使用*取值操作,想使用必须转换为其它的类型

标题:对字符数组,字符指针,字符串常量

1.以字符串形式出现的,编译器都会为该字符串自动添加一个0作为结束符,如在代码中写

2."abc"是常量吗?答案是有时是,有时不是。

不是常量的情况:"abc"作为字符数组初始值的时候就不是,如

因为定义的是一个字符数组,所以就相当于定义了一些空间来存放"abc",而又因为

字符数组就是把字符一个一个地存放的,所以编译器把这个语句解析为

做一下扩展,如果char str[] = "abc";是在函数内部写的话,那么这里

"abc\0"因为不是常量,所以应该被放在栈上。

是常量的情况:把"abc"赋给一个字符指针变量时,如

因为定义的是一个普通字符指针,并没有定义空间来存放"abc",所以编译器得帮我们

找地方来放"abc",显然,把这里的"abc"当成常量并把它放到程序的常量区是编译器

通过,但是执行ptr[0] = 'x';就会发生运行时异常,因为这个语句试图去修改程序扩展:c语言字符串指针赋值 / c语言字符指针赋值 / c语言给字符指针赋值

记得哪本书中曾经说过char* ptr = "abc";这种写法原来在c++标准中是不允许的,

但是因为这种写法在c中实在是太多了,为了兼容c,不允许也得允许。虽然允许,

话编译器就不会让它编译通过,也就避免了上面说的运行时异常。

放在常量区中,但是ptr本身只是一个普通的指针变量,所以ptr是被放在栈上的,

只不过是它所指向的东西被放在常量区罢了。

3.数组的类型是由该数组所存放的东西的类型以及数组本身的大小决定的。

也就是说尽管s1和s2都是字符数组,但两者的类型却是不同的。

4.字符串常量的类型可以理解为相应字符常量数组的类型

6.对于函数参数列表中的以数组类型书写的形式参数,编译器把其解释为普通

7.根据上面的总结,来实战一下:

C语言中字符数组和字符串指针分析,该贴原址:

这几天搞Unix上的C程序,里面用到了很多字符数组和字符串指针,我记得在学完C语言后相当一段时间里,对指针这个东西还是模模糊糊,后来工作也没怎么用到过C,虽然网上这类的文章也有很多,还是决定自己在这做个小总结,也算加深下自己的印象,写了下面的测试程序:

运行后屏幕上得到如下结果:

其实看到结果估计很多东西就好明白了,

先看看前三个输出也就是关于变量day的,在 char day[15] = "abcdefghijklmn"; 这个语句执行的时候,系统就分配了一段长15的内存,并把这段内存起名为day,里面的值为"abcdefghijklmn",如下图所示:

再看程序,第一个输出,&day,&号是地址运算符,也就是day这个变量的内存地址,很明显,在最前面,也就是a字符所在字节的地址;

对于第二个输出也就好理解了,&day[0],就是day数组中第一个变量(也就是a)的地址,因此他们两个是一样的;

第三个输出是day,对于数组变量,可以使用变量名来索引变量中的内容,其实这里的day可以理解成数组变量退化的指针,并且指向数组的开头,既然把它理解成指针,那么它的值肯定是地址了,所以他的值和上面两个也一样。

如图所示,内存分配了两段内存,一个名为strTmp,类型是一个字符指针,另外一段是一个字符串常量,且strTmp里面存放着字符常量的首地址,注意这里无法通过strTmp修改这段字符串,因为是常量;于是程序中的后面三个输出就好理解了;

strTmp:strTmp这个字符指针的值,即字符常量的首地址

因此,最后两个的值是一样的。

指针可以这样理解,指针这种类型,和int,char,double等等是一样的,只是它用来保存地址值的,而int变量保存整数,char变量保存字符,仅此而已,就char型指针或者int指针,本质是一样的,都是存放的地址,只不过那个地址所里面的变量类型不同而已,还有一种void型指针,就是可以放任何类型变量的地址。扩展:c语言字符串指针赋值 / c语言字符指针赋值 / c语言给字符指针赋值

五、个人代码以及注释,纯属个人理解,定有不妥之处,望批评指正:

printf("strTmp is %d\n",strTmp);//将字符串常量"abcd"的地址转换成int类型,这里不同的机子不同的时间的运行结果可能会不一样,因为地址可能会发生变化

printf("strTmp is %c\n",strTmp);//将字符串常量"abcd"的地址转换成字符型,这里不同的机子不同的时间的运行结果可能会不一样,因为地址可能会发生变化

printf("*strTmp is %c\n",*strTmp);//将字符串常量"abcd"的地址所隐含的内容转换成字符型,由下面注释的这句会抛出异常可知,这里并无截取字符串,*strTmp长度本身就是1

六、后来又有看到下面这样的说法可供读者参考:

1. C语言中没有字符串类型,只有用字符数组来表示。这和c++中string是有区别的,C++中string是可以直接赋值如string s;s="Hello world";但是C语言中的字符数组却不能这样。所以,这里的strTmp可以理解为字符数组的首地址,也可以用它代表整个字符数组,所以能输出所有字符数组中的内容。

2.字符串就是字符数组或者是指针。 内存实现都一样的。 数组名字就是一个指针。

3.定义的字符串方式举例:

字符串定义其实很简单在c/c++语言中定义一个字符串可以使用如下的语法:

chars4[10];//定义字符串变量,数组形式

以上四种方法都能定义一个字符串,同时通过字符串在内存中的分布可以清楚地知道是什么情况

4. C语言中字符串赋值方法strcpy(char*d,char*s)其中s代表是源字符串,d代表目标字符串,也就是你要赋值的字符串。

5.c语言中的字符串跟java或c++中的字符串不同。如char *p;其中p是一个指针,p中存储一个内存缓冲区的首地址。所谓的内存缓冲区就是一段连续的内存地址,里面存放了一系列的字符。那系统又是如何判断在哪里结束呢。那就是根据符号‘\0’。这个字符占一个字节,8位,每位的值都是0。

扩展:c语言字符串指针赋值 / c语言字符指针赋值 / c语言给字符指针赋值

swscanf()- 用于处理宽字符字符串,和sscanf功能相同 通过学习和使用个人认为,在字符串格式不是很复杂,但是也并不简单的时候用这个函数比较合适,这个尺度就要靠自己把握了,字符串不是很复杂,但自己写个处理的函数比较麻烦,效率也不高,就用这个函数,如果字符串很复杂,那就用正则表达式吧。

不多说了,看看下面这些介绍和列子吧! 名称:sscanf() - 从一个字符串中读进与指定格式相符的数据.

sscanf与scanf类似,都是用于输入的,只是后者以屏幕(stdin)为输入源,前者以固定字符串为输入源。

%[a-z] 表示匹配a到z中任意字符,贪婪性(尽可能多的匹配)

%[aB'] 匹配a、B、'中一员,贪婪性

%[^a] 匹配非a的任意字符,贪婪性 例子:

//假设email地址信息没有特定的结束标志

%[ ] 的用法:%[ ]表示要读入一个字符集合, 如果[ 后面第一个字符是”^”,则表示反意思。 [ ]内的字符串可以是1或更多字符组成。空字符集(%[])是违反规定的,可 导致不可预知的结果。%[^]也是违反规定的。

总结:%[]有很大的功能,但是并不是很常用到,主要因为: 1、许多

. (典型的就是 TC 在输入浮点型时有时会出错). 2、用法复杂, 容易出错. 3、编译器作语法分析时会很困难, 从而影响目标代码的质量和执行效率. 个人觉得第3点最致命,越复杂的功能往往执行效率越低下。而一些简单的字符串分析我们可以自已处理。

主要功能是把格式化的数据写入某个字符串中。sprintf 是个变参函数

用途:将一段数据写入以地址buffer开始的字符串缓冲区

返回值:实际写入的字符串长度

说明:此函数需要注意缓冲区buffer溢出,要为写入的argument留足长度,可以用来代替itoa,即把整数转化为字符串。

用途:sprintf的安全模式,比sprintf多一个参数size。将一段数据写入以地址str开始的字符串缓冲区。字符串长度最大不超过长度size。如果超过或等于,则只写入size-1个,后面补个'\0'。

参数:(1)str,将要写入数据的起始地址;(2)size,写入数据的最大长度(实际写入肯定小于等于此值,包括'\0');(3)format,写入数据的格式;(4)argument(省略号),要写的数据

需要注意的是,snprintf返回值是format过后字符串的长度,并不是实际拷进字符串缓冲区的长度。


我要回帖

更多关于 c语言字符串 的文章

 

随机推荐