一、字符数组?
1、什么是字符数组?
一个数组中全部成员都是字符来的。
例子: char A[5];
2、字符数组赋值?
1)定义同时初始化?
char A[10] = {'h','e','l','l','o'}; -> 剩余没有赋值的5个元素都为0
char A[10] = {"hello"}; -> 将字符串hello赋值给数组
char A[10] = {"10086"}; -> char A[10]已经决定每一个成员都是字符类型,所以 '1','0','0','8','6'
int A[10] = {1,0,0,8,6}; -> int A[10]已经决定每一个成员都是整型类型,所以 1,0,0,8,6
char A[10] = "hello"; -> {}可以省略!
3、将字符串常量赋值给数组在内存中是如何变化?
int a = 10;
char A[10] = "hello";
其实将常量区中的值赋值给栈区空间。
1)注意:
所有字符串常量在常量区存在都会以'\0'作为结束的标志。
Oct Dec Hex Char
000 0 00 NUL '\0'
2)例如:
hello\0world\0apple\0tree\0
二、字符指针?
整型指针 -> int类型
字符指针 -> char类型
例子1:
char a = 'h';
char *p = &a; -> p就是字符指针 -> 指向一个字符类型的数据a
例子2:
char *p = "hello"; -> 正确!
究竟p指向字符?还是指向一个字符串?
字符指针p永远只能指向字符,不可能指向整个字符串,在这个例子,p指向"hello"这个字符串的首元素'h'的地址
注意:
1)p是一个指针变量,所以只能存放地址,存放着是hello中'h'的地址。
2)p是一个指针变量,不能存放字符串,不是将常量区的hello拷贝过来。
3)字符指针只能指向字符,不能指向字符串。
4)%s 输出字符串
输出原则:给定一个地址,判断地址上值是不是'\0'。
如果不是\0,则打印该地址上的值并将该地址往后挪动一个单位。
如果是\0,就停止打印。
请问以下代码是什么含义?
char A[10] = "hello";
char *p = "hello";
printf("A = %s\n",A); //A是字符串首元素的地址,结果:hello -> 打印的是栈区的hello
printf("p = %s\n",p); //p是字符串首元素的地址,结果:hello -> 打印的是常量区的hello
结论:
1)只要将一个字符串赋值给一个字符数组,那么就会把常量区的字符串拷贝到该字符数组中。
2)只要将一个字符串赋值给一个字符指针,那么该指针就是存放着这个字符串的首元素的地址。
#include <stdio.h>
int main(int argc,char *argv[])
{
char A[] = "helloworld";
char *p = "helloworld";
char *pa = A; //pa等价于数组名A,使用pa来访问东西,都是属于栈区!
printf("sizeof(A) = %d\n",sizeof(A));//11
printf("sizeof(p) = %d\n",sizeof(p));//4
printf("A = %s\n",A); //helloworld
printf("*A = %c\n",*A); //h 栈区
printf("*(A+1) = %c\n",*(A+1)); //e 栈区
printf("A+1 = %s\n",A+1); //elloworld 栈区
printf("p = %s\n",p); //helloworld 常量区
printf("pa = %s\n",pa); //helloworld 栈区
printf("A[0] = %c\n",A[0]); //h 栈区
A[0] = 'k';
printf("A = %s\n",A); //kelloworld 栈区
printf("*p = %c\n",*p); //h 常量区
//*p = 'k'; //26行段错误,原因常量区不能修改值。
//printf("p = %s\n",p);
printf("*pa = %c\n",*pa); //k 栈区
pa[0] = 'm';
printf("pa = %s\n",pa); //melloworld
return 0;
}
14、有以下程序
main()
{
char s[]=“Yes\n/No”,*ps=s;
puts(ps+4);
*(ps+4)=0;
puts(s);
}
程序运行后的输出结果是( B )
A) n/No B) /No C) n/No D) /No
Yes Yes Yes /No
/No /No Yes
16、有以下程序
main()
{
char s[]= “ABCD”,*p;
for(p=s+1;p<s+4;p++)
printf(“%s\n”,p);
}
程序运行后的输出结果是()
BCD
CD
D
17、以下程序运行后的输出结果是( gae )
main()
{
char a[]=“Language”,b[]=“Programe”;
char *p1,*p2;
int k;
p1=a;p2=b;
for(k=0;k<8;k++)
if(*(p1+k)==*(p2+k)) 等价于 if(p1[k] == p2[k])
printf(“%c”,*(p1+k));
}
三、指针数组
1、什么是数组指针?什么是指针数组?
数组指针是一个指针来的,这个指针指向整一个数组。
指针数组是一个数组来的,这个数组的每一个成员都是指针。
2、如何定义指针数组?
定义的方法与定义普通数组一致。
1)给一个数组名 p
2)确定元素的个数,使用[]括号括住它 p[5]
3)确定每一个元素的类型 int *pa
4)将第3步的变量名去掉 int*
5)将第4步的结果写在第2步结果的前面 int* p[5] -> 指针数组
3、如何定义数组指针?
int A[5];
int (*p)[5]; = &A; --> 数组指针
练习: 提示: strlen()计算字符串实际长度
15、有以下程序
main()
{
char str[][20]={“Hello”,”Beijing”},*p=str[0];
printf(“%d\n”,strlen(p+20));
}
程序运行后的输出结果是( C )
A) 0 B) 5 C) 7 D) 20
18、有以下程序
main()
{
char *p[10]={“abc”, “aabdfg”, “dcdbe”, “abbd”, “cd”};
printf(“%d\n”,strlen(p[4]));
}
执行后输出结果是( A )
A) 2 B) 3 C) 4 D) 5
19、若有定义:int *p[3];,则以下叙述中正确的是( B )
A)定义了一个基类型为int的指针变量p,该变量具有3个指针。
B)定义了一个指针数组p,该数组含有3个元素,每个元素都是基类型为int的指针。
C)定义了一个名为*p的整型数组,该数组含有3个int类型元素。
D)定义了一个可指向一维数组的指针变量p,所指一维数组应具有3个int类型元素。
若有以下程序:
void main()
{
char *a[3] = {"I","love","China"};
char **ptr = a;
printf("%c %s",*(*(a+1)+1),*(ptr+1)); // 'o' "love"
}
四、const指针?
1、什么是const指针?
已经学习了非常多指针种类,例如:整型指针int*、字符指针char* -> 指的是指针的类型
const指针并不是指针的类型,只是用于修饰特定的指针类型。
2、使用场景?
一般const作用形式参数。
例子:
int fun(int a); //a=10 -> 可以随时通过a修改a本身的值。
int fun(const int a); //a=10 一旦a被初始化后,不能通过a修改a的值。
int main()
{
fun(10);
}
结论: const修改了某个变量之后,就不能通过该变量修改该变量里面的值。
3、 例子:
#include <stdio.h>
int main()
{
/* const作用于整型变量
const int a;//使用const修饰变量a,一旦变量初始化随机值之后,就不能通过a修改a的值
a = 100; //编译出错: error: assignment of read-only variable ‘a’
printf("a = %d\n",a);
//a = 200; //编译出错: error: assignment of read-only variable ‘a’
//printf("a = %d\n",a);
*/
/* const作用于指针变量本身
int a = 100;
int b = 50;
int * const p = &a; //const修饰p的本身,所以一旦p被初始化之后,就不能通过p修改p的本身
//p = &b; //编译出错:error: assignment of read-only variable ‘p’
*p = 200; //正确的,因为const修饰p的本身,但是没有修饰p指向的内容,所以可以通过p修改p指向的内容
printf("a = %d\n",a);
*/
/* const修饰指针变量指向的内容
int a = 100;
int b = 50;
const int *p = &a; //const修饰p指向的内容,而不是修饰p
p = &b; //可以通过p修改p本身。
//*p = 200; //编译出错:error: assignment of read-only location ‘*p’
//不可以通过p修改p指向的内容。
b = 200; //可以,没有通过p修改p指向的内容
*/
return 0;
}
4、结论
int * const p; -> const修饰p的本身,一旦p被赋值了某个一个地址之后,就不能通过p修改p的地址。
int * const p = xxxx地址(正确) p = yyyy地址(错误)
-> 但是可以通过p修改p指向的内容。
*p 随便搞
const int *p; 等价 int const *p;
-> const修饰p指向的内容,p随意指向任何的地址
const int *p = xxxx地址(正确) p = yyyy地址(正确)
*p 出现错误
五、字符串函数
1、字符串在程序中如何保存使用?
char A[10] = "hello"; -> 将常量区"hello"拷贝到数组A内存空间。
char *p = "hello"; -> 将常量区"hello"首元素的地址保存在指针变量p中。
2、在linux下,有些关于字符串函数提供用户使用。
1)计算字符串实际长度 -> strlen()
2)比较两个字符串是否匹配 -> strcmp()
3)拷贝字符串到某段内存中 -> strcpy()
4)追加字符串 -> strcat()
六、计算字符串实际长度 -> 不包含'\0'在内 Ubuntu:man 3 strlen
NAME -> 函数的功能
strlen - calculate the length of a string -> 校对字符串长度
#include <string.h> -> 头文件
size_t strlen(const char *s); -> 函数原型
s: 需要计算的字符串的首元素的地址
返回值:字符的个数。
例子:
#include <stdio.h>
#include <string.h>
int main()
{
char A[100] = "helloworld";
char *p = "helloworld";
printf("sizeof(A) = %d\n",sizeof(A));//100
printf("sizeof(p) = %d\n",sizeof(p));//4
printf("strlen(A) = %d\n",strlen(A));//10
printf("strlen(p) = %d\n",strlen(p));//10
return 0;
}
结论: sizeof()计算空间大小,strlen()计算字符串的长度。
七、比较两个字符串是否匹配 -> strcmp()
1、与整型变量是否相等比较
int a = 200;
int b = 100;
if(a == b) -> 整型数据使用"=="来进行判断
2、比较两个字符串能不能用"=="?
char A[100] = "helloworld";
char *p = "helloworld";
if(A == p) -> 不可以,只能判断两个地址是否相等,这样对比是没有任何意义,只有对比内容才有意义。
3、 如何比较两个字符串? -> 只能使用strcmp() -> man 3 strcmp
NAME
strcmp, strncmp - compare two strings 比较两个字符串
#include <string.h>
int strcmp(const char *s1, const char *s2);
int strncmp(const char *s1, const char *s2, size_t n);
s1:需要进行比较的字符串1的地址
s2:需要进行比较的字符串2的地址
n: 只匹配前n个字节
返回值:
s1与s2匹配 -> 0
s1与s2不匹配 -> 非0
4、例子:
#include <stdio.h>
#include <string.h>
int main()
{
int ret;
char A[100] = "helloworld";
char *p = "hello";
ret = strncmp(A,p);
if(ret == 0)
{
printf("match!\n");
}
else{
printf("no match!\n");
}
return 0;
}
练习:有一张银行卡,密码是gec123456,请求用户输入密码,如果密码正确,则输出密码的长度,如果密码错误,则重新输入!如果输入的次数超过5次,则程序直接退出。
#include <stdio.h>
#include <string.h>
int main(int argc,char *argv[])
{
char passwd[20] = "gec123456"; //银行卡密码
char input_passwd[20] = {0}; //清空数组
char *p = input_passwd;
int count = 0;
while(count < 5)
{
scanf("%s",p);
if(strcmp(passwd,p) == 0)
{
printf("passwd length = %d\n",strlen(passwd));
break;
}
else{
count++;
continue;
}
}
return 0;
}
八、拷贝字符串到某段内存中 -> strcpy()
char A[10] = "hello";
char A[10] = {"hello"};
char A[10] = {'h','e','l','l','o'};
char A[10]; -> 如果定义没有初始化,则以后都不能整体初始化。
A[0] = 'h';
...
strcpy() -> 如果定义没有初始化,则以后还能使用strcpy()整体初始化。 -> man 3 strcpy
char A[10];
A = "hello" //错误
strcpy(A,"hello"); //正确
NAME
strcpy, strncpy - copy a string
SYNOPSIS
#include <string.h>
char *strcpy(char *dest, const char *src);
char *strncpy(char *dest, const char *src, size_t n);
dest:需要把字符串拷贝到的空间的起始地址,这个空间必须足够大。
src:需要拷贝的字符串的地址。
n: 只拷贝src前n个字节
返回值:
成功: 返回指向dest内存空间的地址
失败: NULL
#include <stdio.h>
#include <string.h>
int main()
{
char A[11] = "helloworld";
char *p = "abc";
int i;
for(i=0;i<11;i++)
{
printf("A[%d] = %c\n",i,A[i]);
}
strcpy(A,p);
for(i=0;i<11;i++)
{
printf("A[%d] = %c\n",i,A[i]);
}
printf("A = %s\n",A);
return 0;
}