C语言中char*和char[]用法区别分析

本文详细分析了C语言中char*与char[]的区别,包括它们的内存分配位置、可修改性及字符串操作行为。通过实例对比,解释了为何char*不能直接修改字符串内容,而char[]可以。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文实例分析了C语言中char * 和 char []的区别。分享给大家供大家参考之用。具体分析如下:

一般来说,很多人会觉得这两个定义效果一样,其实差别很大。以下是个人的一些看法,有不正确的地方望指正。

本质上来说,char *s定义了一个char型的指针,它只知道所指向的内存单元,并不知道这个内存单元有多大,所以:

当char *s = “hello”;后,不能使用s[0]=‘a’;语句进行赋值。这是将提示内存不能为"written"。

当用char s[]=“hello”;后,完全可以使用s[0]=‘a’;进行赋值,这是常规的数组操作。

若定义:

char s[] = "hello";
char *p = s;

也可以使用p[0] = ‘a’;因为这是p ==s,都是指向数组的指针。

下面看另外一种定义:

char *s = (char *)malloc(n);//其中n为要开辟空间的大小

这句话其实相当于:

char s[n];

定义的也是一个指向数组的指针,便可进行数组的下标操作

例子

#include <stdio.h>
 
int main(int argc, char* argv[]) {
char* buf1 = "this is a test";
char buf2[] = "this is a test";
printf("size of buf1: %d\n", sizeof(buf1));
printf("size of buf2: %d\n", sizeof(buf2));
return 0;
}

结果是:

$ > ./main
size of buf1: 4
size of buf2: 15

相信本文所述对大家C语言程序设计的学习有一定的借鉴价值。

可以看看评论:
1、循环该字符串.如果字符==’\0’.则到头了.
2、sizeof是看占用内存,你开了多大的内存sizeof就是多大,跟里面有没有数据无关,如果想看有多少内容,可以用strlen,不过strlen只可以看字符串”
3、说下 malloc开的内存在堆 而直接开 内存在栈 还是不要说它们一样比较好

参考:https://blog.csdn.net/qq_21794823/article/details/53316853


还可以看看这个例子:

C语言之对char*与char[]的理解

https://blog.csdn.net/liuchenxia8/article/details/79125846#commentBox

在我们学习的过程中,在定义字符串时常常会用char* 或者 char[]去定义一个字符串,可是这两个的区别却天差地别。
今天在这里我阐述一下自己对这两种定义的理解与看法。
首先分别用这两种方法定义字符串,如下。

char *str1 = "abcd1234";
char str2[] = "abcd1234";

接下来,我们分别对这两种方法定义的字符串进行测试。

 printf("%d  %d\n",str1,str2);

在这里插入图片描述

显而易见,这两种定义的方法在strlen的作用下的值是一样的,其字符串的长度并无差别。
再进行下面的测试。

    char *str1 = "abcd1234";
    char *str2 = "abcd1234";
    char str3[] = "abcd1234";
    char str4[] = "abcd1234";

    printf("%p %p\n",str1,str2);
    printf("%p %p\n",str3,str4);

如果这样运行的话,结果会是什么呢?
在这里插入图片描述

这是为什么呢?用char * 定义的两个内容一样的字符串的地址竟然是一样的,而char [] 这样定义的内容相同的字符串却不一样?
我们接下来继续看。

 char *str1 = "abcd1234";
 char str2[20] = "abcd1234";

 strncat(str1,str2,4);
 printf("%s\n",str1);

用strncpy来进行测试,意思为将str2的前四个字节的内容复制到str1中。我们来看看结果如何。

在这里插入图片描述

我们发现,程序直接崩溃掉了。如果这样来呢?

char *str1 = "abcd1234";
char str2[20] = "abcd1234";

strncpy(str2,str1,4);
printf("%s\n",str2);

在这里插入图片描述

此时,却可以正常的使用。那么之前的那些是什么原因导致的呢?
经过分析以及自己的理解,char str[]这里单独的str表示的是一个char类型的数组指针,该指针所指向的数组内容是保存在栈上面的,是可以修改的。而char *str是一个字符串指针,这个指针指向的是字符串第一个字符的地址,而这个指针存在栈上,但是字符串的内容并不在栈里面,而在字符常量区域里面储存。所以查看char *str1 = "abcd1234"与char *str2 = "abcd1234"的地址时,他们都是储存的字符a的地址,所以这个地址时相同的,所以其 %p 的值也是一样的,但是char str3[] = “abcd1234” 与 char str[] = "abcd1234"是分别两个char类型的数组,而str3与str4分别表示的是char型的数组指针,所以他们的地址时不同的。

char *str1 = "abcd1234";
char str2[20] = "abcd1234";

strncat(str1,str2,4);      

当我们测试以上代码时,由于在栈里面存储的仅有字符的地址,所以当进行字符串拼接时,首先在栈里面找不到str1中的"abcd1234"而这时的字符串在字符常量区,是无法修改的,所以出现了程序崩溃,报错。

char *str1 = "abcd1234";
char str2[20] = "abcd1234";

strncpy(str2,str1,4);
printf("%s\n",str2);    

而当我们测试上面的代码时,如果数组一样,利用指针的访问,是可以轻而易举的改变、修改、拼接str2,所以可以进行strncat的执行。

本人愚见,欢迎大家共同探讨研究,如果错误,请及时联系作者进行修改更正,谢谢大家!

评论:
感觉 还是编译器的原因,char * str str可以被赋值所以他就将字符串常量地址赋值给str,char str[] str理解为数组起始地址,无法赋值,他就把字符常量的值赋值给数组

补充几个小知识:
C语言中%p,%u,%lu都有什么用处?
%p表示输出这个指针,
%d表示后面的输出类型为有符号的10进制整形,
%u表示无符号10进制整型,
%lu表示输出无符号长整型整数 (long unsigned)

C语言中的%p和%x的区别
格式控制符“%p”中的p是pointer(指针)的缩写。指针的值是语言实现(编译程序)相关的,但几乎所有实现中,指针的值都是一个表示地址空间中某个存储器单元的整数。printf函数族中对于%p一般以十六进制整数方式输出指针的值,附加前缀0x。
示例:
int i = 1;
printf("%p",&i);
相当于
int i = 1;
printf(“0x%x”,&i);
对于32位的指针,输出一般会是类似0xf0001234之类的结果。


https://zhidao.baidu.com/question/304407402.html?sort=11&rn=5&pn=0#wgt-answers
C语言中,控制printf函数输出格式的是格式字符,printf没有直接打出2进制数的格式符,直接打出16进制的格式符是x格式符,即%x。

printf函数中输出的格式为printf("<格式化字符串>", <参量表>),格式化字符串由格式控制、和输出表列两部分组成,其中格式控制包含格式声明和普通字符。

格式声明由“%”和格式字符组成,如%d、%f等。它的作用是将输出的数据类型转换为指定的格式然后输出。普通字符是需要在输出时原样输出的字符。
在这里插入图片描述
扩展资料

C语言printf函数格式字符:

1、%d,按整型数据的实际长度输出。

2、%md,m为指定的输出字段的宽度。

3、%ld,输出长整型数据。

4、o格式符,以八进制整型式输出整数。

5、x格式符,以十六进制数形式输出整数。

6、u格式符,用来输出unsigned型数据,即无符号数,以十进制形式输出。

7、c格式符,用来输出一个字符。

8、s格式符,用来输出一个字符串。

9、f格式符,用来输出实数(包括单双精度),以小数形式输出。

10、e格式符,以指数形式输出实数。

11、g格式符,用来输出实数,它根据数值的大小,自动选f格式或e格式(选择输出是占宽度较小的一种),且不输出无意义的零。

12、p格式符,用于变量地址的输出。

13、%[scanfset]:

scanfset 有两种形式:一种是以非 “^” 字符开头的 scanset , 表示在读入字符串时将匹配所有在 scanfset 中出现的字符,遇到非scanfset 中的字符时输入就结束;

另外一种形式是以 “^” 字符开头的scanfset ,表示在读入字符串时将匹配所有不在scanfset 中出现的字符,遇到scanfset 中的字符输入就结束。

参考资料来源:百度百科——格式字符


d 有符号10进制整数   i 有符号10进制整数   o 无符号8进制整数   u 无符号10进制整数   x 无符号的16进制数字,并以小写abcdef表示   X 无符号的16进制数字,并以大写ABCDEF表示
二进制的好像没有……


printf没有直接输出 2 进制的参数, 16进制可以,不过可以自己写一个,比如,下面是输出 整数的 二进制。

void print_2(int val2)
{
unsigned char *p = (unsigned char*)&val2 + 3; //从低位到高位,低端字节计算机
for(int k = 0; k <= 3; k++)
{
int val2 = *(p-k);
for (int i = 7; i >= 0; i--)
{
if(val2 & (1 << i))
printf("1");
else
printf("0");
}
printf(" ");
}
}

在C语言中,打印16进制可以使用printf的%x格式。

打印二进制数并没有现成的格式数值,只能自行编写函数打印。

以下是一个打印二进制值的函数,通过位操作,逐位判断二进制值,并输出对应的值。

默认高位0不输出。

void print_bin(int n)
{
    int l = sizeof(n)*8;//总位数。
    int i;
    if(i == 0)
    {
         printf("0");
         return;
     }
    for(i = l-1; i >= 0; i --)//略去高位0.
    {
        if(n&(1<<i)) break;
    }
 
    for(;i>=0; i --)
        printf("%d", (n&(1<<i)) != 0);
}

二进制,印象中没有,可以用其他库函数实现


16进制是%x那个x可大写可小写
2进制没有,需要自己转换


16进制是%x那个x可大写可小写
2进制没有,需要自己转换


二进制好像没有
十六进制 为X 或x
如 printf("%X",12)为 C
printf("%x",12) 为c


直接打出二进制的没有,16进制是x%.


C语言中 %02X 是什么意思
表示以16进制的格式输出整数类型的数值,输出域宽为2,右对齐,不足的用字符0替代。
示例程序如下:

#include <stdio.h>
int main()
{
    int a=15;
    printf("%02X\n",a);
    printf("%03X\n",a);
    printf("%04X\n",a);
    return 0;
}

运行结果为:
0F

00F

000F

这里还有一份冗长的linux解析版,非常详细:
https://blog.csdn.net/sunbo94/article/details/80210243

两个论坛,可供消遣:
https://bbs.csdn.net/topics/392215053
https://bbs.csdn.net/topics/390676437

为了加深理解,我这里也放出自己的代码:

#include<string.h>
#include <stdio.h>
int main(void) {
	char *str1 = "abcd1234";
	char str2[] = "abcd1234";
	printf("%o  %o\n",str1,&str2);
	printf("%o  %o\n",&str1,str2);
	str1[0] = 'd';

	str1 = str2;
	str1[0] = 'd';
	printf("%s   %s", str1,str2);

}


    #include<string.h>
    #include <stdio.h>
    int main(void) {
	char *str1 = "abcd1234";
	char *str2 = "abcd1234";
	printf("%o  %o\n",str1,&str2);
	printf("%o  %o\n",&str1,str2);
	str1[0] = 'd';

	str1 = str2;
	str1[0] = 'd';
	printf("%s   %s", str1,str2);

}


    #include<string.h>
    #include <stdio.h>
    int main(void) {
	char str1[] = "abcd1234";
	char str2[] = "abcd1234";
	printf("%o  %o\n",str1,&str2);
	printf("%o  %o\n",&str1,str2);
	str1[0] = 'd';

	//str1 = str2;
	str1[0] = 'd';
	printf("%s   %s", str1,str2);

}

总结几点:

1、数组名与指针,虽然都是代表地址,但他们也有不同,数组名更特殊,但指针的使用更加灵活,可以指向堆区内存,也可以指向常量区,甚至可以指向数组(此时数组与指针就没有区别了)。并且上例中,数组名与&数组名输出结果一样,应该是编译器做过转换的,实际上它是一个新的二级行指针了,但是他的首地址还是它自身罢了。你可以尝试用它去给一个一级,或者二级指针赋值,它会报错,实际上是一种强制类型转换。可以参见:https://www.cnblogs.com/mq0036/p/3382732.html ,加深理解。
2、当指向常量区,如字符串时,是不可以使用索引[]更改值的,而数组去却一样,要想使用指针修改元素,可以将指针指向数组,或者另行开辟内存区。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值