C语言学习疑问解惑

内容纲要

%#

%# 表示格式化输出,一般这样使用 %#p
%x 表示输出 16 进制格式,但是受环境影响,格式会变化。
%p 表示输出 16 进制 系统寻址范围为取值范围的整数。
有多少位就打印多少位。32位系统一般是 8 位,64 位系统一般 16 位。不足 8 位自动补 0 ;
例如 int 4 个字节,那么 %p 打印输出共 32 位 2 进制表示的值,不足位数自动补 0 。主要用来输出地址、指针。
%# 表示格式化输出,16 进制自动加上 0x

指针地址的字节数

指针地址都是使用 4 个字节存储。
char *int *double * 等类型的指针类型,都是四个字节!

(char*)

这个表示将一个值转为 char 类型的指针。
这个表示强制转换,此时不代表特殊的意义。跟 =下列例子意义相同。

char a = '6';
int b = (int)a;

示例

#include <stdio.h>

int main( void )
{
    char    a   = 'a';
    int b   = (int) &a;     /* 将地址作为值赋给b,指针都是用4字节存储 */
    printf( b );

    char *p;
    p = (char *) b;                 /* 将值转为地址形式 */

    printf( *p );

    return(0);
}

while({表达式})

C语言中没有布尔类型,https://www.whuanle.cn/archives/738
while 单条件为 true 是或 1 或非0 时,继续运行。碰到 flase、 0 、’\0′ 等情况结束。

whille(a>b)
while(i)
while(2)

char *pchar* p

两者本质是一样的,都是定义一个指针。但是他们定义多个变量时,会出现差异。
当使用 char* 时,代表声明的都是指针变量,例如:

    char* a, b, c;

下面这样,表示只有 j 才是指针变量,其它都是 char 变量。

char *j,p,k;

但是这样不好,普通变量和指针变量一起定义,这样容易出现歧义,应该分开两行声明。
如果实在要放到一起声明的话,一般使用如下的方式定义

    char l,m,*n

对于方法来说,* 的位置不重要。

char* test()
char *test()

malloc 和 calloc

两者都是分配内存,在头文件中定义 stdlib.h
malloc 在分配内存时,不会对内存进行“初始化”,所有字节的内容仍然是被分配时所含的随机值。
calloc 的话,分配内存时,会对所有字节置零。
在较新的 C 语言规范中,malloc 和 calloc 都返回一个void型的指针,也就是说,返回的地址值可以假设为任何合法的数据类型的指针。

一般来说,我们使用指针,都是要用数据类型去定义的,例如 char *pint *i
而使用 malloc 和 calloc 的话,可以转成任何类型的指针。

以下是错误的使用,原因在于 malloc 返回的是 void

#include <stdio.h>
#include <stdlib.h>

int main() {
    char *p;
    p = malloc(200);
    gets(p);
    printf(p);
    free(p);
    return 0;
}

所以分配内存,返回指针,应该使用如下的方式接收

    p = (char *)malloc(200);

还有一个问题,分配内存,不一定都是成功的,如果分配失败,会返回 NULL。

所以应该这样写

#include <stdio.h>
#include <stdlib.h>

int main() {
    char* p;
    p = (char*)malloc(200);
    if (p == NULL)
    {
        printf("分配失败");
        exit(1);
    }
    gets(p);
    printf(p);
    free(p);
    return 0;
}

指针的初始化

指针初始化有两种方法,一种是使用已有变量地址,一种使用动态分配内存。
示例

    char a = 'a';
    // 方法1
    char* p = &a;
    // 方法2
    p = (char*)malloc(200);

指针变量也是变量

指针变量也是变量,也有作用域。

#include <stdio.h>

char* test(char* p) {
    printf("p 的地址 %#p \n",&p);
    return p;
}

int main() {

    char a = 'a';
    char* p1 = &a;
    printf("p1 的地址 %#p \n",&p1);

    char* p2 = test(p1);
    printf("p2 的地址 %#p \n", &p2);
    return 0;
}

输出结果如下

p1 的地址 000000C166F5FA08
p 的地址 000000C166F5F9C0
p2 的地址 000000C166F5FA28

可以看到每个 p 的地址都不同。指针变量也是,也有作用域。

大端和小端存储

字和字节:
一个字节为 8 位。这个是几乎所有计算机通用的。
以 CPU 的位数为单位,一次所能处理的位数转为字节数,是全字长。另外还有双字长,半字长,
一个 64 位计算机中,全字长是 8 个字节(64) 位。双字长是 16 字节,半字长是 4 字节。
可以这样理解。在 32 位系统中 ,全字长 4 字节, 半字长 2 字节,双字长 8 字节。
short 是 半字长(2字节), long 是全字长(4字节),double 是双字长。

一般一个字节的位,是高位在左,低位在右。多个字节是高字节在左,低字节在右。

在 寄存器 和 内存中,如果 都是高位在左和低位在右,则称为小端存储。一个 long 转为 int ,只有低位的 2/4 个字节被 int 接收。union 中变量共享内存,低位会互相影响。

void指针

就好像 C# 或 java 的 object。

object a = new MyClass();
int b = (MyClass)a.Test();

void 指针可以指向任何类型变量地址。
但是要使用此地址的值,必须先转为对应类型的指针类型。

#include <stdio.h>

int main() {

    char a = 'a';
    int b = 0;

    void* p = &a;
    printf("%d", *(char*)p);

    p = &b;
    printf("\n");
    printf("%d", *(int*)p);
}
点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注