我了解C语言,现在正在学习Java,对于它在数组和字符串上的处理方式感到困惑。它与C语言中的数组和字符串完全不同。请帮助我理解C语言和Java语言(在处理字符串和数组时)之间的实际区别。
C语言中的数组只是一种访问连续内存空间的语法糖,或者说是指针符号的变体。为了避免分配大块的连续内存,并避免自己操作可变大小的数据时需要重新分配内存,你可以使用常见的计算机科学数据结构概念的实现(例如链表,它使用指针来指示系列中下一个元素的内存地址)。
你可以用数组符号替代指针算术,在C语言中互换使用。
以下代码将使用不同的访问方法打印出一个数组的5个元素:
#include <stdio.h>
int main(int ac, char **av) {
char arr[2] = {'a', 'b'};
printf("0:%c 0:%c 1:%c 1:%c\n", arr[0], *arr, arr[1], *(arr + 1));
return (0);
}
#include <stdio.h>
int main(int ac, char **av) {
int arr[2] = {42, -42};
printf("0:%d 0:%d 1:%d 1:%d\n", arr[0], *arr, arr[1], *(arr + 4));
return (0);
}
(要获取给定数据类型的大小,请使用 sizeof。)
在这里,我假设您想了解传统的 C 字符串实现,而不是第三方库提供的实现。
C 中的字符串基本上只是字符数组。这样做的主要原因很明显:由于您需要经常操作字符串并将它们打印到流中,使用连续的内存空间是有意义且易于实现的。 但是,由于您需要记住连续内存空间的大小,以避免无意间访问禁止访问的内容,因此我们依赖于“NULL 结尾字符串”的概念,这意味着一个 N 个字符的字符串实际上是一个由 N + 1 个字符组成的数组,并以 '\0' 字符结尾,这个字符被用作查找字符串结尾时的默认字符。
一个简单的声明如下:
char *test = "my test";
char test[8] = { 'm', 'y', ' ', 't', 'e', 's', 't', '\0' };
(注意末尾的'\0')
然而,你必须意识到,在这种情况下,字符串"my test"是静态的,那就是你直接指向的内存空间。这意味着当你尝试动态修改它时,你会遇到问题。
例如,以下代码将会出现错误(在之前的声明后面添加):
test[4] = 'H'; /* expect a violent complaint here */
为了拥有一个可以实际修改的字符串,你可以简单地声明一个字符串:
#include <stdio.h>
#include <stdlib.h>
int main(int ac, char **av) {
char *test = strdup("my test");
printf("%s\n", test);
return (0);
}
strdup()是C标准库的一个函数,它为您的字符串分配内存并将字符注入其中。或者,您可以使用malloc()手动分配内存并复制字符,或使用像strcpy()这样的函数。
因此,此特定声明是可变的,您可以自由修改字符串的内容(最终只是一个使用malloc()分配的动态分配的字符数组)。
如果您需要更改此字符串的长度(添加/删除其中的字符),则每次都需要注意已分配的内存。例如,如果您没有先重新分配一些附加内存,则调用strcat()将失败。但是,某些函数将为您处理此问题。
C字符串默认情况下不支持Unicode。您需要自行实现管理代码点,或考虑使用第三方库。
Java中的数组与其C语言版本非常相似(甚至有一个方法用于高效的数组到数组的拷贝,使用了底层本地实现:System.arraycopy())。它们表示连续的内存空间。
然而,它们将这些底层数组封装在一个对象中(该对象为您跟踪数组的大小/长度)。
Java数组的内容是可以修改的,但与其C语言的对应物类似,当试图扩展数组时,您需要分配更多的内存(除了您间接地这样做之外,通常会重新分配完整的数组,而不是像在C中那样使用realloc())。
Java中的字符串是不可变的,这意味着一旦初始化就无法更改,并且对字符串的操作实际上会创建新的字符串实例。查找StringBuilder和StringBuffer以使用现有实例进行高效字符串操作,并注意其内部实现细节(特别是在有效预设缓冲区容量时,以避免频繁重新分配)。
例如,以下代码将从someString和"another string"产生第3个字符串实例:
String myNewStr = someString + "another string";
还有很多可以讲和研究的。
目前你的问题比较广泛,如果你在评论中添加子问题,我很乐意进行编辑。
此外,也许这可以帮助:
java.lang.String
类的实例(对象)。它们表示字符数据,但内部实现不暴露给程序员。您不能将它们视为数组,但是如果需要,您可以提取字符串数据作为字节数组或字符数组(方法getBytes
和getChars
)。还请注意,Java字符始终是16位,而C中的字符通常(并非总是)是8位。数组:
最显然的区别是Java在声明数组时不使用与C相同的语法。 在C中,数组下标是声明符的一部分,而在Java中,它是类型说明的一部分:
int[] arr; // Java, arr is null until array object is instantiated
int arr[]; // C, incomplete declaration
arr
存在但具有null值。在C语言中,只有在出现完整声明之后,arr
才存在。int[][] 2Darr; // Java, arr is null until array object is instantiated
int 2Darr[][]; // Illegal declaration in C; size must be specified for at least
// the outer dimension
new
操作进行实例化,同时指定数组的大小:int[] arr = new int [10];
int[][] 2Darr = new int[10][20];
如果数组不是基本类型,那么每个单独的数组元素都必须单独实例化:
String[] strs = new String[10];
for (int i = 0; i < strs.length; i++)
strs[i] = new String("some value");
Java中的数组表达式不像C中的数组表达式那样将其类型“退化”为指针类型(这很方便,因为Java本身没有指针类型);Java中的数组类型是“一流”的对象,这意味着它们在任何语境下都保留了它们所有的类型特征。当您将一个数组对象传递给方法时,该方法接收到的是一个数组对象,而不是指针。
Java数组知道它们的大小(由.length
属性给出)。
字符串:
与C不同,Java提供了一个独立的String数据类型。请不要将Java字符串视为带有零结尾的char数组;它们是不同的。Java String对象是不可变的;您无法修改String对象的内容。您可以从现有String对象的修改内容创建一个新的String对象。还有像StringBuilder和StringBuffer这样的类,允许您直接操作字符数据并创建新的String对象。
希望这有所帮助。
int[] a
或int a[]
。两者完全可互换。 - Grodrigueznew String("some value")
пјҢиҖҢжҳҜзӣҙжҺҘдҪҝз”Ё"some value"
гҖӮ - Thomas LötzerC语言中的字符串只是字符数组。当发现NUL字符(\0)时,字符串就结束了,这只是一种约定。
所有字符串操作都依赖于C标准库中的函数,如strlen()、strcpy()等。
要获得C“字符串”的大小,必须传递指向单独函数的指针。你可以认为在C中根本没有字符串,只有char数组的约定。
另一方面,Java将字符串作为语言本身的一部分内置了进去。Java String具有方法,例如可以告诉你它的大小。Java也有像C一样的基本类型,如float和int。
但它还有“对象”,而String就是一种对象。
这与C和C++之间的区别非常相似。
在C语言中,字符串实际上是以'\0'结尾的字符数组。而在Java中,字符串是一个类。Java字符串可以与C++中的std::string进行比较,而不是C语言中的字符数组。
声明:在C语言中 - char str[100]; 在Java中 - String str;
在Java中,大多数情况下,您不需要担心字符串的实现,因为提供了丰富的成员函数来处理它。在C语言中,也有许多API,如strlen、strcpy、strcat等,这些API对于正常操作已经足够了。
主要的区别在于当您需要执行涉及两个字符串的某些操作时。例如,假设将一个字符串分配给另一个字符串。在Java中,这很简单。
String str1("This is Stack Overflow.");
String str2;
str2 = str1;
但在C语言中,您将不得不使用循环来分配每个字符。现在再次强调,这并不意味着Java更快,因为在内部,Java也会执行相同的操作。只是程序员不知道而已。
在Java中,一些操作可以使用自然运算符来完成,例如比较。
str1 == str2。
但在C语言中,您将不得不使用strcmp函数来完成此操作。
strcmp(str1,str2);
在使用C语言时,您必须并且必须知道如何在内部操作字符串。但在Java中则不需要。
现在,在C中,当您在堆区创建字符串时,您还必须格外小心。
char * str1 = malloc(100);
您将需要使用free(str1)释放此内存。在Java中,程序员无需了解堆内存或栈内存,因此这样的事情不会出现。
==
运算符测试的是身份,而不是相等性。为了测试相等性,请使用 equals
方法。这不仅适用于字符串,也适用于所有对象。 - GrodriguezString是JAVA中的一个对象,它与C语言中的字符数组不同。