区别1:
当一个指针变量在未取得确定地址前使用是危险的,容易引起错误。
一个错误的例子,如下:
char *name;
scanf("%s",name);
printf("%s",name);
有的编译器虽然也能通过,但这是错误的,因为是个指针,定义时指向不可用的地址。解决这个问题有两种方法:用数组的方法或给字符指针分配内存空间的方法。
数组的方法:
char name[20];
scanf("%s",name);
printf("%s",name);
给字符指针分配内存空间的办法:
char *name;
name=(char*)malloc(50); //此时name已经指向一个刚刚分配的地址空间。
scanf("%s",name);
printf("%s",name);
区别2:
- 在ANSI C中,初始化指针时所创建的字符串常量被定义为只读。如果试图通过指针修改这个字符串的值,程序就会出现未定义的行为。在有些编译器中,字符串常量被存放在只允许读取的文本段中,以防止它被修改。
- 数组也可以用字符串常量进行初始化:
Char a[]=”abcdefg”;
如指针相反,由字符串常量初始化的数组是可以修改的。其中的单个字符在以后可以改变。
#include<iostream>using namespace std;
#include<ctype.h>
/******************************************************************************/
/*
6 * Convert a string to lower case
7 */
int strlower(char *string)
{
if (string == NULL)
{
return -1;
}
while (*string)
{
if (isupper(*string))
* string = tolower(*string);
string++;
}
* string = '\0';
return 0;
}
void main()
{
char test[] = "ABCDEFGhijklmN";//如果改成char *test='' ABCDEFGhijklmN"就不对了。
strlower(test);
cout << test << endl;
}
**********************************************************我是分割线哦!**************************************************************************
copy的别人的内容
C++/C程序中,指针和数组在不少地方可以相互替换着用,让人产生一种错觉,以为两者是等价的。
数组要么在静态存储区被创建(如全局数组),要么在栈上被创建。数组名对应着(而不是指向)一块内存,其地址与容量在生命期内保持不变,只有数组的内容可以改变。
指针可以随时指向任意类型的内存块,它的特征是“可变”,所以我们常用指针来操作动态内存。指针远比数组灵活,但也更危险。
下面以字符串为例比较指针与数组的特性。
1 修改内容
示例1中,字符数组a的容量是6个字符,其内容为hello\0。a的内容可以改变,如a[0]= ‘X’。指针p指向常量字符串“world”(位于静态存储区,内容为world\0),常量字符串的内容是不可以被修改的。从语法上看,编译器并不觉得语句p[0]= ‘X’有什么不妥,但是该语句企图修改常量字符串的内容而导致运行错误。
char a[] = “hello”; a[0] = ‘X’; cout << a << endl; char *p = “world”; // 注意p指向常量字符串 p[0] = ‘X’; // 编译器不能发现该错误 cout << p << endl; |
示例1 修改数组和指针的内容
2 内容复制与比较
不能对数组名进行直接复制与比较。示例2中,若想把数组a的内容复制给数组b,不能用语句 b = a ,否则将产生编译错误。应该用标准库函数strcpy进行复制。同理,比较b和a的内容是否相同,不能用if(b==a) 来判断,应该用标准库函数strcmp进行比较。
语句p = a 并不能把a的内容复制指针p,而是把a的地址赋给了p。要想复制a的内容,可以先用库函数malloc为p申请一块容量为strlen(a)+1个字符的内存,再用strcpy进行字符串复制。同理,语句if(p==a) 比较的不是内容而是地址,应该用库函数strcmp来比较。
// 数组… char a[] = "hello"; char b[10]; strcpy(b, a); // 不能用 b = a; if(strcmp(b, a) == 0) // 不能用 if (b == a) … |
// 指针… int len = strlen(a); char *p = (char *)malloc(sizeof(char)*(len+1)); strcpy(p,a); // 不要用 p = a; if(strcmp(p, a) == 0) // 不要用 if (p == a) … |
示例2 数组和指针的内容复制与比较
3 计算内存容量
用运算符sizeof可以计算出数组的容量(字节数)。示例3(a)中,sizeof(a)的值是12(注意别忘了’\0’)。指针p指向a,但是sizeof(p)的值却是4。这是因为sizeof(p)得到的是一个指针变量的字节数,相当于sizeof(char*),而不是p所指的内存容量。C++/C语言没有办法知道指针所指的内存容量,除非在申请内存时记住它。
注意当数组作为函数的参数进行传递时,该数组自动退化为同类型的指针。示例3(b)中,不论数组a的容量是多少,sizeof(a)始终等于sizeof(char *)。
char a[] = "hello world"; char *p = a; cout<< sizeof(a) << endl; // 12字节 cout<< sizeof(p) << endl; // 4字节 |
示例3(a) 计算数组和指针的内存容量
void Func(char a[100]) { cout<< sizeof(a) << endl; // 4字节而不是100字节 } |
示例3(b) 数组退化为指针
*****************************************************************************************************************************************************************************************
char数组与char指针
1、以字符串形式出现的,编译器会在结尾自动添加\0,思考,为什么?
存在的C语言方法,如strlen(s),计算字符串的长度,其中s指针。strlen要计算字符串长度,必须知道哪里是结尾,因此使用\0表示结尾。只有字符数组才有\0的概念,其它类型(int)的数组没有这个概念。因为其他类型的数组或者指针,没有strlen这种方法。
那么问题来了,int数组如何计算长度呢?如int a1 = {3,7,9,};
使用sizeof(a1)/sizeof(int)。
2、数组可以在栈上分配,也可以在堆上分配,但必须指定大小。
char a1[100]; //在栈上分配
char* pa = new char[100];// 在堆上分配,返回首元素的地址
3、char a1[] = "abc"; 相当于在栈顶分配4个字节,分别放上a,b,c,\0,等价于char a1 ={'a','b','c','\0'};
4、char* pa = "abc"; 分析一下就知道,pa是char指针,"abc"是一个文本字符串,显然类型不吻合,需要适配。可认为编译器做了下面的事情:在常量区分配4个字节,分别放上a,b,c,\0,然后把a的地址返回给pa。
注意:文本字符串放在常量区,是不可修改的,试图修改,运行异常。那么在思考一下,既然右边是const,而pa并没有限定为const char*,按道理赋值失败。为什么可以成功?
可以认为在C语言中,到处充斥着这样的代码。为了兼容,必须允许。但是,我们应该写const char* pa ="abc"; 这样的话,试图修改pa的内容,编译报错。
5、char a1[] = "abc", 等价于char a1[] = {'a','b','c','\0',}; strlen(a1)等于3,长度不包括\0
假如这样写 char a1[] = {'a','b','c',}; strlen(a1)是多少? 答案不确定,因为strlen一直找到\0才认为是结尾。
6、 char a1[] = "abc"; 下面的结果分别是什么?
cout<<&a1[0]<<endl;
cout<<a1<<endl;
输出相同,都是数组元素的第一个地址。
7、char* pa = "abc"; 下面的结果分别是什么?
cout<<&pa<<endl;
cout<<&pa[0]<<endl;
cout<<pa<<endl;
第一行输出pa在栈上的地址,第二行和第三行输出相同,都是首地址。pa是指针,就是指向首个元素的地址。
8、char a1[5]; 数组名是个指针常量,不能修改指向。
9、char* pa = "abc"; 可认为pa是个指向常量的指针。
10、下面的结果,违反直觉,按道理第4行,第5行应该输出地址。但是却输出指向的字符串。这有一定的合理性,我们打印char指针,往往是要看指向的内容,而不是要看地址是多少。而且cout很容易做到,只要遇到\0就结束。那么问题来了,我想看地址怎么办?使用int强制转化为地址。
1 char a1[]="abc"; 2 char* pa="def"; 3 4 cout<<a1<<endl; //输出abc 5 cout<<pa<<endl; //输出def 6 7 cout<<(int)a1<<endl; // 输出a1地址 8 cout<<(int)pa<<endl; // 输出pa地址
11、
1 char p[]="abcde"; 2 char* p2="abcde"; 3 4 cout<<sizeof(p)<<endl; //数组大小为6 5 cout<<sizeof(p2)<<endl; // 指针大小为4 6 7 cout<<strlen(p)<<endl; // 长度为5 8 cout<<strlen(p2)<<endl; // 长度为5