【 C 】字符串常量
当一个字符串常量出现在表达式中时,它的值是个指针常量。编译器把这些指定字符的一份拷贝存储在内存的某个位置,并存储一个指向第一个字符的指针。但是,当数组名用于表达式中时,它们的值也是个指针常量。我们可以对它们进行下标引用、间接访问以及指针运算。
这些操作对于字符串常量是不是也有意义呢?
看看下面这个表达式是什么意思?
"xyz" + 1
看上去像是一个垃圾!它好像是试图在一个字符串上面执行某种类型的加法运算。
但是,当你记得字符串常量实际上是一个指针常量时,它的意义就变得清楚了。这个表达式计算“指针值 + 1”的值。它的结果是个指针,指向字符串的第二个字符:y。
那么这个表达式又是什么呢?
*"xyz"
理解了第一个,后面的都好说:对一个指针执行间接访问时,其结果就是该指针指向的值。字符串常量的类型是指向字符的指针,所以这个间接访问得到的结果是字符‘x’。
我们继续放出大招:
"xyz"[2]
很简单,对一个指针进行下标访问是合理的,就像数组名也是一个指针常量,对其下标访问就是对数组中的元素进行访问,这个同理,表达式的值为一个字符‘z’。
下面给出一个错误的例子:
*( "xyz" + 4 )
这个表达式的结果是什么呢?
事实上,这是一个错误,它的偏移量4超过了字符串的访问,就像你访问一个数组的元素,超出了索引范围一样,这样有可能会出大事!这个表达式的结果是一个不可预测的值。
什么时候会用到类似这些形式的表达式呢?
《C与指针》给出了一个神秘函数的例子:
#include <stdio.h>
void mystery( int n )
{
n += 5;
n /= 10;
printf("%s\n", "**********" + 10 - n );
}
最后一个标准输出语句使用了字符串常量,下面我们测试下这个函数执行的情况:
#include <stdio.h>
#define M 6
void mystery( int n )
{
n += 5;
n /= 10;
printf("%s\n", "**********" + 10 - n );
}
int main()
{
mystery( M );
return 0;
}
我们通过改变M的值,来运行这个程序:
大家可在这个网站上实验:https://www.tutorialspoint.com/compile_c_online.php
当输入M = 10 时候:
输入M = 100时:
各位自行总结规律!
各位大侠如果觉得这个例子垃圾,那我们就再看一个例子:
这个例子在递归函数中也见过,非常好玩!
贴出来代码:
//接受一个整型值(无符号),把它转换为字符并打印它。
#include <stdio.h>
void binary_to_ascii(unsigned int value)
{
unsigned int quotient;
quotient = value / 10;
if(quotient != 0)
binary_to_ascii(quotient);
putchar(value % 10 + '0');
}
这个例子,如果你不太了解递归函数,恐怕会感到无解!
但它确实能实现把一个整型值转换为字符打印的操作。
测试下呗:
//接受一个整型值(无符号),把它转换为字符并打印它。
#include <stdio.h>
void binary_to_ascii(unsigned int value)
{
unsigned int quotient;
quotient = value / 10;
if(quotient != 0)
binary_to_ascii(quotient);
putchar(value % 10 + '0');
}
int main()
{
binary_to_ascii(16);
return 0;
}
下面我们对这个例子进行修改,以十六进制的形式打印结果值:
//接受一个整型值(无符号),把它转换为字符并打印它。
#include <stdio.h>
void binary_to_ascii(unsigned int value)
{
unsigned int quotient;
quotient = value / 16;
if(quotient != 0)
binary_to_ascii(quotient);
putchar( "0123456789ABCDEF"[value % 16] );
}
int main()
{
binary_to_ascii(26);
return 0;
}
这就很完美了,成功的运用了字符串常量是一个指针常量的意义来设计程序!
当然,如果觉得字符串常量难以理解的话,可以有一个简单的替代方案,但是代码没有字符串常量简洁:
//接受一个整型值(无符号),把它转换为字符并打印它。
#include <stdio.h>
void binary_to_ascii(unsigned int value)
{
unsigned int quotient, remainder;
quotient = value / 16;
if(quotient != 0)
binary_to_ascii(quotient);
remainder = value % 16;
if( remainder < 10 )
putchar( remainder + '0' );
else
putchar( remainder - 10 + 'A' );
}
int main()
{
binary_to_ascii(26);
return 0;
}
【 C 】字符串常量的更多相关文章
- 使用Microsoft Roslyn提取C#和VB.NET源代码中的字符串常量
Microsoft Roslyn是微软.NET“编译器即服务(Compiler as a Service)”的主要产品,它提供了开放的编译器API,并为源代码产生.分析和重构提供了新一代的语言对象模型 ...
- Java字符串常量池
JVM为了减少字符串对象的重复创建,维护了一个特殊的内存,这段内存被称为字符串常量池. Java中字符串对象的创建有两种形式:一种是字面量形式,String str = "a":一 ...
- 字符数组,字符指针,字符串常量,以及sizeof的一些总结
1.以字符串形式出现的,编译器都会为该字符串自动添加一个\0作为结尾 如在代码中写"abc",编译器帮你存储的是"abc\0". 2.数组的类型是由该数组所存放 ...
- Java中的字符串常量池
ava中字符串对象创建有两种形式,一种为字面量形式,如String str = "droid";,另一种就是使用new这种标准的构造对象的方法,如String str = new ...
- C++字符串常量
C++字符串常量 当一个字符串常量出现于表达式中时,它的值是个指针常量.编译器把这个指定字符的一份copy存储在内存的某个位置(全局区),并存储一个指向第一个字符的指针. #include <i ...
- PostgreSQL中美元符号引用的字符串常量
虽然用于指定字符串常量的标准语法通常都很方便,但是当字符串中包含了很多单引号或反斜线时很难理解它,因为每一个都需要被双写.要在这种情形下允许可读性更好的查询,PostgreSQL提供了另一种被称为“美 ...
- Python学习总结4:字符串常量与操作汇总
参考博客:http://www.cnblogs.com/Camilo/archive/2013/09/21/3332267.html http://www.cnblogs.com/SunWentao/ ...
- C++常量(C++数值常量、字符串常量、符号常量)
http://see.xidian.edu.cn/cpp/biancheng/view/104.html 字符串常量 用双撇号括起来的部分就是字符串常量,如"abc"," ...
- 字符串常量演示Demo
public class StringDemo { public static void main(String[] args) { // TODO Auto-generated method stu ...
- C语言中字符串常量到底存在哪了?
常量存储总结局部变量.静态局部变量.全局变量.全局静态变量.字符串常量以及动态申请的内存区 1.局部变量存储在栈中2.全局变量.静态变量(全局和局部静态变量)存储在静态存储区3.new申请的内存是在堆 ...
随机推荐
- Retrieving failed records after an SqlBulkCopy exception
Let me start by saying that the idea I used in this article is not originally mine, but since I have ...
- 深入浅出SharePoint——Caml快速开发
适用于Visual Studio 2010的Caml智能感知工具 http://visualstudiogallery.msdn.microsoft.com/15055544-fda0-42db-a6 ...
- 高可用web框架
nginx nginx简介 Nginx是一个自由.开源.高性能及轻量级的HTTP服务器及反转代理服务器.Nginx以其高性能.稳定.功能丰富.配置简单及占用系统资源少而著称. Nginx 超越 Apa ...
- metasploit 渗透测试笔记(meterpreter篇)
0x01 背景 meterpreter作为后渗透模块有多种类型,并且命令由核心命令和扩展库命令组成,极大的丰富了攻击方式. 需要说明的是meterpreter在漏洞利用成功后会发送第二阶段的代码和me ...
- iOS NSRunloop的简单理解
最近学习了下NSRunloop. 作一下简单的理解: 1.runloop与线程的关系,每一个线程创建是都会有伴有一个runloop诞生,runloop用来接收事件源,让线程执行事件.当没有事件处理时, ...
- C++派生类成员访问作用域,同名重载
#include <iostream> using namespace std; class CFatherSum //父类Sum { public: int m_iVar; //公用数据 ...
- 简单理解Socket 重要
http://www.cnblogs.com/dolphinX/p/3460545.html 题外话 前几天和朋友聊天,朋友问我怎么最近不写博客了,一个是因为最近在忙着公司使用的一些控件的开发,浏览器 ...
- BZOJ1016:[JSOI2008]最小生成树计数(最小生成树,DFS)
Description 现在给出了一个简单无向加权图.你不满足于求出这个图的最小生成树,而希望知道这个图中有多少个不同的最小生成树.(如果两颗最小生成树中至少有一条边不同,则这两个最小生成树就是不同的 ...
- Spring(十二)之JDBC框架
JDBC 框架概述 在使用普通的 JDBC 数据库时,就会很麻烦的写不必要的代码来处理异常,打开和关闭数据库连接等.但 Spring JDBC 框架负责所有的低层细节,从开始打开连接,准备和执行 SQ ...
- JNI由浅入深_3_Hello World
1.需要准备的工具,eclipse,cdt(c++)插件,cygwin(unix)和 android ndk. 在cygwin的etc目录下将ndk的路径引入到profile文件中,可以在cygwin ...