zoukankan      html  css  js  c++  java
  • c/c++字符串定义及使用的对比

    gcc支持的一种的字符串的表示形式 "xxx" "xxx" "xxx" 他会将这3个字符串连成一个并
    且只会在最后的一个字符串末尾添加 '‘,而且还会忽略各个字符串之间的空格符号。

    当我在由GCC编译的Linux x86_64计算机上编译并运行以下C程序时:

    include <stdio.h>

    int main(void)
    {
    char *p1 = "hello"; // Pointers to strings
    char *p2 = "hello"; // Pointers to strings
    if (p1 == p2) { // They are equal
    printf("equal %p %p ", p1, p2); // equal 0x40064c 0x40064c
    // This is always the output on my machine
    }
    else {
    printf("NotEqual %p %p ", p1, p2);
    }
    }

    我总是得到的输出为:

    等于0x40064c 0x40064c
    

    我知道字符串存储在常量表中,但是与动态分配的内存相比,地址太低了。

    与以下程序比较:

    include <stdio.h>

    int main(void)
    {
    char p1[] = "hello"; // char arrar
    char p2[] = "hello"; // char array
    if (p1 == p2) {
    printf("equal %p %p ", p1, p2);
    }
    else { // Never equal
    printf("NotEqual %p %p ", p1, p2); // NotEqual 0x7fff4b25f720 0x7fff4b25f710
    // Different pointers every time
    // Pointer values too large
    }
    }

    两个指针不相等,因为这是两个可以独立操作的数组。

    我想知道GCC如何为这两个程序生成代码,以及它们在执行过程中如何映射到内存。由于已经将其记录在文档中,因此很多时候都欢迎使用任何指向文档的链接。

    在C中定义字符串有下列几种形式:字符串常量,char数组,char指针

    1.字符串常量

    即:位于一对双括号中的任何字符。双引号里的字符加上编译器自动提供的结束标志字符,作为

    一个字符串存储在内存中。如:printf("%s","hello"); //"hello"

    如果字符串文字中间没有间隔或间隔的是空格符,ANSI  C 会将其串联起来。例:
    
     char greeting[50] = "hello,and" "how are" "you";
    

    等价于:

     char greeting[50] = "hello,and how are you";
    

    字符串常量属于静态存储类。静态存储是指如果在一个函数中使用字符串常量,即使是多次调用了这个函数,

    该字符串在程序的整个运行过程中只存储一份。整个引号的内容作为指向该字符串存储位置的指针。这一点与

    把数组名作为指向数组存储位置的指针类似。

    2.字符串数组及其初始化

    初始化例子:

      char m[40] = "hello,world";  //定义字符串数组时必须指定数组大小(整型常量),在指定大小时,要确保数组的大小比预定的大一个,因为编译器会自动添加''。
    
                                             //多余的元素会初始化为''
    
    
    
      char m={'h','e','l',''};  //注意标志结束的空字符,若没有它,得到的只是一个字符数组而不是字符串
    

    3.利用char指针定义字符串

       char *m = "hello,world"; //自动添加''
    
      注意:此时字符串指针m指向字符串常量,不成用*(m+1)='o'修改此常量,因为这个字符串常量放在常量区不能被修改
    

    4.数组和指针

    数组形式和指针形式有什么不同呢?

       数组形式: char m[40] = "hello,world";   m是个指针常量
    
       指针形式: char *m = "hello,world";  m是个指针变量
    

    数组形式:

         编译器会把数组名m看作是数组首元素的地址&m[0]的同义词,m是个地址常量。可以用m+1来标识数组里的下一个元素,但不能使用++m,增量运算符只能在变量前使用, 而不能在常量前使用。
    
         m[40]在计算机内存中被分配一个有40个元素的数组(其中每个元素对应一个字符,还有一个附加的元素对应结束的空字符'')。每个元素都被初始化为相应的字符。  
    
             通常,被引用的字符串存储在可执行文件的数据段部分;当程序被加载到内存中时,字符串也被加载到内存中,把被引用的字符串复制到数组中
    指针形式:
    
         指针形式(*m)也会在静态存储区为字符串预留空间。此外,一旦程序开始执行,还要为指针变量m另外预留一个存储位置,以在该指针变量中能够存储字符串的地址。
          m指向字符串的第一个字符,可用++m指向第二个字符。  指针m是个变量。    
    

    c/c++中使用字符串的频率还是比较高的,下面就字符串的不同定义及其使用方法做一些对比

    字符串一般有以下三种定义方法:

    1、char *p="hello";

    2、char str[6]="hello";

    3、string s="hello";

    【第一种字符串】:这种定义方式会被编译器默认为字符串常量,自行默认为是不会被改变的,所以编译时会被存储在一个只读的数据段中,尝试对这种类型字符串的改变是不被允许的。

    如:

    char *p="hello";
    p[1]='x';

    这个时候,输出字符串就会爆出"段错误"(我这里的实验平台是linux,会和windows有所不同),因为修改了内存只读区域,这是不允许的;

    【第二种和第三种字符串】:这种定义方式实际上是把存在只读数据段中的字符串复制到了一个字符数组中,这种字符串中的任意字符都可以被随便改变,这里不再做出演示。

    *注意一下情况:

    char *str1="hello";
    char *str2="hello";

    这个时候,str1和str2指向的其实是同一个内存地址,可以用一下语句进行验证:

    if(str1==str2)
    cout<<"str1=str2"<<endl;

    *linux下定义字符串爆出warning的处理方法:在定义字符串时加上const限定修饰符,告诉编译器这是常量,否则g++/gcc都会认为是变量,所以会爆出warning

    在gcc命令行中,我想定义一个字符串,例如-Dname = Mary,然后在源代码中我想要printf(“%s”,name);打印玛丽。
    我该怎么办呢?
    两个选项。首先,逃避引号,使壳不会吃它们:

    gcc -Dname="Mary"

    或者,如果你真的想要-Dname = Mary,你可以把它串起来,虽然它有点怪。

    include <stdio.h>

    define STRINGIZE(x) #x

    define STRINGIZE_VALUE_OF(x) STRINGIZE(x)

    int main(int argc, char *argv[])
    {
    printf("%s", STRINGIZE_VALUE_OF(name));
    }

    请注意,STRINGIZE_VALUE_OF会很乐意评估宏的最终定义。

    Sample code:

    main()
    {
    printf("%d ", MARCO);
    // printf("%s ", MARCO);
    }

    When I try to use gcc -D option, I found the following command works:

    gcc -D MARCO=12345 test.c

    but when I change 12345 to a string:

    gcc -D MARCO=abcde test.c

    an error occurs:

    error: ‘abcde’ undeclared (first use in this function)

    I have tried -DMARCO=abcde, -DMARCO="abcde", -D MARCO="abcde"; all failed with that error.

    Does this -D option only support integers?

  • 相关阅读:
    三元表达式、列表推导式、生成器表达式、递归、匿名函数
    nonlocal关键字、装饰器
    函数嵌套、作用域、闭包
    实参和形参
    函数基础
    文件操作
    字符编码
    推荐一个纯JavaScript编写的图表库——Highcharts
    推荐web 前端代码的编辑分享平台——RunJS
    了解腾讯
  • 原文地址:https://www.cnblogs.com/marklove/p/14271550.html
Copyright © 2011-2022 走看看