C语言字符串指针(指向字符串的指针)

本文深入解析C语言中字符串的两种表示方法:字符数组和字符串常量。探讨它们在内存中的存储位置差异,以及如何影响字符串的读取和修改操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

http://c.biancheng.net/cpp/html/80.html

C语言中没有特定的字符串类型,我们通常是将字符串放在一个字符数组中,这在《C语言字符数组和字符串》中已经进行了详细讲解,这里不妨再来演示一下:

  1. #include <stdio.h>
  2. #include <string.h>
  3.  
  4. int main(){
  5.     char str[] = "http://c.biancheng.net";
  6.     int len = strlen(str), i;
  7.     //直接输出字符串
  8.     printf("%s\n", str);
  9.     //每次输出一个字符
  10.     for(i=0; i<len; i++){
  11.         printf("%c", str[i]);
  12.     }
  13.     printf("\n");
  14.     return 0;
  15. }

运行结果:
http://c.biancheng.net
http://c.biancheng.net

字符数组归根结底还是一个数组,上节讲到的关于指针和数组的规则同样也适用于字符数组。更改上面的代码,使用指针的方式来输出字符串:

  1. #include <stdio.h>
  2. #include <string.h>
  3.  
  4. int main(){
  5.     char str[] = "http://c.biancheng.net";
  6.     char *pstr = str;
  7.     int len = strlen(str), i;
  8.  
  9.     //使用*(pstr+i)
  10.     for(i=0; i<len; i++){
  11.         printf("%c", *(pstr+i));
  12.     }
  13.     printf("\n");
  14.     //使用pstr[i]
  15.     for(i=0; i<len; i++){
  16.         printf("%c", pstr[i]);
  17.     }
  18.     printf("\n");
  19.     //使用*(str+i)
  20.     for(i=0; i<len; i++){
  21.         printf("%c", *(str+i));
  22.     }
  23.     printf("\n");
  24.  
  25.     return 0;
  26. }

运行结果:
http://c.biancheng.net
http://c.biancheng.net
http://c.biancheng.net

除了字符数组,C语言还支持另外一种表示字符串的方法,就是直接使用一个指针指向字符串,例如:

  1. char *str = "http://c.biancheng.net";

或者:

  1. char *str;
  2. str = "http://c.biancheng.net";

字符串中的所有字符在内存中是连续排列的,str 指向的是字符串的第 0 个字符;我们通常将第 0  个字符的地址称为字符串的首地址。字符串中每个字符的类型都是char,所以 str 的类型也必须是char *

下面的例子演示了如何输出这种字符串:

  1. #include <stdio.h>
  2. #include <string.h>
  3.  
  4. int main(){
  5.     char *str = "http://c.biancheng.net";
  6.     int len = strlen(str), i;
  7.    
  8.     //直接输出字符串
  9.     printf("%s\n", str);
  10.     //使用*(str+i)
  11.     for(i=0; i<len; i++){
  12.         printf("%c", *(str+i));
  13.     }
  14.     printf("\n");
  15.     //使用str[i]
  16.     for(i=0; i<len; i++){
  17.         printf("%c", str[i]);
  18.     }
  19.     printf("\n");
  20.  
  21.     return 0;
  22. }

运行结果:
http://c.biancheng.net
http://c.biancheng.net
http://c.biancheng.net

这一切看起来和字符数组是多么地相似,它们都可以使用%s输出整个字符串,都可以使用*[ ]获取单个字符,这两种表示字符串的方式是不是就没有区别了呢?

有!它们最根本的区别是在内存中的存储区域不一样,字符数组存储在全局数据区或栈区,第二种形式的字符串存储在常量区。全局数据区和栈区的字符串(也包括其他数据)有读取和写入的权限,而常量区的字符串(也包括其他数据)只有读取权限,没有写入权限。

关于全局数据区、栈区、常量区以及其他的内存分区,我们将在《C语言和内存》专题中详细讲解,相信你必将有所顿悟,从根本上理解C语言。

内存权限的不同导致的一个明显结果就是,字符数组在定义后可以读取和修改每个字符,而对于第二种形式的字符串,一旦被定义后就只能读取不能修改,任何对它的赋值都是错误的。

我们将第二种形式的字符串称为字符串常量,意思很明显,常量只能读取不能写入。请看下面的演示:

  1. #include <stdio.h>
  2. int main(){
  3.     char *str = "Hello World!";
  4.     str = "I love C!";  //正确
  5.     str[3] = 'P';  //错误
  6.  
  7.     return 0;
  8. }

这段代码能够正常编译和链接,但在运行时会出现段错误(Segment Fault)或者写入位置错误

第4行代码是正确的,可以更改指针变量本身的指向;第5行代码是错误的,不能修改字符串中的字符。

到底使用字符数组还是字符串常量

在编程过程中如果只涉及到对字符串的读取,那么字符数组和字符串常量都能够满足要求;如果有写入(修改)操作,那么只能使用字符数组,不能使用字符串常量。

获取用户输入的字符串就是一个典型的写入操作,只能使用字符数组,不能使用字符串常量,请看下面的代码:

  1. #include <stdio.h>
  2. int main(){
  3.     char str[30];
  4.     gets(str);
  5.     printf("%s\n", str);
  6.  
  7.     return 0;
  8. }

运行结果:
C C++ Java Python JavaScript
C C++ Java Python JavaScript

最后我们来总结一下,C语言有两种表示字符串的方法,一种是字符数组,另一种是字符串常量,它们在内存中的存储位置不同,使得字符数组可以读取和修改,而字符串常量只能读取不能修改。

 

<think>嗯,用户想了解C语言字符串指针指向常量还是变量,以及它们之间的区别。让我先回忆一下相关的知识点。根据引用[1]中的例子,字符指针可以指向一个字符变量,这时候指针是可以解引用并修改的。比如char* pch = &ch;,然后通过*pch = 'm'改变了ch的。这说明当指针指向变量时,字符串内容是可以修改的。 然后,引用[3]和引用[4]提到,当字符指针指向常量字符串时,比如char* str = "Hello";,这时候字符串是存储在只读内存区域的,不能通过指针修改内容。如果尝试修改,会导致未定义行为,比如程序崩溃。这是因为C/C++会把常量字符串放在单独的内存区域,多个指针指向同一个常量字符串时,它们实际指向同一块内存,这样可以节省空间。 还有,引用[4]指出,如果用相同的常量字符串初始化不同的数组,比如char str1[] = "hello";和char str2[] = "hello";,这两个数组会开辟不同的内存块,所以str1和str2的地址不同。而用指针的话,比如char* str3 = "hello";和char* str4 = "hello";,str3和str4会指向同一块内存,因为它们都是指向常量字符串。 用户可能混淆了指针指向的是常量还是变量的情况。需要区分指针本身的类型和指向的内容是否可修改。比如,char* ptr指向的如果是数组,那内容可以修改;如果是常量字符串,则不能修改。另外,指针变量本身是变量,可以指向不同的地址,但指向的内容是否可修改取决于存储的区域。 可能还需要解释为什么用指针和数组初始化会有不同的行为。比如,数组会复制字符串到自己的内存空间,而指针只是指向已有的常量字符串。因此,当修改数组内容时是允许的,但通过指针修改常量字符串则不行。 总结一下,回答需要涵盖以下几点: 1. 字符指针可以指向变量或常量字符串。 2. 指向变量时,可修改内容;指向常量字符串时不可修改。 3. 指针变量本身是变量,可以改变指向。 4. 常量字符串在内存中的存储特性,多个指针可能指向同一地址。 5. 数组初始化字符串指针的不同行为。 可能还需要给出示例代码,说明不同的情况,比如修改指针指向变量和常量时的不同结果,以及数组的情况。同时,注意引用中的例子,比如引用[4]中的str1、str2与str3、str4的区别。 用户的问题可能还涉及如何安全地使用字符串指针,避免未定义行为。因此,在回答中可以建议使用const关键字来声明指向常量的指针,以防止意外修改,比如const char* ptr = "Hello";,这样编译器会阻止修改操作。 最后,生成相关问题时要围绕字符串指针、常量、变量的区别,比如如何安全使用、内存管理、常见错误等。</think>### C语言字符串指针指向常量或变量的区别 在C语言中,字符串指针可以指向**常量字符串**或**变量字符串**,其行为和内存管理方式有显著差异。以下是关键区别: --- #### 1. **指向常量字符串指针** - **定义方式**:`char *ptr = "Hello";` - **特点**: - 字符串`"Hello"`存储在**只读内存区域**(常量区),内容不可修改。 - 多个指针指向同一常量字符串时,实际指向同一内存地址以节省空间[^4]。 - 尝试通过指针修改内容会导致**未定义行为**(如程序崩溃)[^3]。 - **示例**: ```c char *str1 = "Hello"; char *str2 = "Hello"; // str1和str2指向同一地址 printf("%p %p\n", str1, str2); // 输出相同地址 // *str1 = 'h'; // 错误:尝试修改常量字符串 ``` --- #### 2. **指向变量字符串指针** - **定义方式**:通过字符数组初始化,如 `char arr[] = "Hello";`,再用指针指向数组首地址。 - **特点**: - 字符串存储在**栈或堆内存**中,内容可修改。 - 每个字符数组会独立开辟内存空间,即使内容相同,地址也不同[^4]。 - **示例**: ```c char arr1[] = "Hello"; char arr2[] = "Hello"; char *ptr1 = arr1; char *ptr2 = arr2; printf("%p %p\n", ptr1, ptr2); // 输出不同地址 *ptr1 = 'h'; // 合法:修改变量字符串 ``` --- #### 3. **指针变量本身的特性** - 指针变量是**可变的**,可以重新指向其他地址: ```c char *ptr = "Hello"; ptr = "World"; // 合法:指针指向新的常量字符串 ``` - 若需明确指针指向常量,可用`const`修饰: ```c const char *ptr = "Hello"; // 防止误修改 ``` --- #### 4. **关键区别总结** | 特性 | 指向常量字符串 | 指向变量字符串 | |---------------------|------------------------------|-------------------------------| | **存储区域** | 只读内存区 | 栈或堆内存 | | **内容是否可修改** | 不可修改 | 可修改 | | **相同字符串的地址**| 多个指针指向同一地址 | 不同数组指向不同地址 | | **语法示例** | `char *ptr = "Hello";` | `char arr[] = "Hello";` | --- #### 5. **常见错误** - **错误修改常量字符串**: ```c char *ptr = "Hello"; *ptr = 'h'; // 运行时错误(如Segmentation Fault) ``` - **错误初始化指针**: ```c char *ptr; strcpy(ptr, "Hello"); // 错误:ptr未分配内存 ``` --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值