首页 php教程 PHP开发 字符数组和字符指针

字符数组和字符指针

Dec 12, 2016 pm 05:16 PM
字符串数组

问题1:

字符数组名可以作为左值吗?当然不行

比如 

char str[20] = {'h','e','l','l','o',' ','w','o','r','l','d'};

str++;

不可以这么干,因为字符数组名是一个常量指针,也就是是一个const char*

#include <stdio.h>

int main()
{
    char str[20] = {&#39;h&#39;,&#39;e&#39;,&#39;l&#39;,&#39;l&#39;,&#39;o&#39;,&#39; &#39;,&#39;w&#39;,&#39;o&#39;,&#39;r&#39;,&#39;l&#39;,&#39;d&#39;};
    printf("sizeof(str): %d\n",sizeof(str));
    printf("str: %s\n",str);
    str = str + 1;  //error
    return 0;
}
登录后复制

运行结果如下:

字符串数组

当数组名为左值时,它的类型是字符数组;当数组名为右值时,它的数据类型是字符指针。

#include <stdio.h>
#include <string.h>
int main(void)
{
    char buf[10];
    char *p= “afdal”;
    buf = p;  //将一个char* 赋给一个char[10],类型不一样,必然不成功
    printf(“the buf is:%s\n”,buf);
    return 0;
}
登录后复制

问题2:

字符数组如何进行初始化?

#include <stdio.h>

int main()
{
    char ptr[20] = "hello world";  //success
    char str[20] = {&#39;h&#39;,&#39;e&#39;,&#39;l&#39;,&#39;l&#39;,&#39;o&#39;,&#39; &#39;,&#39;w&#39;,&#39;o&#39;,&#39;r&#39;,&#39;l&#39;,&#39;d&#39;};  //success
    char ctr[20];
    ctr = "hello world";  // error: incompatible types when assigning to type ‘char[20]’ from type ‘char *’
    return 0;
}
登录后复制

在给字符数组初始化的时候,会自动在字符数组的结尾加上'\0'

#include <stdio.h>

int main()
{
    char str[20] = {&#39;h&#39;,&#39;e&#39;,&#39;l&#39;,&#39;l&#39;,&#39;o&#39;,&#39; &#39;,&#39;w&#39;,&#39;o&#39;,&#39;r&#39;,&#39;l&#39;,&#39;d&#39;};
    printf("sizeof(str): %d\n",sizeof(str));
    printf("str: %s\n",str);
    int i = 0;
    while(*(str + i) != &#39;\0&#39;)  //判断是否加上&#39;\0&#39;
    {
        printf("%c\n",*( str + i++));
    }
    return 0;
}
登录后复制

运行结果如下:

字符串数组

问题3:

字符数组越界访问能编译通过吗?

字符数组越界访问编译可以通过,没有报错,这样会出现很多的问题

#include <stdio.h>

int main()
{
    char str[12] = {&#39;h&#39;,&#39;e&#39;,&#39;l&#39;,&#39;l&#39;,&#39;o&#39;,&#39; &#39;,&#39;w&#39;,&#39;o&#39;,&#39;r&#39;,&#39;l&#39;,&#39;d&#39;};
    printf("%c\n",str[100]);
    return 0;
}
登录后复制

字符串数组

打印为空

问题4:

字符数组和字符指针又有什么区别呢?

首先在内存的中位置不同,字符数组保存的字符串存放在内存的栈中,而字符指针指向的字符串保存在内存的静态存储区中。

其次字符数组保存的字符串属于字符串变量,可以被修改,而字符指针指向的字符串是属于字符串常量,不能被修改。

#include <stdio.h>

int main()
{
    char str[12] = {&#39;h&#39;,&#39;e&#39;,&#39;l&#39;,&#39;l&#39;,&#39;o&#39;,&#39; &#39;,&#39;w&#39;,&#39;o&#39;,&#39;r&#39;,&#39;l&#39;,&#39;d&#39;};
    char* ptr = "hello world";
    str[0] = &#39;f&#39;;
    ptr[0] = &#39;f&#39;;  //将字符指针指向的字符串修改,将出现段错误,因为该内存地址只读,因为该字符串属于常量
    return 0;
}
登录后复制

运行结果:

字符串数组

段错误是指访问的内存超出了系统给这个程序所设定的内存空间,例如访问了不存在的内存地址、访问了系统保护的内存地址、访问了只读的内存地址等等情况。

#include <stdio.h>

int main()
{
    char* ptr = "hello world";
    ptr[11] = &#39;!&#39;;  //往常量字符串末尾添加字符,相当于连接两个字符串,出错
    ptr[12] = &#39;\0&#39;;
    return 0;
}
登录后复制

这样也会出现段错误。

问题5:

字符指针是不是和字符数组名都是指针常量呢?

不是,字符指针,可以改变它的指向,也就是可以为左值。可以将一个字符指针指向一个字符串常量后又指向另外一个字符串常量。字符指针在为初始化之前,他是一个未定义的值,将指向任何可能的地方,所以在使用字符指针时一定要注意初始化。

#include <stdio.h>

int main()
{
    char* ptr;
    printf("ptr: %c\n",*ptr);
    return 0;
}
登录后复制

运行结果:

编译可以通过,但是ptr指向的内存地址是任意的

当然也可以将一个字符指针指向一个字符数组。

#include <stdio.h>

int main()
{
    char str[12] = {&#39;h&#39;,&#39;e&#39;,&#39;l&#39;,&#39;l&#39;,&#39;o&#39;,&#39; &#39;,&#39;w&#39;,&#39;o&#39;,&#39;r&#39;,&#39;l&#39;,&#39;d&#39;};
    char* ptr = str;
    printf("ptr: %s\n",ptr);
    return 0;
}
登录后复制

运行结果:

字符串数组

问题6:

如果一个字符指针指向一个堆中动态内存。那么我们如何初始化该内存中的值?

#include <stdio.h>
#include <stdlib.h>

int main()
{ 
    char* str = (char*)malloc(sizeof(char)*20);
    printf("str:%p\n",str);     //str在堆中内存首地址
    str = "hello world";
    printf("str:%p\n",str);    //str在静态存储区内存首地址
    char* ptr = "I love you";
    printf("ptr:%p\n",ptr);    //str在静态存储区内存首地址
    return 0;
}
登录后复制

运行结果如下:

字符串数组

很明显前后的地址不一样,前一个指向堆中的内存的地址,而后一个指向了静态存储区中的内存的地址。我本以为我通过上述方式进行初始化str的时候,我可以将堆中内存进行初始化,我发现我错了,字符指针将被重新指向。但是我想如果我们将str声明为const呢?那将会出现什么样的结果呢?

#include <stdio.h>
#include <stdlib.h>

int main()
{ 
    const char* str = (char*)malloc(sizeof(char)*20);  //我以为const将修饰str,使得str不能再作为左值而出现,我错了,const修饰的是由str指向的字符串,
    printf("str:%p\n",str);                            //该字符串不能再被修改
    str = "hello world";
    printf("str:%p\n",str);  
    return 0;
}
登录后复制

运行结果:

字符串数组

如果我们将上述的代码做如下修改,程序还能编译通过吗?

#include <stdio.h>
#include <stdlib.h>

int main()
{ 
    const char* str = (char*)malloc(sizeof(char)*20);
    printf("str:%p\n",str);
    str[0] = &#39;h&#39;;    //这种赋值才是对str原来所指向的堆中的内存的赋值,编译不过,因为str指向的堆中的内存是只读的。
    str = "hello world";     
    printf("str:%p\n",str);
    return 0;
}
登录后复制

运行结果如下:

字符串数组

上述就引发了我思考为什么const修饰的是str指向的字符串,而不是str本身呢?

原来,char* const str才是真正的修饰str本身,使得str为只读的,不能再被修改,也就是重新指向其他内存地址。而const char* str 和 char const* str 的意义是一致的,都是修饰的是*str。

#include <stdio.h>
#include <stdlib.h>

int main()
{ 
    char* const str = (char*)malloc(sizeof(char)*20);
    printf("str:%p\n",str);
    str[0] = &#39;h&#39;; 
    str = "hello world";      //变量str被重新指向,error,编译不过
    printf("str:%p\n",str);
    return 0;
}
登录后复制

运行结果如下:

字符串数组

那么我们又该如何初始化一个字符指针指向的内存呢?

其实我们可以很清楚的分析,如果str是一个字符指针,也就是一个变量,变量是可以被重新赋值的,而每一个字符串本身是有一个地址的,str = “hello world”,必然就是改变了str的值,使得str保存着"hello world"的内存首地址,而一旦你将str = "I love you",必然str将保存这"I love you"的内存首地址,这都是毋庸置疑的。

#include <stdio.h>

int main()
{
    printf("hello world:%p\n","hello world");   //将打印出"hello world"的内存地址
    printf("I love you:%p\n","I love you");    //将打印出"I love you"的内存地址
    return 0; 
}
登录后复制

运行如下:

字符串数组

下面我得回到这样一个问题?

str 和 *str的区别,很明显,str是一个指针,而*str是str指向的内存的存放的值,既然我们想改变str指向内存中的值,既*str的值,那么为何不将*str作为左值,来初始化str所指向内存的值呢?而*str 不就是 str[0]吗?所以很明显了。上述问题:那么我们又该如何初始化一个字符指针指向的内存呢?当然这个仅限于字符指针指向的是由mlloc分配的堆中的内存以及字符数组指向的栈中的内存。而字符指针如果指向字符常量,不可修改字符指针指向的内存的值,因为字符常量是只读的。

#include <stdio.h>
#include <stdlib.h>

int main()
{ 
    char* const str = (char*)malloc(sizeof(char)*20);
    printf("str:%p\n",str);
    str[0] = &#39;A&#39;;     //数组下标型赋值
    *(str + 1) = &#39;l&#39;;  //指针++型赋值
    str[2] = &#39;e&#39;,
    *(str + 3) = &#39;x&#39;;
    printf("str:%s\n",str);  
    printf("str:%p\n",str);
    return 0;
}
登录后复制

运行如下:

字符串数组

#include <stdio.h>
#include <stdlib.h>
int main()
{ 
    char str[20]; 
    printf("str:%p\n",str);
    str[0] = &#39;A&#39;; 
    *(str + 1) = &#39;l&#39;;
    str[2] = &#39;e&#39;,
    *(str + 3) = &#39;x&#39;;
    //str[4] = &#39;\0&#39;;  //当我们没有手动给字符串结尾附上&#39;\0&#39;
    printf("str:%s\n",str);
    printf("str:%p\n",str);
    return 0; 
}
登录后复制

运行如下:

字符串数组

上述的运行结果说明上述程序并没有自动给字符串结尾附上'\0',对于字符数组除非这样赋值,str[20] = "hello world",不然你就得手动给字符串附上字符串结尾'\0'。

#include <stdio.h>
#include <stdlib.h>

int main()
{ 
    char str[20]; 
    printf("str:%p\n",str);
    str[0] = &#39;A&#39;; 
    *(str + 1) = &#39;l&#39;;
    str[2] = &#39;e&#39;,
    *(str + 3) = &#39;x&#39;;
    str[4] = &#39;\0&#39;;
    printf("str:%s\n",str);
    printf("str:%p\n",str);
    return 0; 
}   
~
登录后复制

运行结果:

字符串数组

附上一段我关于memcpy()和memmove()的代码的实现。

#include <stdio.h>
#include <stdlib.h>

void mem_copy(char* const dest, const char* const src)
{
    for(int i = 0; *(src + i) != &#39;\0&#39;; i++)
        *(dest + i) = *(src + i);
}

void mem_move(char* const dest, const char* const src)
{
    int i = 0;
    while(*(src + i) != &#39;\0&#39;)
        i++;
    for(; i != -1; i--)
        *(dest + i) = *(src + i);
}

int main()
{
    char* src = "hello world";
    char* const dest1 = (char*)malloc(sizeof(char) * 20);
    char dest2[20];
    mem_copy(dest1,src);
    mem_move(dest2,src);
    printf("dest1:%s\n",dest1);
    printf("dest2:%s\n",dest2);
    return 0;
}
登录后复制

当我们需要将内存的中的某一地址段的内容拷贝到内存中另一地址段中,以上是将字符串常量区的内容拷贝到堆中和栈中,我们可以看到我分别使用了malloc和字符数组,当然我们得考虑可能在拷贝的过程中会有地址段重叠的问题,重叠该怎么拷贝,解决方案很简单,就是从尾向前拷贝,即可。

运行结果如下:

字符串数组

以上是我对c语言中字符串操作的一些理解

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
4 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
4 周前 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
4 周前 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解锁Myrise中的所有内容
1 个月前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

oracle中split()函数用法 oracle中split()函数用法 May 07, 2024 pm 01:06 PM

SPLIT() 函数通过指定的分隔符拆分字符串为数组,返回一个字符串数组,其中每个元素都是原始字符串中以分隔符分隔的部分。用法包括:将逗号分隔的值列表拆分为数组、从路径中提取文件名、将电子邮件地址拆分为用户名和域。

\0在c语言中是什么意思 \0在c语言中是什么意思 Apr 27, 2024 pm 10:54 PM

C 语言中,\0 是字符串的结束标志,称为空字符或终止符。由于字符串在内存中以字节数组形式存储,编译器通过 \0 识别字符串结束,确保正确处理字符串。\0 工作原理:编译器遇到 \0 时停止读取字符,之后的字符被忽略。\0 自身不占存储空间。好处包括可靠的字符串处理、提高效率(无需扫描整个数组查找结束)以及方便比较和操作。

java怎么对字符串排序 java怎么对字符串排序 Apr 02, 2024 am 02:18 AM

Java 中对字符串排序的方法:使用 Arrays.sort() 方法对字符串数组按升序排序。使用 Collections.sort() 方法对字符串列表按升序排序。使用 Comparator 接口对字符串进行自定义排序。

args在java中是什么意思 args在java中是什么意思 Apr 25, 2024 pm 10:15 PM

args 在 Java 中表示命令行参数,是一个字符串数组,包含程序启动时传递给它的参数列表。它仅在 main 方法中可用,其默认值为一个空数组,通过索引可以访问每个参数。args 用于接收和处理命令行参数,从而在程序启动时进行配置或提供输入数据。

java中的args是什么意思 java中的args是什么意思 May 07, 2024 am 02:24 AM

args 是 Java 中 main 方法的特殊参数数组,用于获取命令行参数或外部输入的字符串数组。通过访问 args 数组,程序可以读取这些参数,并根据需要进行处理。

PHP 函数中人工智能技术的应用 PHP 函数中人工智能技术的应用 May 01, 2024 pm 01:15 PM

AI技术已与PHP函数相结合,增强了应用程序的功能。具体的AI应用包括:使用机器学习算法对文本进行分类,如朴素贝叶斯。使用自然语言处理技术进行深入文本分析,如分词和词干提取。

在C语言环境下如何对中文字符进行排序? 在C语言环境下如何对中文字符进行排序? Feb 18, 2024 pm 02:10 PM

如何在C语言编程软件中实现中文字符排序功能?在现代社会,中文字符排序功能在很多软件中都是必不可少的功能之一。无论是在文字处理软件、搜索引擎还是数据库系统中,都需要对中文字符进行排序,以便更好地展示和处理中文文本数据。而在C语言编程中,如何实现中文字符排序功能呢?下面将简要介绍一种方法。首先,为了在C语言中实现中文字符排序功能,我们需要使用到字符串比较函数。然

C++ 函数对程序性能有哪些影响? C++ 函数对程序性能有哪些影响? Apr 12, 2024 am 09:39 AM

函数对C++程序性能的影响包括函数调用开销、局部变量和对象分配开销:函数调用开销:包括堆栈帧分配、参数传递和控制权转移,对小函数影响显着。局部变量和对象分配开销:大量局部变量或对象创建和销毁会导致堆栈溢出和性能下降。

See all articles