第十八课 c语言11 字符串与数组
这一节课b站缺失了,参考一下大佬的笔记学习,链接:https://blog.csdn.net/Edimade/article/details/124446533?spm=1001.2014.3001.5502
1.字符数组
:::info
char arr[10] = {'A','B','C','D','E','F'}; //编译器默认在结尾添加0x00
char arr[3] = {'A','B','C'}; //但是如果没有留出'\0'的空间,编译器就不会自动添加
char arr2[6] = {'A','B','C','D','E',0}; //注意区分这里的0不是'0'
char buffer[100] = ""; //定义了一个空字符串,字符串中每个字节默认初始为0x00
char buffer[] = ""; //这个数组长度只有1,且默认初始为0x00
:::
总结:
定义字符数组来表示字符串时,一定要在结尾给'\0',我们可以手动添加,也可以不添加让编译器自己自动帮我们在结尾处添加'\0',但是一定要注意如果让编译器添加的话,要把字符数组的宽度的长度设置好,一定要预留空间给'\0'
2.字符串
也是字符数组的一种,字符串就会经常在常量区
:::info
char names[] = "ABCDE";
//可以省略数组大小,但是此时的数组大小应该6,因为编译器会自动在末尾加0x00
char* p = "ABCDE";
//这个是将常量区中存储ABCDE字符串的首地址赋给p,此时p的长度是4字节,常量区的字符
:::
char arr1[6] = {'A','B','C','D','E','\0'};
char arr2[6] = {'A','B','C','D','E',0}; //注意区分这里的0不是'0'
char arr3[6] = {'A','B','C','D','E'}; //只要比5大,数组的长度随便
char names[] = "ABCDE";
printf("%s\n",arr1);
printf("%s\n",arr2);
printf("%s",names);
char word[8];
scanf("%7s", word);//最多读7个字符
3.常量区
前面有一张内存图,现在来说说之前没讲到的全局变量和常量区
这是海哥上课的例子代码
char* x = "china";
//x中存的就是存储在常量区的china字符串的首地址,x指针型变量直接指向常量区中的存储china字符串的首地址
char y[] = "china";
//这里也是常量区中的china字符串,但是与指针不同的是,这里会将字符串值复制一份到给y字符数组变量分配的内存中(栈)
void Func(){
y[1] = 'A'; //可以修改
*(x + 1) = 'A'; //无法修改
x = "ABC"; //可以修改,相当于重新指向ABC这个新的地址
}
先从反汇编层面看看
可以看到x变量存储的直接就是china常量区的地址,而y存储的是china拷贝过来的值而且放到堆栈里,所以x无法修改但是y数组可以
总结:
- *(x+1) = 'A'是尝试去修改常量区china字符串的值,因为常量区可读不可写,所以修改失败
- y数组由于修改的是拷贝过来的堆栈区,所以可以修改成功
- x = "ABC";也可以修改成功,相当于重新指向ABC这个新的地址
作业一
**错误示范 **
我们要用int类型搜索内容,一次搜四个字节,但是int类型+1后下一次搜索就是每隔四个字节搜一次,而我们现在需要用int类型每隔一个字节搜一次,所以出现下面的错误代码
#include "stdafx.h"
char data[100] = { //全局变量
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x07,0x09,
0x00,0x20,0x10,0x03,0x03,0x0C,0x00,0x00,0x44,0x00,
0x00,0x33,0x00,0x47,0x0C,0x0E,0x00,0x0D,0x00,0x11,
0x00,0x00,0x00,0x02,0x64,0x00,0x00,0x00,0xAA,0x00,
0x00,0x00,0x64,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x02,0x00,0x74,0x0F,0x41,0x00,0x00,0x00,
0x01,0x00,0x00,0x00,0x05,0x00,0x00,0x00,0x0A,0x00,
0x00,0x02,0x74,0x0F,0x41,0x00,0x06,0x08,0x00,0x00,
0x00,0x00,0x00,0x64,0x00,0x0F,0x00,0x00,0x0D,0x00,
0x00,0x00,0x23,0x00,0x00,0x64,0x00,0x00,0x64,0x00
};
int length = sizeof(data) / sizeof(data[0]);
void find_blood(int num,int width){ //输入要查找的数值,查找宽度
if(width == 1){
for(int i = 0;i < length - width + 1;i++){
if(*(data + i) == num)
printf("add:%x num:%d\n",data + i,*(data + i));
}
}else if(width == 2){
for(int i = 0;i < length - width + 1;i++){
short* p = (short*)(data + i); //直接使用char* data++,但是每次判断前把当前地址转型赋给一个新short* p即可,不需要上面那么麻烦
if(*p == num){
printf("add:%x num:%d\n",p,*p);
}
}
}else if(width == 4){
for(int i = 0;i < length - width + 1;i++){
int* p = (int*)(data + i);
if(*p == num){
printf("add:%x num:%d\n",p,*p);
}
}
}else{
printf("宽度不符合规定");
}
}
int main(int argc, char* argv[])
{
printf("%x\n",data);
find_blood(256,2);
getchar();
return 0;
}
这把借鉴作业了
还有个改进前的思路也可以看看
void findblood(int size){
if(size == 2){ //数值类型为short时,即2字节
short* temp = (short*)blood; //因为每次定位到一个地址,要查的数是从这往后2字节,所以先强转
for(int i = 0;i < 100 - size + 1;i++){
if(*(temp) == 100){ //因为temp是short*类型,所以取的地址宽度为2字节
printf("%x\t%d\n",temp,*temp);
}
char* temp2 = (char*)temp; //因为要一个一个地址挨着找,所以先转换成char*类型,如果拿 short*的temp直接++,那么结果就是源temp中地址+2*1,就不是依次逐个地址找了,就是跳了一个
temp2++; //那么char*变量在++时,结果为:地址 + char宽度,即下一个地址
temp = (short*)temp2;//然后再将下一个地址的值赋给temp,下次比较就是从temp往后数2字节是否 是0x0064
}
}else if(size == 4){ //数值类型为int时,即4字节
int* temp = (int*)blood;
for(int i = 0;i < 100 - size + 1;i++){ //因为如果4字节为单位,则查到倒数第4个地址就是最后 一个地址了,就不用继续我往后查了
if(*(temp) == 100){
printf("%x\t%d\n",temp,*temp);
}
char* temp2 = (char*)temp;
temp2++;
temp = (int*)temp2;
}
作业二
1、2、
3、
注意:x数组需要给大一点的空间,否则在y赋值过去后,没有足够的空间来容纳两个字符串的拼接结果,可能会导致超出数组界限的访问,进而引发未定义的行为。
记录一下自己第一次打印调试出错误
虽然我感觉我理解错题意了下面代码,不过就这样吧
char datas[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x07, 0x09,
0x00, 0x20, 0x10, 0x03, 0x03, 0x0C, 0x00, 0x00, 0x44, 0x00,
0x00, 0x33, 0x00, 0x47, 0x0C, 0x0E, 0x00, 0x0D, 0x00, 0x11,
0x00, 0x00, 0x00, 0x02, 0x64, 0x00, 0x00, 0x00, 0xAA, 0x00,
0x00, 0x00, 0x64, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x02, 0x00, 0x74, 0x0F, 0x41, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x0A, 0x00,
0x00, 0x02, 0x57, 0x4F, 0x57, 0x00, 0x06, 0x08, 0x00, 0x00,
0x00, 0x00, 0x00, 0x64, 0x00, 0x0F, 0x00, 0x00, 0x0D, 0x00,
0x00, 0x00, 0x23, 0x00, 0x00, 0x64, 0x00, 0x00, 0x64, 0x00 };
int length = sizeof(datas) / sizeof(datas[0]);
void FindNameAddr(char* pData, char* pName,int width)
{
if (width == 1)
{
for (int i = 0; i < length - width + 1; i++)
{
if (*(pData+i) == *pName)
{
if(*(pData + i +1) == *(pName+1))
if (*(pData + i + 2) == *(pName + 2))
printf("addr:%x\n",pData+i);
}
}
}
else if (width == 2)
{
for (int i = 0; i < length - width + 1; i++)
{
short* ret = (short*)(pData+i);
if (*ret == *((short*)pName))
{
if(*(ret+1) == *((short*)pName+1))
printf("addr:%x\n", pData + i);
}
}
}
else if (width == 4)
{
for (int i = 0; i < length - width + 1; i++)
{
int* ret = (int*)(pData + i);
if (*ret == *((int*)pName))
{
printf("addr:%x\n", pData + i);
}
}
}
else
{
printf("宽度输入错误");
}
}
int main()
{
FindNameAddr(datas, (char*)"WOW", 4);
}
第十九课 c语言12 指针数组 结构体指针
1.指针数组
赋值
常见的指针数组
2.结构体指针
赋值取值
思维不被限制,结构体指针指向的地址不是结构体也可以,只是他的内存宽度对应不上,但是强转后编译器能编译通过,不管指向的地址后面是什么都打印出来就完事了
作业
1、