问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

C语言字符串指针变量与字符数组详解

创作时间:
作者:
@小白创作中心

C语言字符串指针变量与字符数组详解

引用
CSDN
1.
https://blog.csdn.net/hjx1235/article/details/144327575

C语言中的字符串指针变量与字符数组是两个容易混淆但又非常重要的概念。本文将通过详细的对比分析,帮助读者理解它们之间的区别和应用场景。

一. 指针数组作main函数

首先我们先补充一个知识点:

二. 字符指针变量和指针数组

字符串的定义自动包含一个指针(指针常量)char message1[81];为81个字符保留存储空间,并自动创建一个指针常量message1,其中包含message1[0]的地址。

也可以使用指针char *message2;现在,可以执行赋值语句,例如message2 = "this is a string";不能使用赋值操作符复制字符串。

下面的声明有效:

char *message = "abcdef";

但是,这不是:

char *message;
/*指针声明*/
strcpy(message,"abcdef"); /*无效拷贝*/

该策略在这里无效,因为指针的声明仅为一个值(地址)保留了足够的空间。

char message1[81] = "this is a string";
/*(message1的地址与this is a string的地址无关,message1=&message1[0])*/
char *message2 = “this is a string”;
/*(字符串名message2地址就是this is a string的地址)。*/

两者在函数调用栈释放中的应用

对比下面的两段代码:

char* GetMemory(void)
{
    char *p = "hello world";
    return p;
}
int main()
{
    char* str = NULL;
    str = GetMemory();
    printf(str);
}
char* GetMemory(void)
{
    char p[] = "hello world";
    return p;
}
int main()
{
    char* str = NULL;
    str = GetMemory();
    printf(str);
}

第一段代码运行结果:

第二段代码运行结果:

我们来观察这两个代码,其中第一个代码*p指向一个常量字符串,而常量字符串存放在常量区,函数运行完出了作用域,常量区不释放,因此能返回p

但是我们来看第二段代码,p表示数组,存在函数栈区,函数运行完出了作用域,栈区释放,返回地址也就没用了,此时返回的指针就变成了悬空指针,再通过这个指针去访问内存(如在main函数中使用printf输出)就会导致未定义行为,可能出现程序崩溃或者输出乱码等错误情况。

改写方法,可以在函数里面用malloc函数在堆区开辟一段空间,然后在主函数用free函数释放。也可以用static修饰,来把它放在静态区。

比如:

char* GetMemory(void)
{
    static char p[] = "hello world";
    return p;
}
int main()
{
    char* str = NULL;
    str = GetMemory();
    printf(str);
}

运行结果:

#include <stdio.h>
#include <stdlib.h>
char* GetMemory(void)
{
    char* p = (char*)malloc(12 * sizeof(char));  // 为字符串分配足够的内存空间,包含'\0'
    if (p == NULL) {  // 判断内存分配是否成功
        return NULL;
    }
    strcpy(p, "hello world");  // 将字符串复制到分配的内存空间中
    return p;
}
int main()
{
    char* str = NULL;
    str = GetMemory();
    if (str!= NULL) {
        printf("%s", str);
        free(str);  // 释放通过malloc申请的内存空间
        str = NULL;  // 将指针置空,避免产生野指针
    }
    return 0;
}
  • 使用malloc函数动态分配内存,这里为字符串"hello world"分配足够的内存空间,字符串长度为 11 个字符,再加上字符串结束标志'\0',总共需要 12 个char类型的字节空间,所以调用malloc(12 * sizeof(char))。同时将返回的void*类型指针强制转换为char*类型指针并赋值给p
  • 通过if (p == NULL)判断内存分配是否成功,如果malloc函数未能成功分配内存(返回NULL),则直接返回NULL,避免后续出现对无效内存的操作。
  • 使用strcpy函数将常量字符串"hello world"复制到通过malloc分配好的内存空间中,使得这块内存中存储了正确的要输出的字符串内容。
  • 在调用GetMemory函数获取字符串指针后,通过if (str!= NULL)判断返回的指针是否有效(即内存分配成功),如果有效才进行后续操作,避免对可能为NULL的指针进行解引用导致程序出错。
  • 使用printf("%s", str)按照字符串格式输出获取到的字符串内容。
  • 调用free(str)函数释放之前通过malloc申请的内存空间,避免内存泄漏。这是因为动态分配的内存需要手动释放,否则这块内存会一直被占用,直到程序结束,多次这样的情况发生可能导致内存资源耗尽等问题。
  • 最后将str指针置为NULL,这样可以避免后续不小心再次使用这个指针访问已经释放的内存(即产生野指针的情况),增强程序的健壮性。

使用字符指针变量和字符数组的比较

用字符数组和字符指针变量都能实现字符串的存储和运算,但它们二者之间是有区别的,不应混为一谈,主要有以下几点:

  • 存储单元的内容,编译时为字符数组分配若干存储单元,以存放各元素的值,而对字符指针变量,只分配一个存储单元。
char *a;
scanf(“%s”,a); 错
char *a,str[10];
a=str;
scanf (“%s”,a); 对
  • 指针变量的值是可以改变的,而数组名代表一个固定的值(数组首元素的地址),不能改变。

  • 字符数组中各元素的值是可以改变的,但字符指针变量指向的字符串常量中的内容是不可以被取代的。

char a[]=”House”,*b=” House”;
a[2]=’r’; 对
char a[]=”House”,*b=”House”;
b[2]=’r’; 错

本期内容就到这里~~~。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号