C语言 - char *和char []的区别

1、声明不同

1.1 如何声明一个char*字符串

你可以这样:

char* str = "test";  //str是一个指针,存放在栈区,"test"是一个常量,存放在常量区,VS2017要求这句声明前面必须加上const,因为它所指向的常量字符串是不可更改的

还可以这样:

char* str = (char*)malloc(10 * sizeof(char));
strcpy(str, "qwewqe");  //对其进行赋值
printf("%s\n", str);
free(str);

还可以这样:

char* str =new char[20] { 'a' };  //直接将字符串内所有的元素都设为字符 'a'
delete str;

或者这样:

int main()
{
    int a;
    a = 10;
    char * arr = new char[a];
    cin.getline(arr, a);//最多读a个字符,如果提前遇到换行符,会立即停止
    cout << arr << endl;
    return 0;
}

1.2 如何声明一个char []字符串

你可以这样:

char cat[4] = {'T', 'O', 'M', '\0'};  //如果最后一个字符不是 '\0' ,那么cat就只是一个字符数组,而不是字符串了
delete [] cat;

还可以这样:

char cat[4] = "cat";  //注意字符数是3,而cat的大小是4

或者这样:

char cat[] = "cat";  //让编译器自动判断大小

计算字符串长度:

int main()
{
    //使用sizeof统计字符串长度
    char cat[] = "cathgdhgfd65y7u6";
    int len = sizeof(cat) / sizeof(cat[0]);
    printf("cat = %s len = %d\n", cat ,len);
   
    //使用strlen统计字符串长度
    char* str = "cathgdhgfd65y7u6";
    int len2 = strlen(str)+1;
    printf("str = %s len2 = %d\n", str, len2);
    
    return 0;
}

[]内如果要限定大小,只能用const size_type,包括字面值。

 

2、概念不同

c语言中没有特定的字符串类型,常用以下两种方式定义字符串:1)字符数组;2)指向字符串的指针。

char *str声明的是一个指针,这个指针可以指向任何字符串常量。

char str[]声明的是一个字符数组,数组的内容可以是任何内容,严格意义上说,末尾加上'\0'之后才能算是字符串。

 

3、变量不同

char *str的str是指针变量,str的值未初始化(局部变量的话,全局则自动初始化为NULL)

char str[]的str是地址常量,str的值是str[]的地址

 

4、内存的分配方式不同

内存分配可分为三种:静态存储区、栈区、堆区

  • 1、静态存储区:该内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在,它主要存放静态数据、全局数据和常量。
  • 2、栈区:它的用途是完成函数的调用。在执行函数时,函数内局部变量及函数参数的存储单元在栈上创建,函数调用结束时这些存储单元自动被释放。
  • 3、堆区:程序在运行时使用库函数为变量申请内存,在变量使用结束后再调用库函数释放内存。动态内存的生存期是由我们决定的,如果我们不释放内存,就会导致内存泄露。

char []定义的是字符串数组,该字符数组保存在全局数据区或栈区,因此数组的内容是可以改变的:

char str[6] = {"hello"}; //虽然只初始化了5个元素,但由于编译器会自动在末尾加'\0',所以size为6
str[0] = 'H'; //合法


char *定义的是字符串指针变量,该指针变量指向一个字符串,该指针的值是该字符串在内存中的地址,所以可以修改指针的值,但不能修改指针指向的值:

char *str = {"hello"};
str[0] = 'H'; //非法

把字符串 h 改成 H,出现段错误,本质原因:*str="hello"存放在常量区,是无法修改的。而数组是存放在栈中,是可以修改的。

 

5、char *作为函数返回值时

指针作为返回值时会出现:在函数返回后,指针指向的内存单元被释放了,这样就会导致指针成了野指针。

//这样会报错,因为str数组元素为局部变量,存储在栈内,函数结束后,内容失效
char* func(char* name)
{
    char str[5];
    strcpy(str,name);
    return str;
}

 

错误分析:

str为地址,返回值为char*,是进行了值传递,没有问题,但是,数组中的元素为局部变量,存储在栈中,函数外无效。

解决方法1:将数组定义为static

char* func(char *name)
{
   static char str[5];
   strcpy(str,name);
   return str;
}

解决方法2:字符串为静态常量(存储在常量区)

char* func()
{
    char *str= "hello";
    //char str[]= "hello";
    return str;
}

解决方法3:设置为动态数组

char* func(char* name)
{
    char *str= (char*)malloc(5*sizeof(char));
    strcpy(str,name);
    return str;
}

解决方法4:设置为全局变量

char str[10];
char* func(char* name)
{
    strcpy(str,name);
    return str;
}

 

小结:通过以上方法,返回字符串,只要返回字符串首地址即可。

1)调用函数时,若直接输出的话,用一个字符指针接受即可:char *result = func();

2)调用函数时,若要获取返回的字符串:char result[5]; strcpy(result, func());

 

 

补充知识:

今天看到了gets()与puts()函数,发现了一个奇怪的点:字符串可以直接赋值给字符指针变量。例如以下:

char * p="EDS";
puts(p);    //输出结果为EDS


学过指针让我清楚明白了指针变量是不能直接赋值的,而这里的字符指针却直接被赋值字符串。这让我深感疑惑了,经过查阅,才知道:

char * p="EDS"; 双引号在这里做了这三件事情:

  • 1. 申请了空间(在常量区),存放了字符串
  • 2. 在字符串尾加上了'/0'    
  • 3. 返回该字符串的首地址

先来看puts()这个函数 

函数原型

int puts(const char *string);

 

参数

输入:字符串指针

输入可以是字符串数组,也可以是字符串常量,例如:

char a[15]="1234";    //字符串数组
char * p="EDS";    //字符串常量
p=a;    //将a的首地址赋值给p,p指向了a字符串数组
puts(p);    //输出结果为1234


puts()函数的输入是一个字符串指针。当使用一个字符串数组名作为输入时,数组名此时表示一个指向数组的指针值,这符合puts()的输入要求,并能够正确输出。但是,当输入为一个字符串常量时,函数仍然能够正常的输出字符串。 
理由如下: 

如上所述,双引号的加入,返回了字符串常量的地址值,即指针,这样才能够满足puts()函数对输入参数的要求,而这个指针应该指向了字符串常量实际所在的地址。 
程序运行时,双引号分配了常量区空间,字符串常量将占用内存空间,这样才能保证puts()函数能通过指针找到要输出的数据。 既然字符串常量占用内存,那么应该就能够通过得到它的地址并输出。
另外看一下下面的这组区别,char a[10] = “hello”; 这是数组的初始化,和a[0] = ‘h’ a[1] = ‘e’…是一个道理,但是换成char a [10],然后a = “hello”就不行了 “hello”赋值的值是一个地址,而a虽然也有地址,但是这与指针是不一样的,指针的值是地址,而数组的值虽然也是地址,但是却是一个地址常量,所以不能给常量赋值。所以,可以把字符串赋值给指向字符指针变量p,而不能把字符串赋值给一个字符数组

 

posted @ 2024-05-07 14:38  [BORUTO]  阅读(13)  评论(0编辑  收藏  举报