综述:在C语言中字符串或字符数组最后都会有一个额外的字符‘\0’来表示结束,而在java语言中没有结束符这一概念。具体见下面分析。
1. C 语言
在C语言中字符串和字符数组基本上没有区别,都需要结束符;如:char s[4]={'a','b','c','d'};此字符数组的定义编译可以通过,但却没有关闭数组,若其后需要申请内存,那么以后的数据均会放入其中,尽管它的长度不够,但若为 char s[5]={'a','b','c','d'};则系统会自动在字符串的最后存放一个结束符,并关闭数组,说明字符数组是有结束符的;而字符串定义的长度必须大于字符序列的长度,如:char s1[4]={"abcd"};编译不能通过,而应写成char s1[5]={"abcd"};并且系统会自动在字符串的最后存放一个结束符,说明字符串有结束符;
在C语言中使用strlen()函数可以测数组的长度,strlen(()函数计算的时候不包含结束符'\0'。
char s[5]={'a','b','c','d'};
char s1[5]={"abcd"};
int a=strlen(s);
int b=strlen(s1);
结果是a,b均为4;
注:printf函数跟strlen一样,打印输出字符串/数组时都以'\0'作为结束符,即:打印输出到'\0'为止(不包括'\0')。
2.Java语言
字符串和字符串数组都是不需要结束符的;
如:char[] value={'j','a','v','a','语','言'};
String s1=new String(value);
String s2="java语言";
int a=value.length;
int b=s1.length();
int c=s2.length();
运行得到的结果a,b,c都是6,说明字符串和字符串数组都不需要结束符。但注意此处value.length和s1.length(),在数组中有属性length可以记录数组对象的长度,而length()方法是File类中的一个实例方法,用于返回文件的大小,当然也可以返回字符串的大小。
3.java中无需结束符的原因
Java里面一切都是对象,是对象的话,字符串肯定就有长度,即然有长度,编译器就可以确定要输出的字符个数,当然也就没有必要去浪费那1字节的空间用以标明字符串的结束了。比如,数组对象里有一个属性length,就是数组的长度,String类里面有方法length()可以确定字符串的长度,因此对于输出函数来说,有直接的大小可以判断字符串的边界,编译器就没必要再去浪费一个空间标识字符串的结束。
4.java字符串末尾空字符的处理
java和c通信的时候,由于c中的char中有结束符的,所以当java收到C发来的字符串时,后面往往会有若干空字符,如果不做处理的话,java会对其一并输出,为了将空字符处理掉不输出,可以采用如下两种方法:
方法一:
调用java字符串的trim()方法,该方法会将字符串前后的空字符读去掉。
方法二:自己实现去掉尾部空字符的方法:
-
/**
-
* 截取掉C中之前的字符串。即只截取前的字符
-
*
-
* @param s:尾部带有空字符的java字符串
-
* @return
-
*
-
*/
-
public static String deletTailChar0(String s){
-
if(s ==
null){
-
return
null;
-
}
-
char[] chars = s.toCharArray();
-
StringBuffer sb =
new StringBuffer();
-
for(
char c : chars){
-
Character ch = c;
-
if(
0 == ch.hashCode()){
//如果到了字符串结束,则跳出循环
-
break;
-
}
else{
-
sb.append(c);
-
}
-
}
-
return sb.toString();
-
}
附:
1.Java 数组初始化的两种方法:
静态初始化: 程序员在初始化数组时为数组每个元素赋值;
动态初始化: 数组初始化时,程序员只指定数组的长度,由系统为每个元素赋初值。
-
public
class ArrayInit {
-
public static void main(String[] args) {
-
-
//静态初始化数组:方法一
-
String cats[] =
new String[] {
-
"Tom",
"Sam",
"Mimi"
-
};
-
-
//静态初始化数组:方法二
-
String dogs[] = {
"Jimmy",
"Gougou",
"Doggy"};
-
-
//动态初始化数据
-
String books[] =
new String[
2];
-
books[
0] =
"Thinking in Java";
-
books[
1] =
"Effective Java";
-
-
System.out.println(cats.length);
-
System.out.println(dogs.length);
-
System.out.println(books.length);
-
}
-
}
注意,
声明一个数组不需分配任何存储空间,它仅仅是代表你试图创建一个数组。跟C/C++声明一个数组的明显区别就是空间的大小没有被特别标识。因此,下面的声明将会引起一个编译期错误。
迭代器其实就是维护一个当前的指针,这个指针可以指向当前的元素,可以返回当前所指向的元素,可以移到下一个元素的位置,通过这个指针可以遍历容器的所有元素。迭代器一般至少会有以下几种方法:
First(); //将指针移至第一个位置或获得第一个元素
GetCurrent(); //获得当前所指向的元素
MoveNext(); //移至下一个元素
2.1 C++中的迭代器:
-
void TestIterator()
-
{
-
vector<
int> vec;
// 定义一容器
-
for(
int i =
0; i <
5; i++)
-
{
-
vec.push_back(i*
2);
//添加元素
-
}
-
//用迭代器访问容器中的每个元素
-
cout <<
"iterator vector:" <<
endl;
-
for(
vector<
int>::iterator itr = vec.begin(); itr != vec.end(); itr ++)
-
{
-
cout << *itr <<
" ";
//itr是一个指针,指向当前的元素, 所以要解引用获得元素值
-
}
-
cout <<
endl;
-
-
-
map<
int,
string> student;
//创建一个map,对应学号-姓名的键值对
-
//添加元素
-
student.insert(
pair<
int,
string>(
1,
"张三"));
-
student.insert(
pair<
int,
string>(
3,
"王五"));
-
student.insert(
pair<
int,
string>(
2,
"李四"));
-
//遍历容器中的元素
-
cout <<
"iterator map:" <<
endl;
-
for (
map<
int,
string>::iterator itr = student.begin(); itr != student.end(); itr ++)
-
{
-
cout << itr->first <<
"-->" << itr->second <<
endl;
-
}
-
}
c++中的容器(如vector、map、list、set等)一般会提供四个迭代器:
iterator:正向迭代,从前往后遍历,可修改元素的值
const_iterator:正向常量迭代,但不能修改元素的值,因为指向的是const的引用
reverse_iterator:反向迭代,从后往前遍历,可修改元素的值
const_reverse_iterator:反向常量迭代,但不能修改元素的值,因为指向的是const的引用
每一种迭代器都提供一对首尾位置的标志begin和end。
2.2 Java中的迭代器:
-
public static void testIterator() {
-
//创建一个列表
-
List<Integer> list =
new ArrayList<Integer>();
-
list.add(
4);
//添加元素
-
list.add(
3);
-
list.add(
7);
-
-
//返回一个迭代器,并遍历列表中的元素
-
Iterator<Integer> iterator = list.iterator();
-
while (iterator.hasNext()) {
-
Integer value = iterator.next();
-
System.out.print(value +
" ");
-
}
-
System.out.println();
-
-
//返回ListIterator迭代器并从后往前遍历列表的元素
-
ListIterator<Integer> listIterator = list.listIterator(list.size());
-
-
System.out.println(
"ListIterator:");
-
while (listIterator.hasPrevious()) {
-
Integer value = listIterator.previous();
-
System.out.print(value +
" ");
-
}
-
System.out.println();
-
}
Java中的List接口及其实现类可以通过iterator()返回Iterator,或通过listIterator()和listIterator(int index) 返回ListIterator。
Iterator和ListIterator都是迭代器,ListIterator继承自Iterator。Iterator只能对列表进行遍历,且只能从前往后遍历,ListIterator可以修改列表,且可以选择往前或往后遍历。
java中map容器的遍历(可分别利用keySet或entrySet):
-
方法一:keySet遍历key+value:
-
Iterator<String> iter = map.keySet().iterator();
-
while (iter.hasNext()) {
-
key = iter.next();
-
value = map.get(key);
-
}
-
-
方法二:entrySet遍历key+value:
-
Iterator<Entry<String, String>> iter = map.entrySet().iterator();
-
Entry<String, String> entry;
-
while (iter.hasNext()) {
-
entry = iter.next();
-
key = entry.getKey();
-
value = entry.getValue();
-
}
迭代器小结:C++中通过容器对象的begin或end方法来获取到迭代器,其迭代器的含义是一个指针,指向容器中的元素;而java中的迭代器是一个对象,通过容器的iterator()方法得到容器的迭代器,之后通过迭代器对象的方法hasNext()来获取到容器的指向。
3.C语言常用字符串函数
函数名: strrchr
功 能: 在串中查找指定字符的最后一个出现
用 法: char *strrchr(char *str, char c);
举例:
-
char fullname=
"./lib/lib1.so";
-
char *ptr;
-
ptr =
strrchr(fullname,
'/');
-
printf(
"filename is %s",++ptr);
-
//运行结果:filename is lib1.so
函数名: strchr
功 能: 在串中查找指定字符的第一个出现
用 法: char *strchr(char *str, char c);
举例:
-
char fullname=
"./lib/lib1.so";
-
char *ptr;
-
ptr =
strrchr(fullname,
'.');
-
printf(
"after strchr() is %s",++ptr);
-
//运行结果:after strchr() is /lib/lib1.so
函数名: strtok
功 能: 在串中查找指定字符的第一个出现
用 法: char *strtok(char *s, char *delim);
说明:
1.strtok函数的实质上的处理是,strtok在s中查找包含在delim中的字符并用NULL(’\0′)来替换,直到找遍整个字符串。这句话有两层含义:(1)每次调用strtok函数只能获得一个分割单位。(2)要获得所有的分割单元必须反复调用strtok函数。
2.strtok函数以后的调用时的需用NULL来替换s.
3.形参s(要分割的字符串)对应的变量应用char s[]=”….”形式,而不能用char *s=”….”形式。
举例:
-
void main()
-
{
-
char buf[]=”Golden Global View”;
-
char* token = strtok( buf, ” “);
-
while( token !=
NULL )
-
{
-
printf( ”%s “, token );
-
token = strtok(
NULL, ” “);
-
}
-
return
0;
-
}
-
/*其结果为:
-
-
Golden
-
Global
-
View
-
*/
strcspn() 用来计算字符串 str 中连续有几个字符都不属于字符串 accept,其原型为:int strcspn(char *str, char *accept);
【参数说明】str、accept为要进行查找的两个字符串。
strcspn() 从字符串 str 的开头计算连续的字符,而这些字符都完全不在字符串 accept 中。简单地说,若 strcspn() 返回的数值为 n,则代表字符串 str 开头连续有 n 个字符都不含字符串 accept 中的字符。
【返回值】返回字符串 str 开头连续不含字符串 accept 内的字符数目。
注意:如果 str 中的字符都没有在 accept 中出现,那么将返回 atr 的长度;检索的字符是区分大小写的。
提示:函数 strspn() 的含义与 strcspn() 相反,可以对比学习。
【示例】返回s1、s2包含的相同字符串的位置。
-
#include<stdio.h>
-
#include <stdlib.h>
-
#include<string.h>
-
int main()
-
{
-
char* s1 =
"http://c.biancheng.net/cpp/u/biaozhunku/";
-
char* s2 =
"c is good";
-
int n =
strcspn(s1,s2);
-
printf(
"The first char both in s1 and s2 is :%c\n",s1[n]);
-
printf(
"The position in s1 is: %d\n",n);
-
-
system(
"pause");
-
return
0;
-
}运行结果:
-
The first
char both in s1
and s2 is :c
-
The position in s1 is:
7
再看一个例子,判断两个字符串的字符是否有重复的。
-
#include<stdio.h>
-
#include <stdlib.h>
-
#include<string.h>
-
int main()
-
{
-
char* s1 =
"http://c.biancheng.net/cpp/xitong/";
-
char* s2 =
"z -+*";
-
-
if(
strlen(s1) ==
strcspn(s1,s2)){
-
printf(
"s1 is diffrent from s2!\n");
-
}
else{
-
printf(
"There is at least one same character in s1 and s2!\n");
-
}
-
-
system(
"pause");
-
return
0;
-
}
-
运行结果:
-
s1 is diffrent from s2!
strpbrk()函数检索两个字符串中首个相同字符的位置,其原型为:char *strpbrk( char *s1, char *s2);
【参数说明】s1、s2要检索的两个字符串。
strpbrk()从s1的第一个字符向后检索,直到'\0',如果当前字符存在于s2中,那么返回当前字符的地址,并停止检索。
【返回值】如果s1、s2含有相同的字符,那么返回指向s1中第一个相同字符的指针,否则返回NULL。
注意:strpbrk()不会对结束符'\0'进行检索。
【函数示例】输出第一个相同字符之后的内容。
-
#include<stdio.h>
-
#include<string.h>
-
int main(void){
-
char* s1 =
"http://see.xidian.edu.cn/cpp/u/xitong/";
-
char* s2 =
"see";
-
char* p =
strpbrk(s1,s2);
-
if(p){
-
printf(
"The result is: %s\n",p);
-
}
else{
-
printf(
"Sorry!\n");
-
}
-
return
0;
-
}
-
输出结果:
-
The result is: see.xidian.edu.cn/cpp/u/xitong/
C语言中常用的API函数可参考:C语言中文网