一
指针 运算
两个指针之间的减法运算
前提:
两个指针必须指向同一个数组
注意:
指针之间是没有加法运算的
两个指针相加的话,可能会越界
如果p1-p 为正 p<p1 p1在高地址
负 p>p1 p在高地质
0 p==p1 p和p1都指向同一个地
二
指针和二维数组
使用数组名访问数组的元素
a[0] 行地址
a[1] 行地址
*(a+0) 第0行地址 等价与a[0]
*(a+1)
a[0]+0 列地址 a[0][0]地址
a[0]+1 a[0][1]
*(a[0]+1) 取值 a[0][1]的值
*(*(a+0)+1) a[0][1]的值
*(*(a+i)+j) a[i][j]的值
1)指向二维数组元素的指针(数组指针)
int *p = a; (不对)
2)二维的指针数组
int main()
{
int a[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};
int *p = a;//不可取
定义一个行指针,[4]表示这一行有四个元素
int (*p)[4];//二维数组的行指针
表示把二维数组名赋值给指针变量p
p = a;
a[0] 1,2,3,4
a[1] 5,6,7,8
a[2] 9,10,11,12
a数组名
*(a+0) //a[0]存放地址
*(a+1)
*(a+2)
for (int i=0; i<3; i++) {
for (int j=0; j<4; j++) {
//a[i] 每一个行的地址
//a[i]+j a[i][j]的地址
//*(a[i]+j) a[i][j]的元素的值
//在一维数组中 a[i]值,*(a+i)
//printf("%d ",*(a[i]+j));
//printf("%d ",*(*(a+i)+j));
printf("%d ",*(*(p+i)+j));
}
printf("\n");
}
return 0;
}
小练习
编写函数实现将一个数组中的内容拷贝到另外一个数组中。
include <stdio.h>
void string_copy(char a[],char b[],int len){
//定义两个数组指针
char *p = a;
char *p1 = b;
for (int i=0; i<len; i++) {
//a[i] b[i]
*(p+i) = *(p1+i);
}
}
int main()
{
char ch[6]="aaaaa";
char ch1[6]="bbbbb";
string_copy(ch, ch1, 6);
printf("%s\n",ch);
return 0;
}
三 字符串指针
*
字符串存储方式:
1)使用字符数组
char c1[]="adsfasdfas";
c1是数组的首地址,常量
c1 = "asdfasdfasdf";(错误的)
2)字符串指针
格式:char *指针变量名
1)字符串指针跟字符指针的区别
赋值区别
char c='a';
char *s=&c; //字符指针
char *s1="dafasdfdsa"; //字符串指针
2)字符数组和字符串指针的区别
1)字符数组存放在 内存的栈 区
2) 字符串指针指向的字符串存储在 内存常量区
char *str="asdfsdfas"; //str指针变量,把字符串的首地址存放到str中
char *str2; //指针变量
str2 = "adsfasdfasdf";
定义char类型的数组
存放到内存的栈区,可以读也可以写
char c[10]="itcast!";
c[5]='A';
str存放的是常量字符串的首地址
str可以重新指向一个新的字符串,但是字符串的内容不能改
char *str="itcast!";
printf("%s\n",str);
四 字符串数组
har ch[]="I need AV";
char ch1[]="I need AV";
字符串数组
1)二维的字符数组存储
char arr[3][20]={"dafasdf","I need AV","I need AV"};
for(int i=0;i<3;i++){
printf("%s\n",arr[i]);
}
存在栈区:arr[0] arr[1] arr[2] //可读可写
2)char型的一维指针数组
//数组中每一个元素都是指针
char *name[5]={"china","usa","hanguo","chaoxian","I need AV"}
for(int i=0;i<5;i++){
printf("%s",name[i]);
}
name[0] name[1] //常量区,不能改
字符串指针练习
输入5个国名并按字母顺序排列后输出。
char
*name[]={ "CHINA","AMERICA","AUSTRALIA","FRANCE","GERMAN"};
include <stdio.h>
#include <string.h>
void sort_string(char *name[],int len){
定义变量
int min;
循环,控制趟数
for (int i=0; i<len-1; i++) {
min = i; //假设一个最小值
for (int j=i+1; j<len; j++) {
//比较大小
if(strcmp(name[j], name[min])<0){
min = j;
}
}
//交换
if (i!=min) {
//交换的时在name数组中的顺序,原来指向谁,还指向谁
char *temp;
temp = name[i];
name[i] = name[min];
name[min] = temp;
}
}
}
int main()
{
char *name[]={ "CHINA","AMERICA","HANGUO","FRANCE","GERMAN"};
sort_string(name, 5);
for (int i=0; i<5; i++) {
printf("%s\n",name[i]);
}
return 0;
}
五 安全输入和输出函数
1)为什么说scanf和gets是不安全的
char ch[10];
//从键盘接收一个字符串
scanf("%s",ch); //如果输入的字符串有空格,scanf就认为输入结束了,空格之后的字符都不会被报存
gets(ch); //可以接收用户输入的字符中含有空格
//scanf和gets都有一个缺点:
用户输入多少东西,就帮你保存多少东西
aaaaaaaaaABBBBB
假设用户输入的长度>10 15 = 10存数组 5连续存了(不安全的)
puts() //输出到缓冲区
2)fgets() fputs() //安全的函数
char ch1[10];
9个字符+'\0' 安全的
fgets函数主要功能是从文件中读取数据到字符数组
格式:fgets(数组名,长度,stdin); stdin 表示标准的输入,从输入缓冲区获取数据
注意:
1)fgets() 读取'\n' 换行符 fgets获取的字符长度小与数组长度的时候,能看到
2) 如果输入的长度大于数组长度,会自动截断
3) if (ch[strlen(ch)-1]=='\n') ch[strlen(ch)-1]='\0';
fputs()//可以写入字符串到文件中
格式:fputs(数组名,stdout); //stdout表示输出到控制台
注意:fputs不能换行,puts可以自动换行
nt main(=)
{
char ch[5];
//长度
fgets(ch, sizeof(ch), stdin); //获取用户输入的内容,保存到ch中'
printf("%ld\n",strlen(ch));
if (ch[strlen(ch)-1]=='\n') ch[strlen(ch)-1]='\0';
//输出
//puts(ch);
fputs(ch, stdout); //输出到控制台
return 0;
}
六 const 函数
如何使用const
1)声明一个常量
*/
#include <stdio.h>
int main(int argc, const char * argv[])
{
1、修饰变量,可以让变量变成只读的(常量)
const int a = 10;
a = 10;
int *p;
p = (int *)&a;
*p = 5;
printf("%p\n",&a);
printf("%p\n",p);
printf("%d\n",a);
printf("%d\n",*p);
2、const修饰指针
int b=10,c=12;
1)const的作用是指针的指向可以改变,指针指向的变量的值不能改
const int *p=&b;
int const *p=&b;
p = &c;
*p = 10;
2)const的作用是,指针的指向不能改变,指针的指向的变量的值可以改变
int * const p1 = &b;
p1 = &c;
*p1 = 30;
3)此处的const表示,指针的指向和指向变量的值都不能改变
const int * const p2 = &b; //可以这样写
p2 = &c;
*p2 = 40;
技巧:
看const在*附近的位置
const 在*的左侧 值不能改变
const 在*的右侧 指向不能改变
const 在*的两侧 指向和值都不能改变
return 0;
}
|
|