我知道C和我正在进入Java并且对它的数组和字符串方法感到困惑.它与C中的数组和字符串完全不同.请帮助我理解C和Java之间的区别(对于字符串和数组).
hay*_*lem 24
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);
}
Run Code Online (Sandbox Code Playgroud)
以下内容对int变量有效.注意稍微修改以适应整数的大小:
#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);
}
Run Code Online (Sandbox Code Playgroud)
(要获取给定数据类型的大小,请使用sizeof.)
在这里,我假设您想了解传统的C字符串实现,而不是第三方库提供的实现.
C中的字符串基本上只是字符数组.这个的主要原因是显而易见的:因为你需要经常操作字符串并将它们打印到流中,使用连续的内存空间是有意义的,并且是一个简单的实现.但是,由于您需要记住连续内存空间的大小而不是无意中访问禁止的内容,我们依赖于"以NULL结尾的字符串"的概念,这意味着N个字符的字符串实际上是N + 1的数组由尾部'\ 0'字符终止的字符,当您想要到达字符串的末尾时,该字符用作要执行的事实字符.
一个简单的声明是:
char *test = "my test";
Run Code Online (Sandbox Code Playgroud)
这相当于:
char test[8] = { 'm', 'y', ' ', 't', 'e', 's', 't', '\0' };
Run Code Online (Sandbox Code Playgroud)
(注意尾随'\ 0')
但是,您必须意识到在这种情况下,字符串"my test"是静态的,这是您直接指向的内存空间.这意味着在尝试动态修改它时会遇到问题.
例如,这会在你面前爆炸(遵循之前的声明):
test[4] = 'H'; /* expect a violent complaint here */
Run Code Online (Sandbox Code Playgroud)
因此,要实际修改字符串,可以将字符串声明为:
#include <stdio.h>
#include <stdlib.h>
int main(int ac, char **av) {
char *test = strdup("my test");
printf("%s\n", test);
return (0);
}
Run Code Online (Sandbox Code Playgroud)
其中strdup()是C标准库的一个函数,为你的字符串分配内存并在那里注入字符.或者您可以使用malloc()自己分配内存,并手动复制字符或使用strcpy()等函数.
因此,这个特殊的声明是可变的,你可以自由地修改字符串的内容(最后它只是一个动态分配的字符数组,用malloc()分配).
如果您需要更改此字符串的长度(向/从中添加/删除字符),则每次都需要警惕已分配的内存.例如,如果您尚未首先重新分配一些额外的内存,则调用strcat()将失败.但是,有些功能会为您解决此问题.
默认情况下,C字符串不支持Unicode.您需要实现自己管理代码点,或考虑使用第三方库.
Java中的数组与它们的C父级非常接近(我们甚至有一种方法可以使用裸骨本机实现进行有效的数组到数组复制支持: System.arraycopy()).它们代表连续的内存空间.
但是,它们将这些裸骨阵列包装在一个对象中(它可以跟踪数组的大小/长度).
Java数组可以修改它们的内容,但是就像它们的C语言一样,你需要在尝试扩展它们时分配更多的内存(除了间接地执行它们,并且通常会重新分配一个完整的数组而不是像C中那样执行realloc()).
Java中的字符串是不可变的,这意味着一旦初始化它们就无法更改,并且对String的操作实际上会创建新的String实例.查找StringBuilder和StringBuffer以使用现有实例进行有效的字符串操作,并注意其内部实现细节(特别是在有效预先设置缓冲区容量时,以避免频繁重新分配).
例如,以下代码使用someString和"另一个字符串" 生成第三个String实例:
String myNewStr = someString + "another string";
Run Code Online (Sandbox Code Playgroud)
在底层实现中,Java String*类也使用字符数组,就像它们的C父类一样.
这意味着它们比裸骨C实现使用更多内存,因为您有实例的开销.
不仅如此,它们实际上使用了更多的内存,因为Java String类默认提供Unicode支持,这意味着它允许每个字符有多个代码点(相比之下,在C中这不是一件容易的事).
另一方面,请注意除了考虑性能之外,您不必担心线程,内存和实现函数寻找尾随'\ 0'字符.
可以说和研究更多.您的问题目前相当广泛,但如果您在评论中添加子问题,我将很乐意进行编辑.
此外,也许这可以帮助:
Gro*_*uez 17
在C中,字符串通常只是一个(或指向)字符的数组,以NUL(\ 0)字符结尾.您可以像处理任何数组一样处理字符串.
但是,在Java中,字符串不是数组.Java字符串是类的实例(对象)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
Run Code Online (Sandbox Code Playgroud)
请注意,在Java中,arr存在但是为空值.在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
Run Code Online (Sandbox Code Playgroud)
Java中的数组对象必须使用new操作进行实例化,并且指定了数组大小:
int[] arr = new int [10];
int[][] 2Darr = new int[10][20];
Run Code Online (Sandbox Code Playgroud)
如果数组不是基本类型,则必须单独实例化每个单独的数组元素:
String[] strs = new String[10];
for (int i = 0; i < strs.length; i++)
strs[i] = new String("some value");
Run Code Online (Sandbox Code Playgroud)
在Java数组表达式不必它们的类型"衰变"到指针类型类似于C数组表达式(这是很方便的,因为Java没有指针类型本身); Java中的数组类型是"第一类"对象,这意味着它们在任何上下文中都保留了它们的所有类型特征.将数组对象传递给方法时,该方法接收数组对象,而不是指针.
Java数组知道它们有多大(由.length属性给出).
字符串:
与C不同,Java提供了一种独特的String数据类型.不要将Java字符串视为以0结尾的char数组; 他们是不同的东西.
Java String对象是不可变的; 您无法修改String对象的内容.您可以从现有String对象的已修改内容创建新的String对象.还有像StringBuilder和StringBuffer这样的类,它们允许您直接操作字符数据并创建新的String对象.
希望有所帮助.