1.指针的步长
void test()
{
//指针步长:指针变量+1,要向后跳多少字节
char* p1 = NULL;
printf("%d\n", p1);
printf("%d\n", p1 + 1);
printf("----------------------------------\n");
int* p2 = NULL;
printf("%d\n", p2);
printf("%d\n", p2 + 1);
//指针步长由指针类型决定
}
指针的类型不单单决定指针的步长,还决定解引用时从给定地址开始取类型大小的字节数。
void test()
{
char buf[1024] = { 0 };
int a = 100;
//memcpy表示拷贝内存,变量a为整数型,buf为字符串,所以不能直接使用字符串拷贝strcpy
memcpy(buf + 1, &a, sizeof(int));//4个字节的数据存放在buf+1的后4位的位置
char* p3 = buf;//将指针指向buf首地址
/*p3+1表示a的首地址,因为p3为char类型,所以加一个*表示取首地址后一个字节的内容
再加int*表示取4个字节*/
printf("*(int *)(p3+1) = %d\n", *(int*)(p3 + 1));
}
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stddef.h>//可计算偏移量
struct Person
{
int a;
char b;
char buf[64];
int d;
};
void test()
{
struct Person p = { 10,'a',"hello world!",100 };
char b;
//b相对于结构体首地址的偏移量
printf("a off = %d\n", offsetof(struct Person, b));
//计算100的偏移量:先对p取地址,然后强制转换成char类型以便控制每字节的偏移量
//取结构体首地址后加上偏移量就为待求变量的首地址,此时再加上int*表示取后4个字节
printf("d = %d\n", *(int*)((char*)&p + offsetof(struct Person, d)));
}
2.指针的间接赋值
void changeValue(int* p)
{
//指针和普通变量相似,指针也有内存即地址,也保存着变量
//唯一不同在于保存的值为地址
*p = 100;
}
void test()
{
int a = 10;
changeValue(&a);//changeValue(a)表示仅把a的值传过去
printf("%d\n", a);
}
先拿到a的固定地址,然后加上int表示把该地址当成指针,计算步长,最后表示解引用即得到a的内存空间
void changePointer(int **val)
{
//**val表示内存空间,*val表示该空间内存取的值
*val = 0x008;
}
void test()
{
int* p = NULL;
//&取地址后会加一层指针等级,比如整型a取地址后为int*,*p取地址后为二级指针**p
changePointer(&p);
printf("p = %x\n", p);
}
3.指针做形参的输入特性
void printString(const char* str)
{
printf("打印内容 : %s\n", str+2);
}
void test()
{
//指针的输入特性,主调函数分配内存,被调函数使用内存
//堆上分配内存
char* s = malloc(sizeof(char) * 100);
memset(s, 0, 100);
strcpy(s, "hello world!");
printString(s);//只需要传值,不需要取地址,&代表将要改变s的地址指向另一块空间
}
void printStringArray(const char** arr, int len)
{
//arr为char*类型,arr[0] == *(arr+0)
for (int i = 0; i < len; ++i)
{
printf("%s\n", arr[i]);
}
}
void test()
{
//栈上分配
//指针数组,每一个元素都是char*类型的指针
//数组名做形参会退化为指向数组首元素的指针
char* strs[] = {
"aaaaa",
"bbbbb",
"ccccc",
"ddddd",
};
int len = sizeof(strs) / sizeof(strs[0]);
printStringArray(strs, len);
}
4.指针做形参的输出特性
void allocateSpace(char **temp)
{
char* p = malloc(100);
memset(p, 0, 100);
strcpy(p, "hello world!");
//指针的间接赋值
*temp = p;
}
void test()
{
//输出特性 被调函数分配内存,主调函数使用内存
char* p = NULL;
allocateSpace(&p);
printf("p = %s\n", p);
if (p != NULL)
{
free(p);
p = NULL;
}
}
5.字符串拷贝
字符串是以0或’\0’结尾的字符数组,数字0和字符’\0’等价
void copyString01(char* dst, char* source)
{
int len = strlen(source);
for (int i = 0; i < len; i++)
{
dst[i] = source[i];
}
dst[len] = '\0';
}
void test()
{
char* source = "hello world!";
//char buf[1024] = { 0 };//如果不初始化,需要在拷贝的数组最后加上'\0'
char buf[1024];
copyString01(buf, source);
printf("%s\n", buf);
}
void copyString02(char* dst, const char* source)
{
//指针方式
while (*source != '\0')
{
*dst = *source;
++dst;
++source;
}
*dst = '\0';
}
void test()
{
char* source = "hello world!";
//char buf[1024] = { 0 };//如果不初始化,需要在拷贝的数组最后加上'\0'
char buf[1024];
copyString02(buf, source);
printf("%s\n", buf);
}
void copyString03(char* dst, const char* source)
{
while (*dst++ = *source++);
}
void test()
{
char* source = "hello world!";
//char buf[1024] = { 0 };//如果不初始化,需要在拷贝的数组最后加上'\0'
char buf[1024];
copyString03(buf, source);
printf("%s\n", buf);
}
6.字符串反转
void reverseString(char* str)
{
if (NULL == str)
{
return;
}
int len = strlen(str);int start = 0;int end = len-1;
while (start < end)
{
char temp = str[start];
str[start] = str[end];
str[end] = temp;
++start; --end;
}
}
void test()
{
char p[] = "abc";
reverseString(p);
printf("p = %s", p);
}
void reverseString(char* str)
{
//指针版
if (NULL == str)
{
return;
}
int len = strlen(str);
char* pStart = str;//首地址
char* pEnd = str + len - 1;
while (pStart < pEnd)
{
char temp = *pStart;
*pStart = *pEnd;
*pEnd = temp;
pStart++; pEnd--;
}
}
7.字符串的格式化—sprintf
void test()
{
//1. 格式化字符串
char buf[1024] = { 0 };
sprintf(buf, "hello %s!", "Trump");
printf(buf);
//2. 拼接字符串
char *s1 = "hello";
char *s2 = "world!";
memset(buf, 0,1024);
sprintf(buf, "%s %s", s1, s2);
printf("\n%s", buf);
//3. 数字转换成字符串
int num = 666;
memset(buf, 0, 1024);
sprintf(buf, "%d", num);
printf("\n%s", buf);
//4. 开辟5个char*的内存空间,并分别命名为name i
char** p = malloc(sizeof(char*) * 5);
for (int i = 0; i < 5; ++i)
{
p[i] = malloc(64);
memset(p[i], 0, 64);
sprintf(p[i], "name_%d", i + 1);
}
printf("\n");
for (int i = 0; i < 5; ++i)
{
printf("%s\n", p[i]);
}
//释放内存
for (int i = 0; i < 5; ++i)
{
if (p[i] != NULL)
{
free(p[i]);
p[i] = NULL;
}
}
if (p != NULL)
{
free(p);
p = NULL;
}
//5. 格式化数字八进制、十六进制
memset(buf, 0, 1024);
sprintf(buf, "%o", num);
printf("八进制:%o", num);
memset(buf, 0, 1024);
sprintf(buf, "%x", num);
printf("\n十六进制:%x", num);
}