1.背景(33条消息) C++ 学习——char * ,char a[ ],char ** ,char *a[] 的区别_xiaohu的博客-CSDN博客
本来只是sjtu oj上一道普通的作业题,指针2 No.7
但是围绕着这道题我对指针做了一些了解(其实主要原因也包括昨天看牙的时候很闲,没有带作业)
2.正文
先看题目
总体来说,这道题思路并不难(相比于约瑟夫环之类的稍微难了一点的题)
分为3个部分
1:输入*变量*个字符串,并存储
2:对每一个字符串删去指定字符
3:按照字典逆序重排字符串
然而,由于之前对指针的了解并不深入,导致我在处理第一个部分的时候卡了很长时间
这里做一个小总结
(1)关于数组/字符数组/指针/字符串
1:数组
数组把多个数据存储在内存中地址相连的单元中,因此可以通过下标访问不同单元的元素
2:指针
指针是一种变量,存储了一个标识其他位置的地址
3:字符数组/字符指针/字符串
-
C语言通过使用字符数组来处理字符串,通常,我们把char数据类型的指针变量称为字符指针变量。字符指针变量与字符数组有着密切关系,它也被用来处理字符串。
-
初始化字符指针是把内存中字符串的首地址赋予指针,并不是把该字符串复制到指针中,此时可以通过指针来修改字符串的内容
char str[] = “Hello World”;
char *p = str;
printf("&str=%p %s\n",&str,str);
*p='h'; *(p+1)='E';
printf("p=%p %s\n",p,p);
“将内存中字符串的首地址赋予指针”可以通过指针修改字符串
然而,当我们用字符串常量对字符指针初始化时
“字符指针直接指向字符串常量”,则不能修改指针指向对象的值
char *p = "Hello World";
*p = 'h'; // 错误, 字符串常量不能修改
在本题中我也犯了这个错误,之后再提
(*在这里区分“字符指针”与“字符数组”
char string[ ]="This is a string.";
此时,string是字符数组,它存放了一个字符串。
字符指针str与字符数组string的区别是:str是一个变量,可以改变str使它指向不同的字符串,但不能改变str所指的字符串常量。string是一个数组,可以改变数组中保存的内容。
则在程序中,可以使用如下语句:
str++; /* 指针str加1 */
str = "This is a NEW string."; /* 使指针指向新的字符串常量 */
str = str1; /* 改变指针str的指向 */
strcpy( string, "This is a NEW string.") /* 改变字符串的的内容 */
strcat( string, str) /* 进行串连接操作 */
在程序中,不能进行如下操作:
string++; /* 不能对数组名进行++运算 */
string = "This is a NEW string."; /* 错误的串操作 */
string = str1; /* 对数组名不能进行赋值 */
strcat(str, "This is a NEW string.") /* 不能在str的后面进行串连接 */
strcpy(str, string) /* 不能向str进行串复制 */
)
注意:数组名不能作左值
// 报错
char str1;
str1 = "abc";
// 想初始化或再次赋值只能单个元素赋值(如下行)
str1[0] = 'B';
4:char[][],char**,char*[]
在本题中,一维数组不足以完成任务,于是需要定义二维数组
再回顾一下
·定义一个字符数组,令其为字符串,很合理
char str[10] = {"hello world"};
·定义了一个字符指针,把字符串赋给指针变量
char *s ;
s = "China";
有些奇怪,类型是否一致
事实上,数组名也是一种指针
即str = &str[0],就是“hello”的首地址
所以s=“china”的本义是把一个字符串的首地址赋给另一个指针
level2:
char *s;char a[ ]
a是字符串的首地址,s保存了字符串的首地址
所以可以s=a,不能a=s(数组名不做左值)
因此
char a [ ] = "hello";
char *s =a;
for(int i= 0; i < strlen(a) ; i++)
printf("%c", s[i]);
printf("%c",*s++);
两种输出均是正确的
*另外,由于a代表一个地址,printf("%c",*a); (注意,不是a)
会输出字符串的第一个字符
进入level3
char *a [ ] ;
由于[ ] 的优先级高于* 所以a先和 [ ]结合,他还是一个数组,数组中的元素才是char *
所以 char *a[ ] = {"China","French","America","German"};
(同过这句可以看到, 数组中的元素是字符串,那么sizeof(a) 是多少呢,是五个单词的占内存中的全部字节数 6+7+8+7 = 28?
但是其实sizeof(a) = 16;
为什么, 字符串常量的本质是地址,a 数组中的元素为char * 指针,指针变量占四个字节,那么四个元素就是16个字节了)
·char s**
二级指针保存的是一级指针的地址,它的类型是指针变量,而一级指针保存的是指向数据所在的内存单元的地址,虽然都是地址,但是类型是不一样的
在 char** s 中,s 是一个指针,这个指针(s)指向一块内存地址,该内存地址中存储的是 char* 类型的数据。指针的加减运算在这里的体现为:a + 1 表示地址加4字节。
char* 也是一个指针,用 *s 表示,这个指针(*s)指向一块内存地址,该内存地址中存储的是 char 类型的数据。指针的加减运算在这里的体现为:(*a) + 1 表示地址加1字节。
想法到此结束,看看我的代码
char** str,** ori,ch;
str = new char* [n];
ori = new char* [n];
for (int i = 0;i < n;++i)
{
ori[i] = new char[50];
cin >> ori[i];
}
for (int i = 0;i < n;++i)
str[i] = new char[50];
由于是*变量*个字符串
因此在这里使用动态内存new
char **ori;
ori=new char*[n];
严丝合缝
new操作的结果只能赋给同类指针,(int *p;p=new int[10];)
在这里,ori是一个包括了n个字符串(字符指针char*)的数组
因此,当我想要输入字符串时
for (int i = 0;i < n;++i)
{
ori[i] = new char[50];
cin >> ori[i];
}
我要首先将ori[i](也就是ori中的一个元素---字符串)做初始定义
其实这里new不new都可以,但是要初定义
接下来用基本的cin即可(没有换行符,没有空格)
而当我在执行删去字符操作时
int tmp;tmp = 0;
int num;
for (int i = 0;i < n;++i)
{
tmp = 0;
num = 0;
for (int i1 = 0;i1 < strlen(ori[i]);++i1)
{
if (ori[i][i1] != ch)
{
str[i][tmp] = ori[i][i1]; ++tmp;
}
}
str[i][tmp + 1] = '\0';
}
用ori[i][i1]把这个字符调用出来,没有问题
但是此时不能用*ori[i][i1]修改它,原因待查
不过可以用新的str**来赋值,也是很简单的做法
这里关键:
定义str时是一个50长度的字符串
而在这里只给\0前面的赋值,str的\0还在后面
因此要 str[i][tmp + 1] = '\0';收束长度
字典重排
char temp[50];
for (int i = 0;i < n;++i)
{
for (int j = i;j < n;++j)
{
if (strcmp(str[i], str[j]) < 0)
{
strcpy(temp, str[i]);
strcpy(str[i], str[j]);
strcpy(str[j], temp);
}
}
}
需要注意的一些地方
比较单个字符可以使用关系运算符,比较字符串应使用strcmp()函数,
if(str[j] < str[i]) 错误
if(strcmp(str[j],str[i])<0) 正确
对单个字符串进行赋值操作可以使用赋值运算符,但是不能用于字符串的复制操作,
字符串赋值操作只能用strcpy()函数
temp = str[i];
str[i] = str[j];
str[j] = temp;
是错误的
***********************/
strcpy(temp,str[i]);
strcpy(str[i],str[j]);
strcpy(str[j],temp);
最后,简单的输出
for (int i = 0;i < n;++i)
cout << str[i]<<endl;
把字符串给出去。