我的C语言总结

文章详细阐述了C语言的基础知识,包括变量、常量、宏定义、数组、字符串处理、指针操作、函数使用等方面,并提供了若干解题思路,如数字转换、输入输出处理、递归函数等。同时,文章还指出了一些常见的编程错误,帮助读者避免常见问题。
摘要由CSDN通过智能技术生成

一、C语言的一些基础知识

             1.  int n=10;//n是变量

             const   int n=10;//n是常变量,但是n的本质还是变量,因此,即使这么写也不能运用到数组的[ ]里,int arr[n] 是错误的,数组[ ]必须要是常量,C99除外。

              2.#define 定义的标识符常量,是常量。

              3.枚举常量——枚举类型中列举出来的可能取值都是枚举常量。

              4.#define MAX 100 这是#define定义的标识符常量,注:这个可以运到用数组[ ]里

              #define ADD(x)  ((x)*(x))  #这是define定义的宏。

                注意:1.#define 定义的宏不能递归使用 。

                            2.#define 定义的标识符不会替换字符串里面的内容。

              5.strlen的使用注意:

                        char arr[ ]={'a','b','c','d'};

                        strlen(arr) //这样使用是可以求出字符串的长度大小

                        strlen(arr[0]) //这样使用就是err的,因为strlen是求字符串的大小,arr[0]的值是a,对应的ASII值为97,strlen不能对ASII值求长度。

              6.除号两端的操作数如果都是整数,执行的结果就是整数除法

                   int a =7/2 ; // a=3

                除号两端只要有一端是浮点数,那么计算出来的结果就是浮点数结果.

                     float  a=7/2  // a=3.50000f

               7.0是表示假,非0(1)表示真。

                        int a=1;

                        if(a)   //条件表达式中只有为真才会被执行,因为a !=0,所以为真,会执行if语句。

                8.if语句后面默认只能跟一条语句,如果跟多余语句,就必须加代码块 { }。

                9.else 只会与最近的if语句进行结合
                        

  int a=0;
  int b=2;
  if(a ==1) 
     if( b==2)
        printf("hehe");
      else
        printf("haha");

 else 只会跟最近的if进行匹配,所以这个是什么都不打印,可以将上面代码看成下面的形式

int a=0;
  int b=2;
  if(a ==1) 
   {
     if( b==2)
        printf("hehe");
      else
        printf("haha");
   }

                10. case 后面必须跟整形常量表达式。

                11.int* str =“pink;

                知道*str+1和str+1的区别:*str+1表示对str进行解引用然后对地址所存的内容+1

                                                             str+1表示对str的地址进行加一个完整的类型字节

               例如:*str+1="ink",而str+1表示跳过整个字节,指向下一个地址。

                12.malloc colloc  realloc函数需要引用头文件#include<stdlib.h>。

                13.system("cls"):清理屏幕 需要头文件#include <window.h>

                      Slepp(1000) :睡眠1秒,需要头文件#include <stdlib.h>。

                14.当我们写了多层循环时,想直接一步跳出整个循环,然后再执行下面的语句时,可以使用goto语句。

                15.最小公倍数 =(m*n)/最大公倍数(m和n的);

                16.int* 类型的指针+1表示一次走4个字节

                     char*类型的指针+1表示一次走1个字节。

                17.结构体

struct tag
{
  char name[20];
  int age;
}S1,S2,S3;  //这个定义的变量一般都是全局变量,所以一般都不用写

                18.对结构体里面的字符串数组我们不能强行修改,例:S1.name="zhangsan"这样是错误的,(原因是name是首元素的地址,地址是一个常量的值,是不可以由我们修改的)如果要强行修改就必须写成strcpy(S1.name,”zhangsan“),对整形类型的就可以直接修改,例:S1.age =30是可以的。

                19. const  int* p=&a;const放在*左边,修饰*p,也就是*p的值不可以被改变。

                        int* const p=&a;const放在*右边,修饰p,也就是p不能被改变。

                20.'A'对应的ASII码值为65,‘a'对应的ASII码值为97,相差32.

                21.C语言是没有输入输出语句,printf和scanf是库函数,独立于C语言,是由编译器提供的。C语言就是计算机语言,规定了语言。

                22.double x,y;

                     x=2    y=x +3/2 ; //y==3而不是3.5 因为y虽然是double类型,但是/两边的3和2是整数,所以算出来的结果是1,而不是1.5.

                23.数组初始化必须写成 char arr[ ]={0},不能写成char arr[ ] =0;//err

                24.补码有两种方式转换成原码:1.补码先-1,再取反得到原码

                                                                     2.补码先取反,再+1得到原码

                25在打印时如果有整形提升,先看这个数的类型是什么,如果是有符号位,则进行整形提升的时候是补符号位,如果是无符号位,则直接补0,然后再变成原码,再根据要打印的要求进行打印。

                26.存放数组就要使用数组指针 

                        int arr[10]={0}; 

                         int (*pa)[10]=&arr; //这个是数组指针,但是我们一般不是这么使用的,而是用于二维数组传参。

void Print(int (*pa)[10],int r,int c)

int main()
{
	int arr[10][10] = { 0 };
	Print(arr,10,10)
}

                27.int  (*parr3[10]) [5] //parr3是存放数组指针的数组。图解为:

 28.我们在写函数的时候,函数名都是自己起的,但是函数名我们可以写指针的形式(也就变成了函数指针),也可以写成函数数组形式(也就变成了函数指针数组)。

int Add(int x,int y)

   int  (*pf)(int x,int  y) =Add;//这个是函数指针

 int  (*pf[10])(int x,int  y)//这个是函数指针数组

函数指针数组的使用:

         int  (*pf[10])(int x,int  y)={0,Add,Sub,Mul,Div};//这样写一般是用来多个函数,且可以不使用switch。

29.认识下  指向函数指针数组的指针

    int (*(*ptr)[10])  (int x,int y)  =&pf;

30.回调函数  void cals就是回调函数。

 31.qsort(arr,s2(数组的个数),size(数组的类型大小),cmp(比较2个元素的大小的函数指针)。cmp这个一般都是要自己写的。qsort函数的头文件是#include<stdlib.h>。

例如:

int cmp_int(const void* e1,const void* e2)

{

  return *(int*)e1-*(int*)e2;  //升序,如果要降序写成*(int*)e2-*(int*)e1;

}

如果是结构体要写成

int cmp_by_name(const void* e1,const void* e2)

{

  return strcmp((strcut Stu*)e1)->name,((strcut Stu*)e2)->name);

}

二、 C语言的一些思路解题

 1.  123这个数可以有两种方法得到 : 1.从后往前用pow ()

                                                              2.从前往后用while( ) {ret =ret *10+flag*nums} 如果是字符串则用while (){ret =ret*10 +flag*(*str -‘0’)};   //flag是变换符号用的 

   2.·scanf 和getchar 和gets        

          scanf ——abc\n  

          getchar——输入缓冲区

      如果要先用scanf,再使用getchar时,当我们输入abc回车后,scanf只会拿出abc,而回车还在输入缓冲区里,如果我们再立即使用getchar,那么getchar就会立即把输入缓冲区的回车拿走,因此我们可以先使用一个getchar的方法来清空输入缓冲区,然后再使用getchar,清理输入缓冲区的代码为:

 int ch=0; //使用getchar必须要定义成int类型,因为当getchar获取字符失败时会返回EOF,
           //EOF的本质是-1

  //如果确认scanf拿完之后只有\n,那么可以不使用循环,
  //直接用一个getchar来清空输入缓冲区也是可以的
 while((ch =getcahr()) !='\n')
 {
    ;
 }

使用循环的原因是 如果从键盘上输入abc空格空格cde\n,scanf也只会那空格之前的abc,而空格会被scanf忽略,因此如果我们要输入空格时,必须使用gets。如果要强行用scanf,要写成scanf("%[^\n]",arr),这样的话就可以存储空格。

  3.下面的代码的作用是:只打印数字字符,跳过其他字符。

#include <stdio.h>
int main()
{
	int ch = '0';
	while ((ch = getchar()) != EOF)
	{
		if (ch < '0' || ch>'9')
			continue;
		putchar(ch);
	}
	return 0;
}

4.sizeof计算大小只看类型,不会计算里面的表达式,S不会被sizeof里面的表达式影响。

int main()
{
	short s = 10;
	int a = 2;
	printf("%d\n", sizeof(s = a + 5)); //2
	printf("%d\n", s); //10
}

5.将一个数的某位置为0或者1.

int main()
{
	int a = 0;
	int n = 0;
	int b = 0;
	scanf("%d", &n);
	//把a的第n位置为1
	b = a | (1 << (n - 1));
	//把a的第n位置为0
	b = a & (1 << (n - 1));
	return 0;
}

6.用递归的方法逆序字符串

int  my_strlen(char* str)                         
{
	int count = 0;
	while (*str != '\0')
	{
		str++;
		count++;
	}
	return count;
}
void reverse_string(char* str)
{
    //注意不能传(*str),这不是指针的意思而是解引用
	int len = my_strlen(str);//如果题目要求不能用strlen求长度的话
	char tmp = *str;
	*str = *(str + len - 1);
	*(str + len - 1) = '\0';
	if (my_strlen(str + 1) > 1)
		reverse_string(str + 1);
	*(str + len - 1) = tmp;
}
int main()
{
	char arr[] = "abcdef";
	reverse_string(arr);
	printf("%s ", arr);
	return 0;
}

 7.(1)要得到二进制中的某一位只要右移(>>)再按位与(&)1就可以得到其中的某一位。

    (2)  n&(n-1)也是求二进制中有多少个1.(这个也可以用来找二个二进制数里有多少个不用,先让两个数异或,再使用此方法)。

具体用法:

while (n)
{
	n = n & (n - 1);
	count++;  //计算出来的count为3,而11刚好有3个1
}

//  n=11=1011 ——n
//      &1010 ——n-1
//      ___________
//       1010 ——新的n
//      &1001 ——n-1
//       ___________
//       1000 ——新的n
//      &0111 ——n-1
//        ___________
//        0000

8.获取一个数的最低位: n2=n-n/10*10;  例如: n=101, n2=101 -101/10*10=101-100=1;

                                                                              n=9,n2=9-9/10*10=9-0=9;                                                                                                     n=11,n2=11-11/10*10=11-10=1;

   例如:

int main()
{
	int n = 100;
	int tmp = 0;
	int tmp2 = 0,count=0;
	for (int i = 0;i <= n;i++)
	{
		if (i % 10 == 7)
			count++;
		else
		{
			tmp = i;
			while (tmp > 0)
			{
				tmp2 = tmp - tmp / 10 * 10;
				if (tmp2 == 7)
				{
					count++;
					break;
				}
				tmp = tmp / 10;
			}
		}
	}
	printf("%d", count);
}

       9. 如果数组已经在一个循环中,然后我们需要对数组作出改变,那么如果能不移动数据,那么尽量不要移动数组   ,因为这样时间复杂度会变成O(n^2);可以使用双指针的办法去改变这个数组。

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int j = 0;
	int del = 5;//删除5
	for (int i = 0;i < 10;i++)
	{
		if (arr[i] != del)
		{
			arr[j] = arr[i];
			j++;
		}
	}
	for (int i = 0;i < j;i++)
	{
		printf("%d ", arr[i]);
	}
}

   10.青蛙跳台阶的解法:

int walk(int n)
{
	if (n <= 2)  //原因是 当台阶为1时,只有一种跳法,当台阶为2时,一共有2种跳法
		         //当n>=2时,walk(n-1)+walk(n-2)
                //walk(n-1)算一次跳一个台阶总共有多少个可能                                     
		        //然后再加上walk(n-2)一次跳两个台阶的总共可能
		return n;
	else
		return walk(n - 1) + walk(n - 2);
}
int main()
{
	int n = 0;
	scanf("%d", &n);
	int  ret = walk(n);
	printf("%d ", ret);
	return 0;
}

          11.        

 三. C语言可能会犯的错误

1.这种写法是错误的,因为再main方法中,arr是数组名,数组名是不允许被修改的,但是如果写成函数的形式传参就可以了。因为传参过去中arr数组名已经退化成char*类型的指针了,指针是可以被修改的。

int main()
{
	char arr[] = "abcdef";
	int count = 0;
	while (*arr != '\0')
	{
		count++;
		arr++;
	}
	printf("%d ", count);
	return 0;
}

2.这个代码循环0次,原因是k=0是一个赋值语句,恒为0;条件为假,不执行语句。

int main()
{
	int i = 0, k = 0;
	for (i = 0, k = 0;k = 0;i++,k++)
	{
		k++;
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值