目录
【1】指针和数组
【2】数组指针
【3】指针数组
【4】函数
【5】函数传参
【6】动态开辟堆区空间
【7】string函数族
【8】递归函数
练习:
【1】指针和数组
直接访问:通过数组名访问
间接访问:通过指针访问
》1. 一维数组
int a[5]={1,2,3,4,5};
int * p = a;
直接访问:
访问a[i]的地址:
&a[i] a+i
访问a[i]的值:
a[i] *(a+i)
间接访问:
访问a[i]的地址:
&p[i] p+i
访问a[i]的值:
p[i] *(p+i)
int a[5] = {1,2,3,4,5};
int *p=a;
printf("%d",*p++);//1
printf("%d",*a++);//报错
运算方法:
1) *和++都是弹幕运算符,优先级相同
2) 单目运算符从右向左运算
*p++ :先取*p,然后p自加
*(p++) :先取*p,然后p自加
(*p)++ :先取*p,然后*p自加
++*p :先取*p,然后*p自加
++(*p) :先取*p,然后*p自加
*++p :先p自加,然后取自加后的*p
*(++p):先p自加,然后取自加后的*p
》2. 二维数组
int a[2][3]={1,2,3,4,5,6};
a:第一行的首地址
a+1:第二行的首地址
*:降级
*行地址:表示将行地址降级成列地址
*a:第一行第一列的地址
*a+1:第一行第二列的地址
*(a+1):第二行第一列的地址
访问a[i][j]的地址:
a[i]+j *(a+i)+j
访问a[i][j]的值:
*(a[i]+j) *( *(a+i)+j)
【2】数组指针
1. 定义:
指向数组的指针,本质的指针(又称行指针)
2. 格式:
存储类型 数据类型 (* 指针名)[列数];
int a[2][3]={1,2,3,4,5,6};
int (*p)[3]=a;//int (*)[3] p
3. 间接访问:
访问a[i][j]的地址:
*(p+i)+j p[i]+j
访问a[i][j]的值:
*(*(p+i)+j ) *( p[i]+j)
4. 大小:
sizeof(p)=4字节 (32位操作系统)
【3】指针数组
1. 定义:
本质是数组,里面存放的是指针
2. 格式:
3.应用实例:
1)用于存放普通变量的地址
int a = 10,b=20,c=30;
int *p[3]={&a,&b,&c};
访问b的地址
p[1] *(p+1)
访问b的值
*p[1] *(*(p+1))
2)用于存放二维数组每行第一列的地址
int a[2][3]={1,2,3,4,5,6};
int * p[2]={a[0],a[1]};
访问a[1][2]的地址:
p[1]+2 *(p+1)+2
访问a[1][2]的值:
*(p[1]+2) *(*(p+1)+2)
sizeof(p)=8;//p是数组,包含两个指针
3)用于存放字符串
char *p[3]={"hello","world","hqyj"};
打印字符串world
printf("%s\n",p[1]);
printf("%s\n",*(p+1));
打印字符串world里面的字符d
printf("%c\n",*(p[1]+4));
printf("%c\n",*(*(p+1)+4));
4)命令行传参
int main(int argc, char const *argv[])
{
return 0;
}
argv:指针数组,存放命令行输入字符串的首地址
argc:表示argv存储数据的个数
【4】函数
【4】函数
1. 定义:
一个完成特定功能的代码模块
2. 格式:
存储类型 数据类型 函数名(参数列表)
{
函数体;
return 表达式;
}
1) 没有参数:参数列表可以省略(也可以写void)
2) 没有返回值:数据类型为void,函数内部省略return语句
3) 有返回值:需要根据返回值的类型定义函数的数据类型
#include<stdio.h>
void fun( )//无参无返回值
{
printf("hello world!\n");
}
void add(int a,int b)//有参无返回值
{
printf("%d\n",a+b);
}
int sub(int a,int b)//有参有返回值
{
return a-b;
}
int main(int argc, char const *argv[])
{
fun();//函数调用
add(3,4);//7
int t =sub(9,5);//4
printf("%d\n",t);
return 0;
}
注意:
函数可以直接定义在被调用位置前,也可以定义在被调用位置后面,但是必须要提前声明函数,函数声明就是将函数第一行复制到上面加;
3. 函数声明:
数据类型 函数名(形参);
4. 函数三要素:
功能、参数、返回值
5. 函数调用:
1) 没有返回值:直接调用:函数名(实参);
2) 有返回值:如果需要返回值,定义一个和返回值类型相同的变量来接收;如果不需要接收返回值,就可以直接调用
练习:
1.已知字符数组a[10]和b[10]已知字符数组a[10]和b[10]中元素的值递增有序,用指针实现将两个数组中元素按照递增顺序输出。
如:char a[10]=”acdgjmno”; char b[10]=”befhil”;->”abcdefghijlmno”
#include<stdio.h>
int main(int argc, char const *argv[])
{
char a[10]="acdgjmno";
char b[10]="befhil";
char * p = a;
char * q = b;
while (*p && *q)
{
if(*p < *q)
{
printf("%c",*p);
p++;
}
else
{
printf("%c",*q);
q++;
}
}
if(*p == '\0'&& *q)
printf("%s\n",q);
else if(*q == '\0' && *p)
printf("%s\n",p);
return 0;
}
2.编写一个函数,函数的2个参数,第一个是一个字符,第二个是一个char *,返回字符串中该字符的个数。
#include <stdio.h>
int countChar(char c, char *str) {
int count = 0;
while (*str != '\0') {
if (*str == c) {
count++;
}
str++;
}
return count;
}
int main() {
char str[] = "Hello, World!";
char c = 'o';
int count = countChar(c, str);
printf("The character '%c' appears %d times in the string.\n", c, count);
return 0;
}
【5】函数传参
1)值传递
单向传递,将实参传递给形参,修改形参,实参不会受影响
2)地址传递
双向传递,在函数中修改形参,实参会随之变化
3)数组传递
和地址传递一样,参数中存在数组定义,但是会认为是指针
练习:封装函数实现两个数的交换
#include <stdio.h>
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
int main() {
int num1 = 10;
int num2 = 20;
printf("Before swap: num1 = %d, num2 = %d\n", num1, num2);
swap(&num1, &num2);
printf("After swap: num1 = %d, num2 = %d\n", num1, num2);
return 0;
}
【6】动态开辟堆区空间
头文件:#include <stdlib.h> void *malloc(size_t size); 功能:在堆区开辟空间 参数: size:开辟空间大小(字节) 返回值: 成功:返回开辟堆区空间首地址 失败:NULL void free(void *ptr); 功能:释放堆区空间 参数: ptr:开辟堆区空间首地址 返回值:无
int * p =(int *)malloc(sizeof(int)*10); if( p == NULL) { printf("p malloc err\n"); return -1; } for(int i=0;i<5;i++) *(p+i)=i; free(p); p=NULL;
总结:
1. 在使用手动开辟堆区空间时,要注意内存泄漏当指针指向开辟堆区空间首地址时,又对指针赋值,则没有指针指向开辟的堆区空间会导致内存泄漏
2. 使用完堆区空间及时释放
【7】string函数族
头文件:#include <string.h>
1.strcpy
char *strcpy(char *dest, const char *src);
功能:实现字符串复制
参数:
dest:目标字符串首地址
src:源字符串首地址
返回值:目标字符串首地址
注意:
复制整个字符串,包括\0
char *strncpy(char *dest, const char *src, size_t n);
复制字符串的前n个字符
2.strcat
char *strcat(char *dest, const char *src);
功能:用于字符串拼接
参数:
dest:目标字符串首地址
src:源字符串首地址
返回值:目标字符串首地址
char *strncat(char *dest, const char *src, size_t n);
拼接字符串的前n个字符
3.strcmp
int strcmp(const char *s1, const char *s2);
功能:字符串的比较
参数:
s1,s2:两个字符串的首地址
返回值:
比较首个不同的字符的ASCII值,数小的字符串就小
0 s1 == s2
1 s1>s2
-1 s1<s2
int strncmp(const char *s1, const char *s2, size_t n);
比较两个字符串的前n个字符
【8】递归函数
1. 定义 :
自己调用自己
2. 执行过程分为两个阶段:
递推阶段:从原问题出发,按递归公式递推从未知到已知,最终达到递归终止条件
回归阶段:按递归终止条件求出结果,逆向逐步带入递归公式,回归到原问题求解
练习:
输入一个字符串,内有数字和非数int字符,如a123x456,将其中连续的数作为一个整数,依次存放到整形数组a中。
例:123存放在a[0],456存放在a[1]。统计共有多少整数,并输出这些整数。
#include <stdio.h>
int main() {
char str[] = "a123x456";
int a[10]; // 假设整型数组大小为10
int count = 0; // 统计整数个数
char temp[20]; // 临时字符串,用于存放连续的数字字符
int index = 0; // 当前存放整数的数组下标
for (int i = 0; str[i] != '\0'; i++) {
if (str[i] >= '0' && str[i] <= '9') {
temp[index++] = str[i];
} else {
if (index > 0) {
temp[index] = '\0'; // 添加字符串结束符
a[count++] = atoi(temp); // 将临时字符串转换为整数并存放到数组中
index = 0; // 重置临时字符串下标
}
}
}
printf("共有%d个整数:\n", count);
for (int i = 0; i < count; i++) {
printf("a[%d] = %d\n", i, a[i]);
}
return 0;
}