栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

Linux C/C++学习4:关于字符串常量的几个基础问题

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Linux C/C++学习4:关于字符串常量的几个基础问题

Linux C/C++学习4:关于字符串常量的几个基础问题
    • 1. 相同字符串常量的地址是否相同?
    • 2. 指针形式的字符串常量(char *)可以更改吗?
    • 3. 数组形式的字符串常量(char [])可以更改吗?
    • 4. 动态申请内存的字符串(malloc)可以更改吗?
    • 5. 参考文献


1. 相同字符串常量的地址是否相同?
  • 源码
// File: strdemo1.c
#include 
char *a = "hello world";
char c[] = "hello world";
int main(int argc, char *argv[])
{
	char *b = "hello world";
    printf("ap=%p, bp=%p, a%sbn", a, b, ((a==b)? "==": "!="));
    char d[] = "hello world";
    printf("cp=%p, dp=%p, c%sdn", c, d, ((c==d)? "==": "!="));
	return 0;
}
  • 执行
root@ubuntu:/opt/constval# gcc -Wall -g strdemo1.c -o strdemo1
root@ubuntu:/opt/constval# ./strdemo1 
ap=0x55995a62d004, bp=0x55995a62d004, a==b
cp=0x55995a62f010, dp=0x7fffdebdfa8c, c!=d
  • 结论
    (1) 指针形式的字符串常量(*a 和 *b):地址相同,指向同一段存储空间,即仅存储一份相同的字符串。
    (2) 数组形式的字符串常量(c[] 和 d[]):地址不同,指向不同的存储空间,即存储了两份相同的字符串。

2. 指针形式的字符串常量(char *)可以更改吗?
  • 源码
// File: strdemo2.c
#include 
char *a = "hello world";	// 已初始化
char *b;					// 未初始化
int main(int argc, char *argv[])
{
	*a = "get out";   		// compile [-Wint-conversion] and execute Segmentation fault
	// *(a+3) = '-';     	// compile normal and execute Segmentation fault
	// *a = 123;         	// compile normal and execute Segmentation fault
	// *a = 't';         	// compile normal and execute Segmentation fault
	
	// *b = "get out";   	// compile [-Wint-conversion] and execute Segmentation fault
	// *(b+3) = '-';     	// compile normal and execute Segmentation fault
	// *b = 123;         	// compile normal and execute Segmentation fault
	// *b = 't';         	// compile normal and execute Segmentation fault

	// printf("++ap=%p, ", ++a);	// normal
	// printf("++ac=%sn", a);		// normal
	// printf("++bp=%p, ", ++b);	// normal (++bp=0x1, because *b is uninitialized)
	// printf("++bc=%sn", b);		// compile normal and execute Segmentation fault
	
	return 0;
}
  • 执行
    执行结果参见源码中的注释,读者可以自行验证每一行。例如"*a = “get out”; //compile [-Wint-conversion] and execute Segmentation fault",即编译时报 [-Wint-conversion] 警告,执行时报Segmentation fault,如下所示。
root@ubuntu:/opt/constval# gcc -Wall -g strdemo2.c -o strdemo2
strdemo2.c: In function ‘main’:
strdemo2.c:6:5: warning: assignment to ‘char’ from ‘char *’ makes integer from pointer without a cast [-Wint-conversion]
    6 |  *a = "get out";   // compile [-Wint-conversion] and execute Segmentation fault
      |     ^
root@ubuntu:/opt/constval# ./strdemo2
Segmentation fault (core dumped)
  • 结论
    (1) 无论 char * 是否初始化,在编译时,输入int型、char型无警告,输入字符串型报[-Wint-conversion]警告;在执行时,均会报Segmentation fault错误。
    (2) 指针形式的字符串常量存放在不可以更改的静态内存存储区域,更改其指向的任何数据都是不允许的。
    (3) 指针本身是一个变量,单独预留一个存储位置,用于存储字符串常量的地址(指向首字符地址),可进行++a等类似的操作。

3. 数组形式的字符串常量(char [])可以更改吗?
  • 源码
// File: strdemo3.c
#include 
char c[12] = "hello world";
int main(int argc, char *argv[])
{
    printf("cp=%p, cv=%sn", c, c);

	c[5] = '-';							// normal
    printf("cp=%p, cv=%sn", c, c);
    *(c+5) = '&';						// normal
    printf("cp=%p, cv=%sn", c, c);
    
    *c = "get out";						// compile [-Wint-conversion] and execute normal
    printf(""get out" pointer is %pn", "get out");
    printf("cp=%p, cv=%sn", c, c);

	// *(++c) = '#';					// compile error: lvalue required as increment operand
	
	return 0;
}
  • 执行
root@ubuntu:/opt/constval# gcc -Wall -g strdemo3.c -o strdemo3
strdemo3.c: In function ‘main’:
strdemo3.c:16:8: warning: assignment to ‘char’ from ‘char *’ makes integer from pointer without a cast [-Wint-conversion]
   16 |     *c = "get out";
      |        ^
root@ubuntu:/opt/constval# ./strdemo3
cp=0x557291653010, cv=hello world
cp=0x557291653010, cv=hello-world
cp=0x557291653010, cv=hello*world
"get out" pointer is 0x557291651012
cp=0x557291653010, cv=ello&world
  • 结论
    (1) 用字符串常量初始化的数组(char [])可以更改,因为它不是存放在不可更改的内存区域。
    (2) 对于 *c = “get out” 进一步说明:*c 实际上指向的是c[12]的第一个字符,将 “get out” 赋值给 *c时,强制将其地址0x557291651012截取后两位,即char型0x12,赋值给c[12]的第一个字符。因为0x12在ASCII码表中对应的是控制字符,即非打印字符,所以其输出为ello&world。
    (3) 编译器会把数组名c看作是数组首元素的地址&c[0]的同义词,即c是个地址常量。可以用c+1来标识下一个元素,但不能使用++c;c[12]在计算机内存中被分配一个有12个元素的数组(其中每个元素对应一个字符,还有一个附加的元素对应结束的空字符’’),每个元素都被初始化为相应的字符;通常,被引用的字符串存储在可执行文件的数据段部分,当程序被加载到内存中时,字符串也被加载到内存中,把被引用的字符串复制到数组中。

4. 动态申请内存的字符串(malloc)可以更改吗?
  • 源码
// File: strdemo4.c
#include 
#include 
int main(int argc, char *argv[])
{
    char *a = "hello world";
    char *b = NULL; 
    if ((b = (char *)malloc(sizeof(char) * 12)) == NULL)
    {
        perror("malloc fail!");
        return -1;
    }
    while(*a != '') *b++=*a++;
    *b = '';
    b -= 11;

    printf("bp=%p, bc=%sn", b, b);
    *(b+5) = '-';
    printf("bp=%p, bc=%sn", b, b);

    free(b);
    return 0;
}
  • 执行
root@ubuntu:/opt/constval# gcc -Wall -g strdemo4.c -o strdemo4
root@ubuntu:/opt/constval# ./strdemo4
bp=0x559b61db72a0, bc=hello world
bp=0x559b61db72a0, bc=hello-world
  • 结论
    (1) 用动态申请的方法给一个字符串赋值,那么该字符串在程序运行过程中的值依然可以修改。

5. 参考文献
  1. 《C语言字符串定义》
  2. 《gcc_warning:assignment makes integer from pointer without a cast》
  3. 《ASCII码字符对照表》
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/613379.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号