C语言基础知识

1.内存管理

C语言内存讲解-详说内存分布和heap空间

2. 结构体内存对其规则

C语言结构体对齐规则
C语言-结构体 字节对齐–嵌套–数组
10道经典例题手撕C语言字节问题

#pragma pack(N) 每个特定平台上的编译器都有自己的默认“对齐系数”(也叫对齐模数)。程序员可以通过预编译命令#pragma pack(n),n=1,2,4,8,16来改变这一系数,其中的n就是你要指定的“对齐系数”。
如果没有通过宏,那么在32位Linux主机上默认指定对齐值为4,64位的默认对齐值为8,AMR CPU默认指定对齐值为8;

#include <stdio.h>
#include <string.h>


int main() {
    char str1[] = "abcd";
    char str2[] = {'a','b','c','d','\0'};
    char *str3 = "abcd";  //这样的话,*str3就相当于str1[]  str3也就数组名
    //上述三个是相同的,str2最后一个一定要加'\0'
    //str1,str2,str3都可以理解为数组名(也就是数组的首元素地址)
    //str1和str2都可以通过下标的方式改变对应的值
    //str3的方式,是按照常量的方式看待str3的,不能通过下标的方式修改

    /*
     * 一般情况下,数组名表示数组首元素地址
     * 特殊情况:
     *      sizeof(数组名),此时的数组名表示整个数组
     *      &数组名,此时表示整个数组的地址
     */

//    sizeof用来是按照字节数的(实际占用内存长度),字符、字符串、'\0'整形都能计算
//    sizeof(地址)就是等于一个地址类型占用的字节大小,跟指向的类型无关。

//    strlen用来字符数的长度,遇到'\0'就会停止计算长度。只能计算字符数组(以\0结尾)
//    strlen(地址)从这个地址开始计算,一直计算到\0为止。


	//字符串数组
	char week[3][10] = {
		"Monday",
		"Thenday",
		"Wenday"
	};
	
	char *pweek[]{  //char型指针数组
		"Monday",
		"Thenday",
		"Wenday"
	};


    //一维数组
    int a[] = {1,2,3,4,5,6};
    int *p = a;
    printf("%d\n",*(p+1));

    //指针数组
	int x = 1, y = 2, z = 3;
	int* b[3] = { &x,&y,&z };  //每一个元素都是指针的数组
	int** pb = b;   //pb和b可以互换

	for (int i = 0; i < 3; i++) {
		printf("%d\n", **(b + i));
	}

	for (int i = 0; i < 3; i++) {
		printf("%d\n", *(pb[i]));
	}

    //二维数组+数组指针
    int array[3][4]={
            {1,2,3,4},
            {5,6,7,8},
            {9,10,11,12}
    };
    int (*pa)[4] = array;  //pa和array可以互换

	//pa\array是第一行一维数组的地址
	//pa[0]\array[0]是第一行一维数组的首元素的地址
	//pa[0] pa[1]...可以理解为每一行一维数组的数组名字
	//pa+0  pa+1 ...和上边等价
	/而pa[0]+1 不等于 pa+1

    for (int i = 0;i < 3;i++){
        for (int j = 0; j < 4; j++){
            printf("%d ",*(*(pa+i)+j));
        }
        printf("\n");
    }

    for (int i = 0;i < 3;i++){
        for (int j = 0; j < 4; j++){
            printf("%d ",*(array[i]+j));
        }
        printf("\n");
    }


    return 0;
}

3. 字符串函数

复制字符串
strcpy(str1,str2) str1的位置必须够,但是不检查是否位置够
strncpy(str1,str2,n) 按照n的个数复制字符 该函数不会自己添加’\0’ 如果没有的话,需要自己添加

拼接字符串
strcat(str1,str2) str1的位置必须够,但是不检查是否位置够 该函数不会自己添加’\0’
strncat(str1,str2,n) 按照n的个数拼接字符 该函数自动添加空字符\0

strncat(
  str1, 
  str2, 
  sizeof(str1) - strlen(str1) - 1
);

比较字符
strcmp(str1,str2)
strncmp(str1,str2,n)

字符串拼接
sprintf(),snprintf()

char first[6] = "hello";
char last[6] = "world";
char s[40];   //s接收

sprintf(s, "%s %s", first, last);

4. 二维数组

#include<stdio.h>

int main(void)
{
	int array[3][4] = {
		{1,2,3,4},
		{5,6,7,8},
		{9,10,11,12}
	};

	for (int i = 0; i < 3; i++)
	{
		printf("%d  %d  %d  %d\n", array[i][0], array[i][1], array[i][2], array[i][3]);
	}

	for (int i = 0; i < 3; i++)
	{
		printf("%p  %p  %p  %p\n", &array[i][0], &array[i][1], &array[i][2], &array[i][3]);
	}

	printf("在理解的时候,[ ]就相当于*解引用;若有[ ]又有&就相当于这两个都没有\n");
	printf("二维数组名字直接使用表示数组指针   若解一层引用表示到具体的某一行数组名\n");

	printf("array:        %p  *array:      %p\n", array, *array);
	printf("array + 1:    %p  *array + 1:  %p\n", array + 1, *array + 1);
	printf("&array[0]:    %p  array[0]:    %p\n", &array[0], array[0]);
	printf("&array[0] + 1:%p  array[0] + 1:%p\n", &array[0] + 1, array[0] + 1);

	int(*p1)[4];
	int(*p2)[4];
	int(*p3)[4];

	p1 = array;     //用指针数组表示二维数组的最佳表示方法
	p2 = *array;    //不会报错,但是逻辑上别扭
	p3 = array[0];  //不会报错,但是逻辑上别扭

	printf("%p  %p  %p\n", p1 + 1, p2 + 1, p3 + 1);
	printf("%p  %p  %p\n", *(p1 + 1) + 2, *(p2 + 1) + 2, *(p3 + 1) + 2);

	int(*p4)[4];
	p4 = array[0] + 1;       //这样虽然不会报错,但是逻辑错误
	printf("%p\n", p4 + 1);  //错误示例

	//正确示范
	p4 = array + 1;
	printf("%p\n", *p4 + 1); //这样的话,逻辑是正确的   

	return 0;
}

5. const 指针

在这里插入图片描述

6. 字符串

#define DMG "I am ueueq"

int main(void)
{
	char str1[] = { 'A','B','C','D','E','\0' };
	char str2[] = "ABCDE";
	char* str3 = "ABCDE";


	//strlen表示的是字符串的实际长度,遇到‘\0’停止,且不包括‘\0’
	//sizeof表示实际占用内存大小,包括'\0'
	printf("strlen:%d  sizeof:%d\n", strlen(str1), sizeof(str1));
	printf("strlen:%d  sizeof:%d\n", strlen(str2), sizeof(str2));

	printf("str2:%p  *str3%p\n", str2, str3);

	str1[1] = 'Z';
	str2[1] = 'Z';
	//	str3[1] = 'Z';   //字面量的字符串定义方法,属于常量定义,不能通过数组下标的方式改变字符串

	puts(str1);
	puts(str2);
	puts(str3);

	//测试新的示例
	//数组与指针定义字符串的不同

	/*
		字面量的定义方式,会将字符串存储在静态存储区(文本);
		若采用数组的定义方式,还会复制一份到到内存地址中,即str所指的位置;并且str所指向的位置不能改变,只能str+1,不能++str
		若采用指针的定义方式,会直接将静态存储区的地址放到strp。可以++strp指向第二个字符;这种方式感觉就是字符指针。
	*/
	/*
		C语言中定义的相同的字符串(字面量方式)。可能只存储一份。
	*/

	char str[] = DMG;
	char* strp = DMG;

	printf("str[]:%p  *strp:%p\n", str, strp);
	printf("DMG:%p\n", DMG);

	const int* pt;
	int const* pz;

	int* const pl;

	return 0;
}

7. 图片记录

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

8. 函数指针

	void func(int a, int b); //函数声明
	void (*pf)(int, int);   //函数指针定义
	pf = func;  //赋值
	pf(1, 2);   //函数指针使用

	int func(char*, int);
	int (*pf)(char*, int);
	pf = func;
	pf('0', 1);

	//函数指针数组
	int func(char*);
	int (*pf[10])(char*);  //表示每一个元素都是指向func函数的函数指针
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

秋山刀名鱼丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值