【C语言】C语言笔记

fabs用来求double类型的绝对值,小数点后保留6位#include<math.h>
double fabs(double )
labs用来求长整型long整型的绝对值, long cabs(long n);
abs用来求整数的绝对值,labs求long long的绝对值#include<stdlib.h>

    double ret = fabs(3.14 - 5.26);
	printf("%f\n", ret);
	printf("%d\n",abs(3-5));
	printf("%d\n",abs(5555555555-6666666666));

###################################################################

    char* p = "hello";
	printf("%d\n", strlen(&p));//随机值
	char arr[] = {"hello"};
	printf("%d",strlen(&arr));//5

#################################################################
typedef u nion {long i; int k[5]; char c;} DATE;
struct data { int cat; DATE cow; double dog;} too;
DATE max;
则语句printf(“%d”,sizeof(struct date)+sizeof(max)); 的
执行结果是:_____
【标准答案】DATE是一个union, 变量公用空间. 里面最
大的变量类型是int[5], 占用20个字节. 所以它的大小是
20
data 是一个struct, 每个变量分开占用空间. 依次为int4 +
DATE20 + double8 = 32.
所以结果是20 + 32 = 52.
当然… 在某些16位编辑器下, int 可能是2字节,那么结果
是int2 + DATE10 + double8 = 20

###################################################################

函数指针,指针函数详解
##################################################################
下面的地址是相等的
(1)能够输出hello
(2)内存泄漏 //没有释放

void GetMemory2(char** p, int num)
{
	*p = (char*)malloc(num);

	printf("*p=%p\n", *p);//------------------地址1
}
void Test(void)
{
	char* str = NULL;
	GetMemory2(&str, 100);

	printf("str=%p\n", str); //------------------地址2 == 地址1
	strcpy(str, "hello");
	printf(str);
}

int main()
{
	Test();
	return 0;
}

###################################################################
在这里插入图片描述
###################################################################
main函数的返回值用于说明程序的退出状态:
如果返回0(return 0),则代表程序正常退出。通常,返回非零代表程序异常退出(可自行设定:如 return -1)。
return 后面是个变量a,则意思是返回a这个变量。
return 后面没有任何参数,就是执行到这一行以后 返回原函数,其实也就是中断函数执行,返回调用函数处,注意区别:break只是退出所在的循环体。
return 的意思是返回一个空值 其意义在于 这可以当成一个用于返回主函数的命令,而不是再当一个返回值用。

mian中,c标准认为0表示成功,非0表示错误(异常终止)。具体的值是某中具体出错信息。
###################################################################
static 和extern
在两个不同的源文件中,如果同时用static定义一个全局变量,变量名和值的是一样的
它们之所以可以连接成功而没有报重复定义的错误是因为虽然它们有相同的内容,但是存储的物理地址并不一样, 就像是两个不同变量赋了相同的值一样,而这两个变量分别作用于它们各自的编译单元。
也许你比较较真,自己偷偷的跟踪调试上面的代码,结果你发现两个编译单元(test1, test2)的g_str的内存地址相同,于是你下结论static修饰的变量也可以作用于其他模块,但是我要告诉你,那是你的编译器在欺骗你,大多数编 译器都对代码都有优化功能,以达到生成的目标程序更节省内存,执行效率更高,当编译器在连接各个编译单元的时候,它会把相同内容的内存只拷贝一份,比如上 面的"123456", 位于两个编译单元中的变量都是同样的内容,那么在连接的时候它在内存中就只会存在一份了。

在两个源文件中,其中一个源文件中定义了一个全局变量,和一个函数,函数可以在另一个源文件中直接使用,但是会有报警,最好也生名义一下,而全局变量没有声明就不能再其他的源文件中使用。

###################################################################
一语句实现x是否为2的若干次幂的判断

一语句实现x是否为2的若干次幂的判断

#define is2*n(x)  ((x & (x - 1))? 0 : 1)

int main(void)

{

        int m = 512;

        cout << ((m & (m - 1)) ? false : true) << endl;

        //即当m中只有一位为1时,才为若干次幂值

//若有两个及以上1,则(m & (m - 1))不为0,输出0,表示不为2的若干次幂

        return(0);

}

##################################################################
在过程中就转化为无符号整数了,而并不是先对(6-20)运算完在进行无符号转换

void foo(void)
{
unsigned int a = 6;
int b = -20;
(a+b> 6)? puts("> 6") : puts("<= 6");
}
//【参考答案】这个问题测试你是否懂得C 语言中的整数自动转换原则,
//我发现有些开发者懂得极少这些东西。不管如何,这无符号整型问题的答
//案是输出是“>6” 。原因是当表达式中存在有符号类型和无符号类型时所有
//的数都自动转换为无符号类型。因此-20 变成了一个非常大的正整数,所
//以该表达式计算出的结果大于6 。这一点对于应当频繁用到无符号数据类
//型的嵌入式系统来说是丰常重要的。如果你答错了这个问题,你也就到了
//得不到这份工作的边缘。

printf("b=%u\n", b);  //b=4294967276

//a+b = 6+(-20) = 6 + 4294967276 = 4294967282

###################################################################
malloc申请一段长度为0的空间,malloc依然会返回一段地址,还有一段地址空间,所以ptr不等于NULL。malloc这个函数,会有一个阈值,申请小于这个阈值的空间,那么会返回这个阈值大小的空间。如阈值为24,那么申请小于24的值就会返回24

数组越界和动态开辟空间越界动态开辟空间不止自己输入的数量,还会有一些用来存放开辟空间的信息,free为什么释放空间没有大小,因为在malloc开辟空间的时候已经存放了这些信息,开辟的空间不止自己设定的大小

在这里插入图片描述

在这里插入图片描述

##################################################################
assert中debug和release的区别,
这里告诉我们判段指针是否为空最好用下面的方法

char* str=NULL;
if(str==NULL)
{
     return;
}

在这里插入图片描述
在这里插入图片描述
###################################################################
数字转换为字符串

#define _CRT_SECURE_NO_WARNINGS 1


#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
//数字转换为字符串

char* Change(int num, char** str)
{
	*str = (char*)malloc(40);//calloc或者if((*str)==NULL)
	int c = num;;
	int b = 0;
	int len = 0;
	if (num < 0)
	{
		b = 1;
	}
	if (b == 1)
	{
		len++;
		c *= -1;
	}
	while (c > 0)
	{
		c /= 10;
		len++;
	}
	c = num;
	if (b == 1)
	{
		
		c*= -1;
		(*str)[0] = '-';
	}
	int i = 0;
	while (c > 0)
	{
		(*str)[len - 1 - i] = (c % 10) + '0';
		c /= 10;
		i++;
	}
	(*str)[len] = '\0';//注意,取消对NULL引用
	return *str;
}

int main()
{
	int a = -1234;
	char* p = NULL;
	Change(a, &p);
	//int f = 0;
	printf("%s", p);
	free(p);
	p = NULL;
	return 0;
}


//错误
//void IntToCharChange1(int num, char* pval)
//{
//    //判断正负号 
//    char negFlag = 0;
//    if (num < 0)
//    {
//        negFlag = 1;
//    }
//
//    //计算字符串长度 
//    int len = 0;
//    int tmp_num = num;
//    if (negFlag)
//    {
//        tmp_num *= -1;
//        len++;
//    }
//    while (tmp_num > 0)
//    {
//        len++;
//        tmp_num /= 10;
//    }
//
//    //转成字符串 
//    tmp_num = num;
//    if (negFlag)
//    {
//        tmp_num *= -1;
//        pval[0] = '-';
//    }
//
//    int val;
//    int i = 0;
//    while (tmp_num > 0)
//    {
//        val = tmp_num % 10;
//        pval[len - i - 1] = val + '0';
//        tmp_num = tmp_num / 10;
//        i++;
//    }
//    pval[len] = '\0';
//}
//
//int main(int argc, char* argv[])
//{
//    if (1)
//    {
//        int num1 = 1234;
//        char* str1;
//        IntToCharChange1(num1, str1);
//        printf("%s\n", str1);
//
//        int num2 = -1234;
//        char* str2;
//        IntToCharChange1(num2, str2);
//        printf("%s", str2);
//    }
//    return 0;
//
//}

//数组
void IntToCharChange1(int num, char* pval)
{
    //判断正负号 
    char negFlag = 0;
    if (num < 0)
    {
        negFlag = 1;
    }

    //计算字符串长度 
    int len = 0;
    int tmp_num = num;
    if (negFlag)
    {
        tmp_num *= -1;
        len++;
    }
    while (tmp_num > 0)
    {
        len++;
        tmp_num /= 10;
    }

    //转成字符串 
    tmp_num = num;
    if (negFlag)
    {
        tmp_num *= -1;
        pval[0] = '-';
    }

    int val;
    int i = 0;
    while (tmp_num > 0)
    {
        val = tmp_num % 10;
        pval[len - i - 1] = val + '0';
        tmp_num = tmp_num / 10;
        i++;
    }
    pval[len] = '\0';
}

int main(int argc, char* argv[])
{
    if (1)
    {
        int num1 = -1234;
        char str1[10] = { 0 };
        IntToCharChange1(num1, str1);
        int m = 0;
        while (str1[m] != '\0')
        {
            printf("%c", str1[m]);
            m++;
        }

        /* int num2 = -1234;
         char* str2=NULL;
         IntToCharChange1(num2, str2);
         printf("%s", str2);*/
    }
    return 0;

}

###################################################################
在字符串中查找有几个单词

int show(char* arr)
{
	int a = 0;
	int b = 0;
	int words = 0;
	while (*arr)
	{
		if ((*arr >= 'a' && *arr <= 'z') || (*arr >= 'A' && *arr <= 'Z'))
		{
			a = 1;
		}
		if (a == 1 && b == 0)
		{
			words++;
		}
		b = a;
		a = 0;
		arr++;
	}
	return words;
}
int main()
{
	char* arr = "hello,he,hi,welcome to my home!";
	int ret=show(arr);
	printf("%d",ret);
	return 0;
}

###################################################################
有两个磁盘文件A和B, 各存放一行字母,要求把
这两个文件中的信息合并(按字母顺序排列),输出
到一个新文件C 中。
在读取文件的时候文件名的大小写是没有影响的

int main()
{
	FILE* pf;
	pf=fopen("A.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 0;
	}
	fputs("aaccbb",pf);


	fclose(pf);
	//pf = NULL;

	pf = fopen("B.txt", "w");
	if (pf== NULL)
	{
		perror("fopen");
		return 0;
	}
	fputs("bbeeff", pf);


	fclose(pf);
	//p = NULL;
	char arr[50] = {0};
	pf = fopen("A.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 0;
	}
	int i = 0;
	char ch;
	while ((ch=fgetc(pf) )!= EOF)
	{
		arr[i] = ch;
		i++;
	}
	fclose(pf);

	pf = fopen("B.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 0;
	}
	while ((ch=fgetc(pf)) != EOF)//fgetc返回值EOF,开始写成了‘\0’了
	{
		arr[i] = ch;
		i++;
	}
	int n = i;
	int t = 0;
	for (i = 0; i < n; i++)
	{
		for (int j = i + 1; j < n; j++)
		{
			if (arr[i] > arr[j]) {
				t = arr[i];
				arr[i] = arr[j];
				arr[j] = t;
			}
		}
	}
	fclose(pf);
	//p1 = NULL;//结束时不要都置为空,因为后面还要用
	//在最后一个置为空就行了
	pf = fopen("C.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 0;
	}
	fputs(arr,pf);

	fclose(pf);
	pf= NULL;

	return 0;
}

###################################################################
在这里插入图片描述
###################################################################################
负数整形的除法和取余
1.最重的一点,我们希望 q * b + r == a,因为这是定义余数的关系。
2.如果我们改变 a 的正负号,我们希望这会改变 q 的符号,但这不会改变 q 的绝对值。
3.当 b>0 时,我们希望保证 r >= 0 且 r < b。例如,如果余数用于哈希表的索引,确保 它是一个有效的索引值很重 。
这三条性质是我们认为整数除法和余数操作所应该具备的。很不幸的是,它们不可能同时成立。
考虑一个简单的例子:3/2,商为 1,余数也为 1。此时,第 1 条性质得到了满足。(-3)/2 的值应该是多少呢?如果 满足第 2 条性质,答案应该是-1,但如果是这样,余数就必定是-1,这样第 3 条性质就无法满足了。如果我们首先满足第 3 条性质,即余数是 1,这种情况下根据第 1 条性质则商是-2,那么第 2 条性质又无法满足了。
因此,C 语言或者其他语言在实现整数除法截断运算时,必须放弃上述三条原则中的至 少一条。大多数程序设计语言选择了放弃第 3 条,而改为 求余数与被除数的正负号相同。 这样,性质 1 和性质 2 就可以得到满足。大多数 C 编译器在实践中也都是这样做的。
例如求-8 % 3,因为-8 / 3 = -2,那么余数就是-8 - 3 * (-2) = -2。
####################################################################################
快速幂实现
分奇偶实现

#include<stdio.h>
#include<math.h>
int Pow(int x, int y)
{
	int ret = x;
	int f = 1;
	while (y > 1)
	{
		if (y % 2 == 1)
		{
			y--;
			f *= x;
		}
		else
		{
			ret *= ret;
			y/= 2;
		}
	}
	return ret * f;
}
int main()
{
	int a = 3;
	int b = 2;
	Pow(a, b);
	printf("%d", Pow(a,b));
	return 0;
}

###################################################################

/**
 * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
 *
 * 比较版本号
 * @param version1 string字符串 
 * @param version2 string字符串 
 * @return int整型
 */
int compare(char* version1, char* version2 ) {
    const char *p=".";
   int arr1[3];
   int arr2[3];
   arr1[0]=atoi(strtok(version1,p));
   arr1[1]=atoi(strtok(NULL,p));
   arr1[2]=atoi(strtok(NULL,p));
   arr2[0]=atoi(strtok(version2,p));
   arr2[1]=atoi(strtok(NULL,p));
   arr2[2]=atoi(strtok(NULL,p));
   for(int i=0;i<3;i++)
   {
       
   }

 
    // write code here
}

##################################################################
二级指针及其以上的指针加1都是4个步长,无论什么类型

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值