一、字符数组?
1、什么是字符数组?
在一个数组中,每个成员都是字符。
例如: char A[3]; -> 每一个成员都是字符来的,所以组成一个字符串。
2、字符数组的赋值?
char A[10] = {'h','e','l','l','o'}; 剩余5个没有赋值的成员都是十进制0。 -> 等价于5个'\0'
char A[10] = {"hello"}; 将字符串"hello"直接赋值给数组。
char A[10] = "hello"; 与第2种写法一样的,{}可以省略。
思考题:
1)请问"char A[10] = {"10086"}与int A[10] = {1,0,0,8,6}"有什么区别?
char A[10] = {"10086"} -> 其实10086这几个数字是一些字符来的,等价于 char A[10] = {'1','0','0','8','6'}
char A[10] = {49,48,48,56,54};
int A[10] = {1,0,0,8,6} -> 其实10086这几个数字是十进制数组来的。 等价于 int A[10] = {SOH,'\0','\0','\b',ACK};
2)请问能不能这样写?
int A[10] = "10086"; -> 不可以将一个字符串直接赋值给一个整型数组。
(因为字符串在内存中是一个地址来的,所以不能将一个地址赋值给一个整型数组)
int A[10] = {'1','0','0','8','6'}; -> 正确,等价于 int A[10] = {49,48,48,56,54};
3、从内存角度分析以下的问题。
char A[10] = {'h','e','l','l','o'};
与
char A[10] = {"hello"};
前者是从常量区将hello这5个字符拷贝到栈区数组中,然后系统就会补5个数字0,等价于字符'\0'。
后者是从常量区中将hello这个字符串拷贝到栈区数组中,然后字符串默认带一个'\0'在后面的,所以一共拷贝了6个字符到数组中,然后系统就会补4个数字0,等价于'\0'。
二、字符指针。
1、什么是字符指针?
指向一个字符变量的地址就是字符指针。
例子:
int a;
int *pa = &a; -> pa就是一个整型指针,这个指针指向整型变量a的。
char b;
char *pb = &b; -> pb就是一个字符指针,这个指针指向字符变量b的。
2、有时候,我们会看到一个字符串赋值给一个字符指针?
char *p = "helloworld"; -> 正确
问题: 究竟字符指针是指向一个字符,还是一个字符串?
字符指针永远都是指向一个字符的,不可能指向一个字符串的,在这个例子中,指针p其实是存放在"helloworld"字符串第一个元素'h'的地址。
3、关于字符数组与字符指针需要注意的问题。
1)每一个字符串都是属于常量区的数据,而且字符串在常量区中往往是以'\0'作为结束标志。
拷贝常量区的字符串时,是连'\0'一起拷贝。
2)常常会看到程序都是用这两种办法来保存字符串,那么它们有什么区别?
char A[10] = "hello";
char *p = "hello";
char A[10] = "hello";
在内存栈区中连续申请10个字节,然后使用变量A间接访问这片内存空间,将常量区中的"hello"这个字符串拷贝到变量A代表的这片内存空间。
char *p = "hello";
在内存栈区中连续申请8个字节,然后使用变量p间接访问这片内存空间,然后将常量区中的"hello"字符串中的第一个字符'h'的地址赋值给p对应的空间上。
3)%s -> 输出一个字符串。
输出原则:
给定一个地址,判断该地址上的字符是不是'\0'
如果不是'\0',则打印该字符,并且将地址往后挪动一个单位,再继续判断。
如果是'\0',则结束打印。
完成14/16/17题。
三、const关键词。
1、什么是const指针?
已经学习过非常多指针类型,例如:int* -> 整型指针 char* -> 字符指针。
const指针并不是指向const这种类型,const不是一种类型,是一个修饰关键词。
2、const使用场景。
const大多数都是用于修饰一个指针,很少会去修饰一个变量。
一般都是出现在函数的形式参数中。
3、举例子。
例子1:
不使用const的情况:
#include <stdio.h>
int fun(int x) //x = age
{
x = 100; //x可以随意赋值
}
int main(int argc,char *argv[])
{
int age = 18;
fun(age);
return 0;
}
使用const的情况:
#include <stdio.h>
int fun(const int x) //x可以赋值一次值,但是赋值了之后,就不能通过x去修改x的值。
{
printf("x = %d\n",x); -> 打印一下值是没有问题。
x = 100; //x可以随意赋值 -> 错误的
}
int main(int argc,char *argv[])
{
int age = 18;
fun(age);
return 0;
}
例子2:
#include <stdio.h>
int main(int argc,char *argv[])
{
/*
const int a = 100;
//a存储了100,一旦赋值了100之后,那么就不能通过a修改a的值。
printf("a = %d\n",a); //正确
//a = 50; //编译报错
*/
//const int a; //随机值
//a = 100;//编译报错
//printf("a = %d\n",a);
/*
int a = 100;
int b = 50;
int *p = &a;
p = &b;
//请问*p得到什么?
printf("*p = %d\n",*p); //50
*/
/*
int a = 100;
int b = 50;
int * const p = &a; //p储存着a的地址,一旦赋值了&a之后,那么就不能通过p修改p的值。
p = &b; //error: assignment of read-only variable ‘p’
//p就不能等于别的值。
//请问*p得到什么?
//printf("*p = %d\n",*p); //编译出错,没答案。
*/
/*
int a = 100;
int b = 50;
int * const p = &a; //p储存着a的地址,一旦赋值了&a之后,那么就不能通过p修改p的值。
//p就不能存储别的地址。
*p = 30; //虽然p不能等于别的值,但是我们可以通过p修改p指向的东西。
//请问*p得到什么?
printf("*p = %d\n",*p); //30
*/
/*
int a = 100;
int b = 50;
const int *p = &a; //p储存着a的地址,因为const不是修饰p,所以p可以等于别的值
p = &b; //可以等于别的值。
//请问*p得到什么?
printf("*p = %d\n",*p); //50
*/
/*
int a = 100;
int b = 50;
const int *p = &a; //p储存着a的地址,因为const不是修饰p,所以p可以等于别的值
//const是修改p指向的内容,所以不能通过p修改p指向的内容。
*p = 30;
//请问*p得到什么?
printf("*p = %d\n",*p); //编译出错
*/
/*
int a = 100;
int b = 50;
int const *p = &a; //p储存着a的地址,因为const不是修饰p,所以p可以等于别的值
p = &b; //p可以等于别的值。
//请问*p得到什么?
printf("*p = %d\n",*p);
*/
/*
int a = 100;
int b = 50;
int const *p = &a; //p储存着a的地址,因为const不是修饰p,所以p可以等于别的值
//const是修改p指向的内容,所以不能通过p修改p指向的内容。
*p = 30;
//请问*p得到什么?
printf("*p = %d\n",*p); //编译出错
*/
/*
int a = 100;
int b = 50;
const int *p = &a; //不能通过p修改p指向的内容
//*p = 30;
a = 30; //但是我是通过a去修改的。
//请问*p得到什么?
printf("*p = %d\n",*p); //30
*/
/*
const int a = 100;
int *p = &a;
*p = 30;
//请问*p得到什么?
printf("*p = %d\n",*p);//30
*/
}