字符数组和字符指针
问题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] = {'h','e','l','l','o',' ','w','o','r','l','d'}; 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] = {'h','e','l','l','o',' ','w','o','r','l','d'}; //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] = {'h','e','l','l','o',' ','w','o','r','l','d'}; printf("sizeof(str): %d\n",sizeof(str)); printf("str: %s\n",str); int i = 0; while(*(str + i) != '\0') //判断是否加上'\0' { printf("%c\n",*( str + i++)); } return 0; }
运行结果如下:
问题3:
字符数组越界访问能编译通过吗?
字符数组越界访问编译可以通过,没有报错,这样会出现很多的问题
#include <stdio.h> int main() { char str[12] = {'h','e','l','l','o',' ','w','o','r','l','d'}; printf("%c\n",str[100]); return 0; }
打印为空
问题4:
字符数组和字符指针又有什么区别呢?
首先在内存的中位置不同,字符数组保存的字符串存放在内存的栈中,而字符指针指向的字符串保存在内存的静态存储区中。
其次字符数组保存的字符串属于字符串变量,可以被修改,而字符指针指向的字符串是属于字符串常量,不能被修改。
#include <stdio.h> int main() { char str[12] = {'h','e','l','l','o',' ','w','o','r','l','d'}; char* ptr = "hello world"; str[0] = 'f'; ptr[0] = 'f'; //将字符指针指向的字符串修改,将出现段错误,因为该内存地址只读,因为该字符串属于常量 return 0; }
运行结果:
段错误是指访问的内存超出了系统给这个程序所设定的内存空间,例如访问了不存在的内存地址、访问了系统保护的内存地址、访问了只读的内存地址等等情况。
#include <stdio.h> int main() { char* ptr = "hello world"; ptr[11] = '!'; //往常量字符串末尾添加字符,相当于连接两个字符串,出错 ptr[12] = '\0'; 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] = {'h','e','l','l','o',' ','w','o','r','l','d'}; 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] = 'h'; //这种赋值才是对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] = 'h'; 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] = 'A'; //数组下标型赋值 *(str + 1) = 'l'; //指针++型赋值 str[2] = 'e', *(str + 3) = 'x'; 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] = 'A'; *(str + 1) = 'l'; str[2] = 'e', *(str + 3) = 'x'; //str[4] = '\0'; //当我们没有手动给字符串结尾附上'\0' 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] = 'A'; *(str + 1) = 'l'; str[2] = 'e', *(str + 3) = 'x'; str[4] = '\0'; 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) != '\0'; i++) *(dest + i) = *(src + i); } void mem_move(char* const dest, const char* const src) { int i = 0; while(*(src + i) != '\0') 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语言中字符串操作的一些理解

热AI工具

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

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

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

热门话题

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

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

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

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

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

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

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

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