指针和函数:
栈 帧:
当函数调用时,系统会在 stack 空间上申请一块内存区域,用来供函数调用,主要存放 形参 和 局部变量(定义在函数内部)。
当函数调用结束,这块内存区域自动被释放(消失)。
传值和传址:
传值:
函数调用期间,实参将自己的值,拷贝一份给形参。
示例
//函数声明
int swap(int a, int b);
int main(void)
{
int m = 37;
int n = 35;
printf("before m =%d n =%d\n", m, n);
//函数调用;
swap(m, n); //实参;
printf("after m = %d n = %d\n", m, n);
system("pause");
return EXIT_SUCCESS;
}
//函数定义
int swap(int a, int b) // a,b 形参
{
int temp = 0;
temp = a;
a = b;
b = temp;
return 0;
}
传址:
函数调用期间,实参将地址值,拷贝一份给形参。 【重点】
(地址值 --》 在swap函数栈帧内部,修改了main函数栈帧内部的局部变量值)
指针做函数参数:
int swap2(int *a, int *b);
int swap2(char *a, char *b);
调用时,传有效的地址值。
示例
//函数声明
int swap(int a, int b);
int swap2(int* a, int* b);
int main(void)
{
int m = 37;
int n = 35;
printf("before m =%d n =%d\n", m, n);
//函数调用;
swap(m, n); //实参;
printf("after swap m = %d n = %d\n", m, n);
swap2(&m, &n);//实参:取地址
printf("after swap2 m = %d n = %d\n", m, n);
system("pause");
return EXIT_SUCCESS;
}
//函数定义:传值
int swap(int a, int b) // a,b 形参
{
int temp = 0;
temp = a;
a = b;
b = temp;
return 0;
}
//函数定义:传址
int swap2(int* a, int* b)
{
int temp = 0;
temp = *a;
*a = *b;
*b = temp;
return 0;
}
数组做函数参数:
void BubbleSort(int arr[10]) == void BubbleSort(int arr[]) == void BubbleSort(int *arr)
传递不再是整个数组,而是数组的首地址(一个指针)。
所以,当整型数组做函数参数时,我们通常在函数定义中,封装2个参数。一个表数组首地址,一个表元素个数。
指针做函数返回值:
int *test_func(int a, int b);
指针做函数返回值,不能返回【局部变量的地址值】。
数组做函数返回值:
C语言,不允许!!!! 只能写成指针形式。
示例1:数组做函数参数
void BubbleSort(int arr[]) //把数组封装为函数形参相当于 void BubbleSort(int *arr)
{
int n = sizeof(arr) / sizeof(arr[0]);
printf("n = %d\n", n); //封装后值变了
printf("sizeof(arr) = %d\n", sizeof(arr)); // 数组首地址,即一个指针的大小,64位系统8字节
printf("sizeof(arr[0]) = %d\n", sizeof(arr[0])); //4字节
for (int i = 0; i < 10- 1; i++)
{
for (int j = 0; j < 10 - 1 - i; j++)
{
if (arr[j] > arr[j + 1])
{
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
//可以改为void BubbleSort(int arr[],int n)
//整形数组做函数参数时,通常在函数定义中封装2个参数,一个表数组首地址,一个表示元素个数。
int main(void)
{
int arr[] = {1,2,15,51,3,78,99,21,8,6};
int n = sizeof(arr) / sizeof(arr[0]);
printf("n = %d\n", n);
printf("sizeof(arr) = %d\n", sizeof(arr));//整个数组的大小
printf("sizeof(arr[0]) = %d\n", sizeof(arr[0]));
BubbleSort(arr);
for (size_t i = 0; i < n; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
system("pause");
return EXIT_SUCCESS;
}
示例2:指针做函数返回值
int m = 100; //全局变量;对应空间消失 ===>程序结束
int* test_func(int a, int b)
{
return &m;
}
int main(void)
{
int *ret = NULL; //NULL = 0;
ret = test_func(10, 20);
printf("ret = %d\n", *ret);
system("pause");
return EXIT_SUCCESS;
}
指针和字符串:
1)
char str1[] = {'h', 'i', '\0'}; 变量,可读可写
char str2[] = "hi"; 变量,可读可写
char *str3 = "hi"; 常量,只读
str3变量中,存储的是字符串常量“hi”中首个字符‘h’的地址值。
str3[1] = 'H'; // 错误!!
char *str4 = {'h', 'i', '\0'}; // 错误!!!
2)
当字符串(字符数组), 做函数参数时, 不需要提供2个参数。 因为每个字符串都有 '\0'。
示例
int main(void)
{
char str1[] = "hello"; //{'h','e','l','l','o','\0'}
char m[] = "hello";//不跟str1一个地址,是变量
char* str2 = "hello"; //“hello"是一个字符串常量
char *n = "hello"; //是字符串常量,只能读,所以跟str2一个地址
str1[0] = 'R';
//不能写成:str2[0] = 'R';
printf("str1 = %s\n", str1);
printf("str2 = %s\n", str2);
printf("str1 = %p\n", str1);
printf("m = %p\n", m);
printf("str2 = %p\n", str2);
printf("n = %p\n", n);
system("pause");
return EXIT_SUCCESS;
}
练习:比较两个字符串: strcmp();实现
比较 str1 和 str2, 如果相同返回0, 不同则依次比较ASCII码,str1 > str2 返回1,否则返回-1
数组方式:
int mystrcmp(char *str1, char *str2)
{
int i = 0;
while (str1[i] == str2[i]) // *(str1+i) == *(str2+i)
{
if (str1[i] == '\0')
{
return 0; // 2字符串一样。
}
i++;
}
return str1[i] > str2[i] ? 1 : -1;
}
指针方式:
int mystrcmp2(char *str1, char *str2)
{
while (*str1 == *str2) // *(str1+i) == *(str2+i)
{
if (*str1 == '\0')
{
return 0; // 2字符串一样。
}
str1++;
str2++;
}
return *str1 > *str2 ? 1 : -1;
}
示例
//str1和str2比较,如果相等,返回0;如果str1>str2返回1;否则返回-1
int mystrcmp(char* str1, char* str2) //数组方式
{
int i = 0;
while (str1[i] == str2[i]) // *(str1+i) == *(str2+i)
{
if (str1[i]=='\0')
{
return 0; //两字符串一样
}
i++;
}
return *str1 > *str2 ? 1 : -1;//三目运算,不然str1<str2只能返回0;
}
int mystrcmp2(char* str1, char* str2) //指针方式
{
while (*str1 == *str2) // *(str1+i) == *(str2+i)
{
if (*str1 == '\0')
{
return 0; //两字符串一样
}
str1++;
str2++;
}
return *str1 > *str2 ? 1 : -1;
}
int main(void)
{
char* str1 = "hello ";
char* str2 = "helloz";
int ret = mystrcmp2(str1,str2);
if (ret ==0)
{
printf("str1 = str2");
}
else if (ret == 1)
{
printf("str1 > str2");
}
else
{
printf("str1 < str2");
}
system("pause");
return EXIT_SUCCESS;
}
练习:字符串拷贝:
//数组版本
void mystrcpy(char *src, char *dst)
{
int i = 0;
while (src[i] != 0) // src[i] == *(src+i)
{
dst[i] = src[i];
i++;
}
dst[i] = '\0';
}
//指针版
void mystrcpy2(char *src, char *dst)
{
while (*src != '\0') // src[i] == *(src+i)
{
*dst = *src;
src++;
dst++;
}
*dst = '\0';
}
练习:在字符串中查找字符出现的位置:
char *myStrch(char *str, char ch) //指针方式
{
while (*str)
{
if (*str == ch)
{
return str;
}
str++;
}
return NULL;
}
// hellowrld --- 'o'
char *myStrch2(char *str, char ch) //数组方式
{
int i = 0;
while (str[i])
{
if (str[i] == ch)
{
return &str[i];
}
i++;
}
return NULL;
}
示例
char *strch(char *src, char ch) //查找字符串中字符出现的位置,数组方式
{
int i = 0;
while (src[i])
{
if (src[i] == ch)
{
return &src[i];
}
i++;
}
return NULL;
}
char* strch2(char* src, char* ch) //指针方式
{
while (*src)
{
if (*src == ch)
{
return src;
}
src++;
}
return NULL;
}
int main(void)
{
char* src = "hello world";
char ch = 'e';
char* ret = NULL;
ret = strch(src, ch);
printf("ret = %s\n", ret);
system("pause");
return EXIT_SUCCESS;
}
练 习:字符串去空格。
void str_no_space(char *src, char *dst)
{
int i = 0; // 遍历字符串src
int j = 0; // 记录dst存储位置
while (src[i] != 0)
{
if (src[i] != ' ')
{
dst[j] = src[i];
j++;
}
i++;
}
dst[j] = '\0';
}
// 指针版
void str_no_space2(char *src, char *dst)
{
while (*src != 0)
{
if (*src != ' ')
{
*dst = *src;
dst++;
}
src++;
}
*dst = '\0';
}
示例
void strnospace(char* src, char* dst) //数组模式
{
int i = 0;//遍历字符串src;
int j = 0;//记录dst存储位置
while (src[i] != 0)
{
if (src[i] != ' ')
{
dst[j] = src[i];
j++;
}
i++;
}
dst[j] = '\0';
}
void strnospace2(char* src, char* dst) //指针模式
{
while (*src)
{
if (*src != ' ')
{
*dst = *src;
dst++;
}
src++;
}
*dst = '\0';
}
int main(void)
{
char str[] = "ni chou sha chou ni za di ";
char dst[100] = { 0 };
strnospace2(str, dst);
printf("dst = %s\n", dst);
system("pause");
return EXIT_SUCCESS;
}
带参数的main函数:
无参main函数: int main(void) == int main()
带参数的main函数: int main(int argc, char *argv[]) == int main(int argc, char **argv)
参1:表示给main函数传递的参数的总个数。
参2:是一个数组!数组的每一个元素都是字符串 char *
测试1:
命令行中的中,使用gcc编译生成 可执行文件,如: test.exe
test.exe abc xyz zhangsan nichousha
-->
argc --- 5
test.exe -- argv[0]
abc -- argv[1]
xyz -- argv[2]
zhangsan -- argv[3]
nichousha -- argv[4]
测试2:
在VS中。项目名称上 --》右键--》属性--》调试--》命令行参数 --》将 test.exe abc xyz zhangsan nichousha 写入。
-->
argc --- 5
test.exe -- argv[0]
abc -- argv[1]
xyz -- argv[2]
zhangsan -- argv[3]
nichousha -- argv[4]
str 中 substr 出现次数:
strstr函数: 在 str中,找substr出现的位置。
char *strstr(char *str, char *substr) -- #include <string.h>
参1: 原串
参2: 子串
返回值: 子串在原串中的位置。(地址值);
如果没有: NULL
实 现:统计字符串中子串出现的次数
int str_times(char *str, char *substr)
{
int count = 0;
char *p = strstr(str, substr); // "llollollo"
while (p != NULL)
{
count++;
p += strlen(substr); // p = p+strlen(substr) --> "llollo"
p = strstr(p, substr); // 返回: "llo"
}
return count;
}
示例
int strtimes(char* str, char* substr)
{
char* p = strstr(str, substr);
int count = 0;
while (p != NULL)
{
count++;
p += strlen(substr);//p跳过子串的距离;
p = strstr(p, substr);
}
return count;
}
int main(void)
{
char str[] = "hellollollo";
char substr[] = "llo";
char* ret = strstr("hellollollo", "lloh"); //需要引入string.h
int renum = strtimes(str, substr);
printf("ret = %s\n", ret);
printf("出现%d次\n", renum);
system("pause");
return EXIT_SUCCESS;
}