问小白 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号