如何利用指针操作数组
int ages[3] = {1, 3 , 5};
ages[0] = 998;
printf("ages[0] = %i\n", ages[0]);
int *p = ages; // int *p = &ages[0]; &ages[0] == ages
printf("p = %p\n", p);
printf("ages = %p\n", ages); // p == ages;
// 以为p指针中存储的值和ages中存储的值相同, 所以以前用ages的地方都可以使用p来替代
p[0] = 889;
printf("ages[0] = %i\n", p[0]);
for (int i = 0; i < 3; i++) {
printf("p%i] = %i\n", i, p[i]);
}
输出:
ages[0] = 998
p = 0x7ffeefbff60c
ages = 0x7ffeefbff60c
ages[0] = 889
p0] = 889
p1] = 3
p2] = 5
指针类型的两个用途: \
第一个用途, 取值的时候, 会根据指针类型所占用的字节去取出对应字节的数据 \
第二个用途, 用于做加法运算, 指针+1, 其实是加上指针类型所占用的长度 , 如果当前指针类型是int, 那么+1本质上是加上4个字节
int ages[3] = {1, 3 , 5};
int *p;
p = ages; // int *p = &ages[0];
printf("ages[0] = %i\n", ages[0]);
printf("*p = %i\n", *p);
printf("p = %p\n", p);
// p = &ages[1];
// 指针+1, 并不是真实的+1, 而是+4
// 指针类型的两个用途: \
第一个用途, 取值的时候, 会根据指针类型所占用的字节去取出对应字节的数据 \
第二个用途, 用于做加法运算, 指针+1, 其实是加上指针类型所占用的长度 , 如果当前指针类型是int, 那么+1本质上是加上4个字节
p = p + 1;
printf("p + 1 = %p\n", p);
printf("*p = %i\n", *p);
// p = &ages[2];
p = p + 1;
printf("p + 1 = %p\n", p);
printf("*p = %i\n", *p);
输出:
ages[0] = 1
*p = 1
p = 0x7ffeefbff60c
p + 1 = 0x7ffeefbff610
*p = 3
p + 1 = 0x7ffeefbff614
*p = 5
通过指针取数组元素:
int ages[3] = {1, 3 , 5};
int *p;
p = ages;
//printf("ages[0] = %i\n", *(p + 0));
//printf("ages[1] = %i\n", *(p + 1)); // p = p + 1; *p;
//printf("ages[2] = %i\n", *(p + 2));
for (int i = 0; i < 3; i++) {
// 指针+1, 是加上指针类型所占用的长度
printf("ages[%i] = %i\n", i, *(p + i));
}
输出:
ages[0] = 1
ages[1] = 3
ages[2] = 5
只要一个指针指向了数组, 那么访问数组就有3种方式:
1. : ages[0];//通过数组变量和索引访问
2. : p[0];//通过指针变量和索引访问
3. : *(p + 0);//通过指针变量计算访问数组元素
指针和字符串
使用字符数组保存字符串
char str[] = "lnj";
printf("str = %s\n", str);
str[0] = 'm';
printf("str = %s\n", str);
因为数组名就是数组的地址, 数组名保存的就是数组的第0个元素的地址,所以我们可以使用指针来保存字符串
通过指针保存一个字符串, 其实就是保存的字符串第0个元素的地址
char *str2 = "lmj";
printf("str2 = %s\n", str2);
通过数组保存字符串和通过指针保存字符串的区别
char *str2 = "lmj";
printf("str2 = %s\n", str2);
//// str2[0] = 'm';
// printf("str2 = %s\n", str2);
// 通过数组保存字符串和通过指针保存字符串的区别
// 如果通过数组来保存字符串, 那么字符串是一个变量 str 可以修改
// 如果通过指针来保存字符串, 那么字符串是一个常量 str2 不能修该
// 数组保存的字符串存储在内存的栈中, 而通过指针保存的字符串存储在常量区
// 存储在栈中的变量有一个特点, 当作用域结束系统会自动释放该变量
// 存储在常量区中的值有一个特点, 不会被释放, 而且多个相同的值对应的地址相同
char str3[] = "lnj";
// printf("str = %p\n", str);
printf("str3 = %p\n", str3);
char *str4 = "lmj";
printf("str2 = %p\n", str2);
printf("str4 = %p\n", str4);
输出
str2 = lmj
str3 = 0x7ffeefbff5e4
str2 = 0x100000f66
str4 = 0x100000f66
从输出可以看到str2和str4的地址相同,是同一个字符串常量。
小结:
保存字符串的两种方式:
char str[] = "lnj";
存储的位置: 栈
特点: 相同的字符串会重复的分配存储空间
字符串可以修改
char *str = "lnj"
存储的位置: 常量区
特点: 相同的字符串不会重复的分配存储空间
字符串不可以修改
注意: 用指针来保存字符串不可以被修改
指针没有初始化不能随便使用,所以数组变量和指针变量一样,未经初始化不能使用。
如何保存字符串数组
可以通过二维字符数组或者一维指针数组
char strs[4][20] =
{
"lnj",
"lmj",
"jjj",
"lk"
};
char *names[4] =
{
"lnj",
"lmj",
"jjj",
"lk"
};
for (int i = 0; i < 4; i++) {
printf("names[%i] = %s\n", i , names[i]);
}
看如下两个函数
char *name = demo();
printf("name = %s\n", name);
char *name2 = demo2();
printf("name2 = %s\n", name2);
char *demo2()
{
char name[]= "lnj";
return name;
}
char *demo()
{
char *name = "lnj";
return name;
}
demo表示的字符串保存着常量池中,demo2表示的字符串保存在demo2栈中,所以name2输出后是一端脏数据。
练习:实现字符串长度的函数
char *name = "lnj";
// size_t size = strlen(name);
int size =myStrlen3(name);
printf("size = %i\n", size);
int myStrlen3(char *str)
{
int count = 0;
// \0 ascii 0 // 0代表假 1真
while (*str++)count++;
return count;
}
指向函数的指针
函数也会占用一块存储空间
因为函数也会占用一块存储空间所以函数也由自己的地址
函数的地址保存在函数名中
函数名就是函数的地址 == 数组名就是数组的地址
指向函数的指针的定义格式
void (*funtionP) ();
* : 代表是一个指针
funtionP : 代表指针变量的名称, 区分
(*funtionP) : 代表将来指向一个函数
void : 代表将来指向的函数没有返回值
() : 代表将来指向的函数没有参数
void (*funtionP) ();
funtionP = test; // 注意: 千万不能写成test()
test(); // 0x100000f00();
(*funtionP)(); // 0x100000f00()
// test == funtionP
funtionP();
#include <stdio.h>
void test()
{
printf("哥被执行了\n");
}
int getAge()
{
return 30;
}
void sum(int v1, int v2)
{
int res = v1 + v2;
printf("res = %i\n", res);
}
int sum2(int v1 , int v2)
{
int res = v1 + v2;
return res;
}
int main(int argc, const char * argv[]) {
int (*ageP)();
ageP = getAge;
printf("age = %i\n", ageP());
// void (*sumP)(int v1, int v2);
void (*sumP)(int, int);
sumP = sum;
sumP(10, 20);
int (*sumP2)(int , int);
sumP2 = sum2;
printf("sum = %i\n", sumP2(10, 20));
return 0;
}
指向函数的指针的应用
可以用来写回调函数
#include <stdio.h>
int sum(int v1, int v2)
{
return v1 + v2;
}
int minus(int v1, int v2)
{
return v1 - v2;
}
// 让demo接受一个指向函数的指针
// 以后我们只需要给demo函数传递对应的指针, 那么函数内部就可以调用不同的函数
int demo(int v1, int v2)
{
return minus(v1, v2);
}
int demo2(int v1, int v2)
{
return sum(v1, v2);
}
int demo3(int v1, int v2, int (*p)(int, int))
{
return p(v1, v2);
}
int main(int argc, const char * argv[]) {
// 定义一个方法, 给你两个数, 用户要求你做加法你就做加法, 用户要求你做减法, 那你就做减法
// printf("sum = %i\n", sum(10, 20));
// printf("minus = %i\n", minus(20, 10));
// printf("minus = %i\n", demo(20 , 10));
// printf("sum = %i\n", demo2(20 , 10));
printf("mins = %i\n", demo3(20, 10, minus));
printf("sum = %i\n", demo3(20, 10, sum));
return 0;
}
练习2、将用户输入的字符串,首字母大写
#include <stdio.h>
char upper(char value);
void upperCase(char *p);
//void ts(char *temp);
void ts(char *temp, void (*funtionP)(char *));
int main(int argc, const char * argv[]) {
// 需求: 要求用户输入一段英文, 将用户输入的英文单词所有的首字母大写
// hello world --> Hello World
// 1.接收用户输入的字符串
// 2.遍历字符串, 判断当前字符是否是空格, 如果是空格就将下一个字符转换为大写
// 1.先实现接受字符串
// 2.再实现字母的大小写转换
// 3.再实现替换字符串中的单词首字符
/*
printf("请输入一句英文, 单词之间用空格隔开\n");
// char *str;
char str[100];
// scanf("%s", str);
gets(str);
printf("str = %s", str);
*/
/*
char c = 'a'; // + - 1
// printf("c = %c\n", upper(c));
upperCase(&c);
// *p == c
printf("c = %c\n", c);
*/
// 1.接收用户输入的数据
printf("请输入一句英文, 单词之间用空格隔开\n");
char str[100];
gets(str);
// 注意: 数组名称不能做+1操作, 只有指针才可以
printf("str = %s\n", str);
/*
char *temp = str;
// 2.遍历字符串
upperCase(temp);
// temp == &str[0]
while (*temp != '\0') { // h e l l o 空格 w
// 2.1取出当前的字符, 判断是否等于 空格, 如果等于空格就需要将下一个字符转换为大写
if ((*temp) == ' ') {
// 2.2将下一个字符转换为大写
upperCase(++temp); // temp == &str[6]; == w
}else
{
temp++; // temp == &str[7];
}
}
*/
ts(str, upperCase);
printf("str = %s", str);
return 0;
}
void ts(char *temp, void (*funtionP)(char *))
{
// 1.不管三七二十一先将第一个字母转换为大写
upperCase(temp);
// temp == &str[0]
while (*temp != '\0') { // h e l l o 空格 w
// 2.1取出当前的字符, 判断是否等于 空格, 如果等于空格就需要将下一个字符转换为大写
if ((*temp) == ' ') {
// 2.2将下一个字符转换为大写
// upperCase(++temp); // temp == &str[6]; == w
funtionP(++temp);
}else
{
temp++; // temp == &str[7];
}
}
}
void upperCase(char *p)
{
// 1.判断是否是小写字母
if (*p >= 'a' && *p <= 'z') {
// 2.将小写字母转换为大写字母
*p = *p - ('a' - 'A'); // 32 小写的ascii大于大写
}
}
char upper(char value)
{
// 1.判断是否是小写字母
if (value >= 'a' && value <= 'z') {
// 2.将小写字母转换为大写字母
value = value - ('a' - 'A'); // 32 小写的ascii大于大写
}
return value;
}