1.字符数组在指定位置插入字符;
#include<stdio.h>
#include<string.h>
int main()
{
char a[100] = {0}; //最好初始化一下
char s;
int len_a, num, i;
printf("please input a string:\n");
scanf("%s %c%d", a, &s, &num);
// printf("aaaaaaaaaaaaaa\n");
len_a = strlen(a);
for(i = len_a; i >= num; i--)
{
a[i + 1] = a[i];
}
// printf("bbbbbbbbbb\n");
a[num] = s;
// a[len_a + 1] = '\0' //不初始化数组中要加'\0'
// printf("ccccccccccccc\n");
printf("%s\n", a);
return 0;
}
getchar();获取一个字符
段错误(Segmentation),不能访问内存。
可能出现段错误的三种情况;
1、int a[10];访问a[10]可能出现段错误
2、指针分配空间 申请i个字节访问i+1个,会出现段错误
3、没有分配,直接访问地址
调试段错误最常用的方法:
在每个函数段后面输出一串字符如:printf("aaaaaaaaaaaaaa\n");
\n一定要加 不加\n程序结束后一并输出
\n的作用:1.换行
2.刷新缓冲区(把缓冲区中的数据清空,并刷新到屏幕上)
∴printf 能加 \n 就加\n
sleep(1) 停1s
fflush(stdout) 函数的作用也是刷新缓冲区
2.在字符数组中指定开始位置插入字符串
#include <stdio.h>
#include <string.h>
int main()
{
char str[64] = {0}, ptr[32] = {0};
int num, len_str, len_ptr, i;
printf("Please input :\n");
scanf("%s%d%s", str, &num, ptr);
len_str = strlen(str);
len_ptr = strlen(ptr);
for (i = 0; i < len_str - num; i++)
{
str[len_str - 1 - i + len_ptr] = str[len_str - 1 - i];
}
strncpy(str + num, ptr, len_ptr);
printf("%s\n", str);
return 0;
}
3.有n个人围成一圈,顺序排号,从第一个开始报数(从1到3报数),凡报到3的人退出圈子,问最后最后留下的是原来第几号的那位
#include <stdio.h>
int main()
{
int num, person; //person表示当前的人数
int k = 0; //k用于报数
int flag[1000] = {0}; //用于标记是否还在 1 不在 0 在
int i = 0; //数组的下标
printf("Please input a number:\n");
scanf("%d", &num);
person = num;
while (person != 1)
{
i++; //人的编号
if (flag[i] == 0)
{
k++;
}
if (k == 3)
{
k = 0;
flag[i] = 1; //踢出去
person--;
}
if (i == num)
{
i = 0;
}
}
for (i = 1; i <= num; i++)
{
if (flag[i] == 0)
{
printf("the last one : %d\n", i);
break;
}
}
return 0;
}
预处理
对#开头的文件处理
种类:
宏定义 #define 预处理做替换
定义常量
定义函数
#include<stdio.h>
#define OUT printf("helloworld\n"); //无参数的宏
#define p(s) printf("abcdefg\n"); //有参数的宏
宏定义的参数没有类型
#define SQR(x) x*x //宏函数只做简单替换
int main() 此时
{ SQR(a+b) = 1 + 2 * 1 + 2 =5
int a = 1, b = 2; 所以写宏函数时多加括号
OUT;
p(s);
printf("%d \n", SQR(a + b));
return 0;
}
面试题:自定义函数和宏函数的区别
(两个方面来分析,时间和空间)
答:宏函数不占空间,不需要给形参分配空间 优点:节省空间
缺点:1.浪费编译时间
2.没有语法检查,不安全
普通函数优点:有语法检查
缺点:浪费空间
文件包含 #include
#include"" 在当前目录和TC指定的目录中找 自定义的用这个 ''
#include<> 在TC指定的文件目录中 库里面用这个 <>
TC:编译环境
条件编译 #if--#else--#endif等
补充:
static 修饰全局变量 改变变量的作用域 只能在本文件被使用
修饰函数 改变函数的作用域 只能在本文件中被调用
修饰局部变量 改变变量的声明周期,直到程序结束才被释放
函数调用最后释放栈空间,被static修饰的局部变量,存放在数据段
即(静态数据区)
#include<stdio.h>
int add()
{
static int a = 0; //输出12345
// int a = 0; //输出5个1
a++;
printf("%d\n", a);
}
int main()
{
int i;
for(i = 0; i < 5; i++)
{
add();
}
return 0;
}
指针
指针式变量的一种,里面是一个地址,通过这个地址找到要找的数据
实质:单元的地址就是指针的内容
运算符:
& 是取地址的运算符 * 表示指针运算符
#include<stdio.h>
int main()
{
int *a;
char *b; //都是指针
//所有类型的指针 长度都是4字节
printf("int:%d\n", sizeof(int *));
printf("char:%d\n", sizeof(char *));
printf("long:%d\n", sizeof(long *));
printf("short:%d\n", sizeof(short *));
printf("double:%d\n", sizeof(double *));
printf("float:%d\n", sizeof(float *));
return 0;
}
*的含义
定义时(数据类型 *) 表示后面的变量是一个指针,没有取值的意思
使用时 表示取值 取地址里的值
int *p; *p=&a; ✖✖✖
把a的地址值赋给整型数a 不合理!
指针做参数
#include<stdio.h>
void fun(int *x, int *y) //如果不传地址,形参改变 实参不变
{ //当i涉及到修改实参内存值的时候,需要传地址
int tmp = *x;
*x = *y;
*y = tmp;
}
int main()
{
int a = 1, b = 2;
fun(&a, &b);
printf("a = %d, b = %d\n", a, b);
return 0;
}
指针和变量
#include<stdio.h>
int main()
{
int x = 3, y = 0, *px = &x;
printf("%p\n",px);
y = *px + 5;
printf("%d\n", y); //y = 8
y = ++*px;
printf("%d\n", y); //y = 4
y = *px++;
printf("%d\n", y); //y = 4
printf("%p\n",px); //px 比 px 大4个字节
return 0;
}
(*px)++ 与 *px++区别?
(*p1)++是x的内容加1;
*p1++是先求*p1的值(x),然后再p1++,指向下一个元素,不再指向x;
利用指针实现strcpy函数
#include <stdio.h>
char *mystrcpy(char *str, const char *ptr)
//char * 返回值(暂时不需要了解)
{
char *tmp = str;
/*while (*ptr != '\0')
{
*str = *ptr;
str++;
ptr++;
}*/
while ((*str++ = *ptr++) != '\0');
//先赋值再判断再移动指针
return tmp;
}
int main()
{
char str[20] = "helloworld";
char ptr[20] = "world";
mystrcpy(str, ptr);
printf("%s\n", str);
return 0;
}
NULL 空指针
头文件中宏定义
#define NULL 0
int *p = NULL; 定义空指针
int *p; 野指针 指向一段不能访问的内存
p为指针变量 p=NULL表示空指针,不指向任何变量。
P !=NULL表示p不是空指针;
不同类型与零值比较
int
if(n == 0)或者 if (n != 0)
float
const float EPSINON = 0.00001;
if ((n >= -EPSINON ) && (n <= EPSINON )) 由于精确度
bool类型 c++中才有
if (flag)或者if (!flag)
指针类型
if (n == NULL)或者if (n != NULL)
指针的使用步骤
1.定义指针变量;
2.给指针变量赋地址; ★容易忽略 内存需合法
3.正常使用指针进行运算;
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
#if 0 //条件编译1
int *p; //定义一个指针
printf("%p\n", p);
*p = 1; //不合法 不能直接使用
int a = 1;
int *q;
q = &a; //给指针赋值
int *pa;
pa = q; //给pa赋值q
#endif
char *fp;
fp = (char *)malloc(sizeof(char) * 20);
//向操作系统申请空间 连续的空间 堆空间
if (NULL == fp)
{
printf("malloc falure!\n");
}
strcpy(fp, "helloworld");
printf("%s\n", fp);
free(fp); //malloc申请的空间不用后释放空间
return 0;
}
用指针实现字符串反向输出
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void string_reverse(const char *ptr, char *str)
{
int len = strlen(ptr), i;
ptr += (len - 1);
for (i = 0; i < len; i++)
{
*str = *ptr;
str++;
ptr--;
}
}
int main()
{
char *ptr = "helloworld!";
//ptr指向helloworld字符串 helloworld是常量,不能修改
char *str = (char *)malloc(sizeof(char) * 64);
string_reverse(ptr, str);
printf("%s\n", str); //打印字符串格式 %s, 参数是字符串的首地址
return 0;
}
指针和数组
访问数组的方法:下标法和指针法
#include <stdio.h>
int main()
{
int i;
int a[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; //数组名a 常指针
int *p = a; //指针p指向数组的第一个元素
for (i = 0; i < 10; i++)
{
//printf("%d ", a[i]); //下标法
//printf("%d ", *(a + i)); //指针法
printf("%d ", *(p + i)); //指针法
}
printf("\n");
char *q = "helloworld"; //通过数组下标访问指针 就存储空间不一样
for (i = 0; i < 10; i++)
{
printf("%c", q[i]);
}
printf("\n");
return 0;
}
思考:
#include<stdio.h>
int main()
{
int a[5] = {1, 2, 3, 4, 5};
int *p1 = (int *)(&a + 1);
int *p2 = (int *)((int)a + 1);
int *p3 = (int *)(a + 1);
printf("%d\n", *p1); 输出结果: // 乱码
printf("%d\n", *p2); // 辣鸡值
printf("%d\n", *p3); // 2
return 0;
}
判断字符串2是不是字符串1的子串
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int len_str, len_ptr, i;
char *str = (char *)malloc(sizeof(char) * 32);
char *ptr = (char *)malloc(sizeof(char) * 32);
printf("Please input :\n");
scanf("%s%s", str, ptr);
len_str = strlen(str);
len_ptr = strlen(ptr);
if (len_str < len_ptr)
{
printf("input error!\n");
return -1;
}
for (i = 0; i < len_str - len_ptr + 1; i++)
{
if (strncmp(str + i, ptr, len_ptr) == 0)
{
printf("%s 是 %s 的子串\n", ptr, str);
break;
}
if (i == len_str - len_ptr)
{
printf("%s 不是 %s 的子串\n", ptr, str);
}
}
return 0;
}
指针和字符串
#include<stdio.h>
int main()
{
char *str[] = {"I love China", "hello", "Nice"}; //指针数组
//[]优先级高,str[],所以是数组
//I love China 是指针 指向字符串 I love China
printf("%s\n", str[0]);
printf("%s\n", str[1]);
printf("%s\n", str[2]);
//打印字符串 %s 参数:字符串的首地址
printf("%s\n", str);
return 0;
}
字符串的赋值方法
#include <stdio.h>
int main()
{
char *ptr = "helloworld"; //ptr指向hellworld字符串
char *str;
str = "helloworld"; //同上
char a[20] = "helloworld"; //数组a保存helloworld字符串
char b[20];
//b = "hellowrold"; //错误 b数组名是常指针
strcpy(b, "helloworld"); //正确
return 0;
}