🎁毫无疑问,指针是c语言中一座大山,🎁
😄但是咋们只要迎难而上,坚持努力,😄🔥迟早会将这大山踩在脚下。🔥
一.指针(中)
1.1字符串与指针
c语言里面是没有字符串这么一个类型的,c语言是通过一个叫 char *的字符指针取实现这个字符串的,字符串:一坨的字符串在一起就是字符串,c语言里面字符串是以 \0这个字符结尾的,你的字符串不管有多长,碰到第一个 \0 就结束了,c语言里面用"“来表示一个字符串,”"引起来的一些字符的末尾默认带一个 \0,“abcdefg” :实际上 “abcdefg\0”,“abcde\0fg”:这个字符串实际上的处理是以 "abcde"来算的
在c语言里面 “abcdefg”:c语言处理这个字符串的行为:,在.rodata这个空间开辟 8个字节 abcdefg\0存储这个字符串,然后将存放a的内存的地址返回回来,typeof(“abcdefg”) -> const char *,因此我可以直接用一个字符指针取接受这个字符串的地址
const char * p = “abcdefg”;
char c = *p;//‘a’
char d = p[1] -> *(p + 1);‘b’
p[2] = ‘f’;//不行 错误的 error的 p是一个const只读的 因此不能写
c语言里面对const这个玩意儿审核不是很严
这就意味着我可以用一个char * 去保存这个地址
char * q = "abcdefg";
char c = *q;
q[1] = 'k';//不行 错误的 error的 q指向的内存空间是只读的
char d = 'L';
q = &d;//可以的 q本身自己的内存是可写的 因此没有毛病
*q = 'P';//可以 q这个时候指向了d这个可读可写的内存空间
q[1] = 'M';//不可以 q[1] -> *(q + 1) ->往后面走了一个字节
//对于我们这些代码来说你是不知道这个内存是否是能用的
//因此会内存非法访问,不行
char str[] = "abcdefg";//可以
char c = *str;//可以 'a'
str[1] = 'K';//完全没有问题
sizeof(str) == 8
char str[] = "abcdefg";//这个代码不是接收这个字符串的首地址
//利用这个字符串里面的字符去初始化这个数组
字符串的长度:字符串的长度为第一个字符到第一个\0中间的所有的字符串的数量
不算\0,注意:必须找到第一个\0 不然这个字符串就没有完
char str[7] = "abcdefg";
sizeof(str) == 7
str代表的这个字符串的长度为多少?
strlen(str) == 根据这个代码,算出来应该是7
但是根据我们的内存的访问来说,它会造成内存的非法访问
这个str里面没有 \0 所以不允许
用数组去保存这个字符串一定要注意:你的内存要开的足够大
利用内存的原则能节约就节约
不要忘记最后的\0
strlen这个函数是求字符串的长度,不包含这个 \0
请将strlen这个函数完成
int mystrlen(const char * str)
{
int size = 0;//字符串的长度
while(*str)//一个个数,数到第一个 \0
{
size++;
str++;
}
return size;
}
%s ->输入输出字符串
char buf[128] = {0};
scanf(“%s”,buf);
printf(“%s\n”,buf);
字符串之间不能比较大小,不能直接赋值,不能直接判断相等…
char * p = "abcdefg";
char * q = "abcdef";
if(q == p)//可以 但是这不是比较两个字符串 是看q和p这两个地址是否相等
{
}
q = p;//可以 将p里面保存的一个地址赋值给q
char str[64] = "abcdefg";
//str = q;//不可以 str本身是只读的,不能被赋值
//q = str;//可以 将str代表的地址赋值给q
我现在希望将q代表这个字符串里面的所有的字符弄到str里面去
请问应该怎么实现??
只能一个个的字符去赋值
请完成mystrcpy这个函数
//成功返回0 失败返回-1
int mystrcpy(char * to,const char * from)
{
if(!to || !from)//他们两个不能有一个空指针
return -1;
//请完成这个copy操作 注意 \0也要复制
while(*from)//到\0退出
{
*to = *from;
to++;
from++;
}
//最后的那个\0还没有复制过去
*to = 0;//*to = '\0';
return 0;
}
判断两个字符串是否完全一样?
到第一个碰到\0的为止,最后的\0也要判断
"abcdefg"
"abcde"这两个字符串不同
"abcde\0fg"
"abcde"
如果完全一样返回0
不完全一样返回非0
mystrcmp函数
int mystrcmp(const char * str1,const char * str2)
{
if(!str1 || !str2)//他们两个不能有一个空指针
return -1;
while(*str1 == *str2)//这里是没有判断两个人是否等于 \0
{
//碰到第一个\0 这个循环都没有退出
if(*str1 == 0)//这个时候 str2也是\0
{
return 0;
}
str1++;
str2++;
}
//只要退出这个循环,那么他们就不相同了
return *str1 - *str2;
}
完成字符串连接函数
mystrcat
int mystrcat(char * str1,const char *str2)
{
//此函数的功能为 将str2连接到str1的后面去
if(!str1 || !str2)//他们两个不能有一个空指针
return -1;
str1 += mystrlen(str1);//让str1指向它后面的那个\0
//然后将str2复制到str1那里去就可以了
mystrcpy(str1,str2);
return 0;
}
c语言是不会做边界检查的,你越界了它也会继续做,直到操作系统将你干掉这种情况一般都会报段错误。
1.2数组指针与指针数组
1.2.1数组指针:表示是指向一个数组的指针
我需要用一个指针指向一个数组,那么我们应该要怎么办
int a[5] = {1,2,3,4,5};
//指向这个数组跟指向数组的第一个元素是有很大的区别的
//指向数组的第一个元素,这个指针++只会往后面挪动一个元素
//而指向这个数组的指针++,它是跳过整个数组
我们要定义一个指针指向这个a数组
typeof(&a) p = &a; -> typeof(a) * p; int[5] *p = &a;
int[5] *p = &a;//祖师爷说这么写很不爽 [5]要到后面去 不能这么写
#define hehe int *
int *p[5]; ->hehe p[5];->它是以hehe类型定义出来5个元素的一维数组
-> 还原 int * p[5] ->它是以int *类型定义出来5个元素的一维数组
因此指向数组的这个指针不能是一个一维数组
因此 *不能跟int走 它要跟 p走
因此指向这个数组的指针的定义:
int (*p)[5] = &a;//这个玩意儿我们就叫数组指针
->我们在使用的时候 (*p)[1] -> a[1]
上面的这个玩意儿是不是就是一个二维数组的指针
int b[3][4];
typeof(b) p = b;
int[4] * p = b;
int (*p)[4] = b;
在使用的时候p就直接可以像b一样使用
(*p)[1] -> (*(p + 0))[1] ->p[0][1]
#include <stdio.h>
//传二维数组
void func(int (*p)[4],int n)
{
printf("%d\n",p[2][2]);
}
//更多的时候我们可能都是按照一维数组弄的
void func1(int *p,int n)//我们为什么要传过来这个n
//这个函数里面是不知道这个数组有多大的
//我需要你告诉我 有多大 因此我要把元素个数传进来
{
for(int i = 0;i < n;i++)
printf("%d\t",p[i]);
printf("\n");
}
int main()
{
int a[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
func(a,3);
func1((int *)a,sizeof(a) / sizeof(a[0][0]));
return 0;
}
int b;
我想定义一个指针指向b
typeof(&b) q = &b;//typeof(b) * q = &b; -> int * q = &b;
1.2.2指针数组:这个数组里面的元素都是一个指针
int * a[4];//定义了a这个4个元素的数组
//里面所有的元素都是一个int *
//a[0]保存了一个地址......
int b[3][4];
//我要定义一个指针指向这个数组
int (*p)[4] = b;//数组指针
我用一个指针数组将这个二维数组里面的元素全部指向
我现在可以使用a这个数组将b里面的元素全部访问到,请问我的a应该怎么处理,
我只需要这个a数组将b的每一行首地址都保存下来就可以了
a[0] = b[0];
a[1] = b[1];
a[2] = b[2];
//a = b;//明显不行 a是一个数组的名字,不能改
现在我想通过a访问b[1][2]
a[1][2]
*(a[1] + 2)
*(*(a + 1) + 2)
int main()
{
char * p[] = {
“hehe”,//.rodata
“sb250”,
“123456”,
“penglei”,
“zhangfei”
};
sizeof(p) = (4 * 5)或者为(8 * 5);
//typeof("hehe"); ->char *
}
练习:
我需要找到一个特定的名字,如果有返回它的下标,没有返回没有找到
这个特定的名字用 %s进行输入
scanf(“%s”,buf);//这个buf需要开的足够大
找到固定什么字符串开头的那个下标,将找到的这个字符串用一个内存重新保存
#include <stdio.h>
#include <string.h>
//失败返回-1 成功返回找到的下标
int zhaoquanming(char *p[],int n,char * who)
{
int i;
for(i = 0;i < n;i++)
{
//比较两个字符串是否相同
if(!strcmp(p[i],who))
{
//找到了 将它的下标返回
return i;
}
}
return -1;
}
int zhaokaitou(char *p[],int n,char * who)
{
//找到了返回下标
//没有找到 打印没有,然后返回-1
//我只需要找到前面的几个字节
int count = strlen(who);//求得字符串的长度
int i;
for(i = 0;i < n;i++)
{
//比较两个字符串前面count个字节是否相同
if(!strncmp(p[i],who,count))
{
//找到了 将它的下标返回
return i;
}
}
return -1;
}
int main()
{
char * p[] = {
"hehe",//.rodata
"sb250",
"123456",
"penglei",
"zhangfei"
};
printf("找全名 %s :下标为 %d\n","penglei",zhaoquanming(p,sizeof(p) / sizeof(p[0]),"penglei"));
int n = zhaokaitou(p,sizeof(p) / sizeof(p[0]),"zhang");
printf("找开头 %s :下标为 %d\n","zhang",n);
char buf[128] = {0};//将找到的这个字符串弄到buf里面去 将buf打印出来
//通过下标找到这个字符串 将n下标代表的字符串弄到buf里面去
strncpy(buf,p[n],127);//最后的一个字节我要让它一定是 \0
printf("buf = %s\n",buf);
char name[128] = "你好";
//将上面的buf 接到name的“前面”去
//buf是为了保存我们有用的那个字符串 因此里面的内容这里应该不要动
char cpbuf[128] = {0};
// 1 strcpy(cpbuf,buf) 2 strcat(cpbuf,name); 3 strcpy(name,cpbuf)
snprintf(cpbuf,127,"%s%s",buf,name);
strcpy(name,cpbuf);
printf("name = %s\n",name);
}
这两个函数用法跟printf一样 都是格式化的输出
int sprintf(char *str, const char *format, …);
int snprintf(char *str, size_t size, const char *format, …);
printf:固定往终端上面输出
sprintf:往str内存里面输出
str可能会内存越界
因此snprintf这个函数就是为了解决上面bug的
最多输出 size个字节
char *
char buf[]
看到这么一些玩意儿之后你就要想到用字符串处理函数***********
练习:
我们的字符串有这些形式,“123”,“345”…,这种我们叫数字字符串,这些数字字符串是不能直接使用 + - …直接去操作的
“123” + “345” = 468;
“123” -> 转变成123这个数字
int atoi(char * str)
{
//数字0 和 字符0
0 == '0' - '0';
1 == '1' - '0';
int sum = 0;
while(*str)
{
sum = sum * 10 + *str - '0';
str++;
}
return sum;
}
int main()
{
int sum = atio("123") + atio("345") -> sum的结果为468
printf("%d\n",sum);
}
NAME
atoi, atol, atoll - convert a string to an integer
将一个数字字符串转换成一个整数
SYNOPSIS
#include <stdlib.h>
int atoi(const char *nptr);
nptr:你要转换的字符串
返回值:你转换好了的字符串通过这个返回值返回给你