char*str与char str[]的差异。

本文探讨了C语言中指针使用常见的错误案例,包括尝试将未初始化的指针直接用于读取输入或存储数据等问题,并给出了正确的做法。

下面是几个错的例子:

1

# include <stdio.h>
int main(void)
{
	char *str;
	scanf("%s",str); //error
	return 0;
}


2

# include <stdio.h>
int main(void)
{
	char *str;
	gets(str); //error
	return 0;
}

3

# include <stdio.h>
# include <stdlib.h>
int main(int argc,char* argv[])
{
	FILE*fp=NULL;
	char*str;
	if((fp=fopen(argv[1],"r"))==NULL)
	{
		printf("file open error!\n");
		exit(1);
	}
	
	fgets(str,4,fp);  //error
	
	fclose(fp);
	fp=NULL;
	puts(str);
	return 0;
}

归纳:

上面的程序都有一个共同点,那就是试图从流中读取一个字符串放到str中。这3个程序都是错误的。

为什么不可以这样?

答:定义的str字符指针,他的值对应的内存空间是不确定的,或者说它的空间是不可用的,就好比int a;

此时的a是一个不可预测的垃圾值一样,把a拿来直接用不能达到我们的目的,那么我们就可以为a赋值,

在来利用a。同样,要想把str变的可用,可以用malloc(或者calloc)为其申请一块一定大小的内存给他,就OK了。

当然,如果你只给str申请了 2个字节的空间,而你却把5个字节大小的字符串放进去,这又是另一种错误,

越界。

所以,上面的3个程序,加上:str=(char*)malloc(sizeof(char)*n)


引申:(下面的程序也是同样的错误)


 

# include <stdio.h>
int main(void)
{
	int *p;
        *p=5; //error
	return 0;
}

      

# include <stdio.h>
int main(void)
{
	char *p;
	*p='a';
	return 0;
}

总结:

       定义的指针变量是不能直接拿来存放数据的,它没有有效的空间,使用前应为其动态分配内存等方法,

   让他指向有效内存空间

    

      引用:Stephen Prata 著 《C prime  plus 》P263 

         “  切记:当创建一个指针的时候,系统只分配了用来存储指针本身的内存空间,并不分配存储数据的内存空间

             因此在使用指针变量之前,必须给它赋予一个已分配的内存地址。


另一个问题:

问:为什么把char*str换成char str[10];这样也可以避免上述的错误呢?

答:此时是把str定义为一个长度为10的数组,那么,str这个数组从一定义就拥有10个字节的内存空间,

他可以指向对应长度的字符数组,无需为其分配空间。


总结:

通过指针去存放数据,要保证这个指针指向有效空间。


另外,char*str=“i am a boy” 与char str[6]="i am a boy"  的区别


1:char*str=“i am a boy”

说明:str在栈里,他是一个指针变量,本身也占用内存,但是他不支配有效内存空间。“i am a boy”是一个常量,

他在静态储存区。

=号的意义是:把“i am a boy”这个数组常量的首地址赋值给str(初始化str),这样str就指向字符数组了。


2:char str[]="i am a boy"  

说明:str[6]="i am a boy" 整个都在栈里,他相当于:str[6]={ ' i ' , ' ' , 'a' , ' m' ,' ', 'a' ,'b' ,'o'  ,'y'}。

str本身支配11个字节的空间。 




最后:再上2个图,说明栈区和常量区的区别









个人心得,有错欢迎提出。

<think>首先,用户的问题是关于C语言中的函数声明的区别:他想理解“char*fun(char*str1,char*str2)”和“char(*pfun)(char*str1,char*str2)”的区别。用户提供了一些引用作为参考:-引用[1]:涉及函数指针数组和指向函数指针数组的指针的代码。-引用[2]:字符串复制函数使用字符数组参数。-引用[3]:讨论字符串常量和指针。-引用[4]:不同类型指针的区别,包括指针数组和数组指针。-引用[5]:C语言指针类型,包括基类型和指针变量的类型。用户说这些引用仅供参考,并不是用户真正的需求,并提醒我参考用户上一次的问题和我的回答。系统显示的上一次用户问题是“我想理解两种函数声明的区别”,所以在我的响应中,我需要专注于解答这个具体问题。根据系统指令:-所有行内数学表达式必须使用$...$,但由于这是C语言代码,不是数学,所以我可能不需要数学格式。问题中没有涉及数学表达式,所以我应该避免不必要的LaTeX。-独立公式必须用$$...$$,但这里可能不需要。-LaTeX语法正确。-使用中文回答。-生成相关问题。-回答中引用的段落末尾自然地添加引用标识。-结构清晰,逐步解决问题。-保证回答真实可靠。关键部分是解释这两种声明的区别:1.`char*fun(char*str1,char*str2)`-这是一个函数声明。-函数名为fun。-返回值类型是char*(指向char的指针)。-参数是两个char*(指向char的指针)。-所以,fun是一个函数,它接受两个字符串指针并返回一个字符串指针。2.`char(*pfun)(char*str1,char*str2)`-这是一个指针声明。-它的核心是`(*pfun)`,表示pfun是一个指针。-后面的`(char*str1,char*str2)`指定了这个指针指向一个函数的类型。-所以,pfun是一个指向函数的指针,这个函数接受两个char*参数并返回char*。总结区别:-第一个是函数声明,定义了函数fun。-第二个是函数指针声明,定义了指针pfun,它可以指向类似fun的函数。参考用户提供的引用:-引用[1]中提到了函数指针数组和指向函数指针数组的指针。它演示了如何使用函数指针,如`char*(*a[3])(char*p)`。这相关,因为用户的问题涉及函数指针。-引用[4]讨论指针数组和数组指针,这和函数指针类似。-引用[5]解释指针类型,包括函数指针的类型。在回答中,我应该:1.用中文清晰地解释这两种声明的语法和含义。2.使用代码示例来展示它们的使用。3.如果需要,添加引用标识到相关部分。4.结构:-先解释第一个声明。-再解释第二个声明。-比较区别。-给出完整示例。5.生成相关问题。确保回答真实可靠:我基于我的C语言知识回答,这是标准的。最终,生成相关问题:-相关问题可以是C语言相关的扩展问题。用中文回答。</think> ### C语言中函数声明函数指针声明的区别 用户的问题涉及两种C语言声明:`char *fun(char*str1, char*str2)` 和 `char (*pfun)(char*str1, char*str2)`。以下是逐步分析它们的区别,基于C语言的语法规则和引用知识。 #### 1. `char *fun(char*str1, char*str2)`:函数声明 - **语法解释**: - 这是一个标准函数声明。 - `char *`:函数的返回类型是指向字符的指针(例如,一个字符串)。 - `fun`:函数名。 - `(char*str1, char*str2)`:参数列表,包含两个参数,每个参数是`char*`类型(即指向字符的指针,常用于字符串操作)。 - 整体含义:声明了一个名为`fun`的函数,它接受两个字符串指针作为输入,并返回一个字符串指针。 - **代码示例和用法**: ```c #include <stdio.h> char* fun(char* str1, char* str2) { // 示例实现:拼接字符串(实际应用中需要避免缓冲区溢出) static char result[100]; // 使用静态数组存储结果 sprintf(result, "%s %s", str1, str2); return result; // 返回静态数组的地址 } int main() { char* result = fun("Hello", "World"); // 调用函数 printf("%s\n", result); // 输出: Hello World return 0; } ``` - 这个函数可以直接调用,如`fun("str1", "str2")`。 - 注意:在引用[2]中,函数`copy_string`以数组作为参数,类似这里的字符串指针参数,它们都通过地址传递数据[^2]。 - **类型信息**: - `fun`的类型是函数类型:`char (*)(char*, char*)`(在编译器的类型系统中,函数本身也有类型,但变量不能直接持有函数类型)。 #### 2. `char (*pfun)(char*str1, char*str2)`:函数指针声明 - **语法解释**: - 这是一个函数指针声明。 - `(*pfun)`:`pfun`是一个指针变量。括号`(*)`表示指针操作。 - `char (*)(char*str1, char*str2)`:指针指向的类型。具体来说,`pfun`可以指向任何返回`char*`、接受两个`char*`参数的函数。 - 整体含义:声明了一个名为`pfun`的指针变量,它可以存储指向特定类型函数的地址。 - **代码示例和用法**: ```c #include <stdio.h> char* fun1(char* str1, char* str2) { printf("%s\n", str1); // 示例函数1 return str1; } char* fun2(char* str1, char* str2) { printf("%s\n", str2); // 示例函数2 return str2; } int main() { // 声明函数指针pfun char (*pfun)(char*, char*); // pfun指向返回char*、参数为(char*, char*)的函数 pfun = fun1; // 将函数fun1的地址赋值给指针 pfun("Hello", "World"); // 输出: Hello pfun = fun2; // 指向fun2 pfun("Hello", "World"); // 输出: World return 0; } ``` - 函数指针常用于回调、函数表或动态绑定(例如,引用[1]中`char* (*a[3])(char* p)`定义了一个函数指针数组[^1])。 - 在引用[4]中,指针的类型(如`char*`)会影响内存行为,函数指针类型必须精确匹配目标函数的签名[^4]。 #### 3. 关键区别总结 | 方面 | `char *fun(char*str1, char*str2)` | `char (*pfun)(char*str1, char*str2)` | |---------------------|-----------------------------------|---------------------------------------| | **本质** | 函数声明(定义函数体) | 指针声明(存储函数地址) | | **行为** | 声明一个可调用的函数实体 | 声明一个变量(指针),可指向任何匹配签名的函数 | | **使用场景** | 用于直接函数定义和调用 | 用于动态函数调用、回调机制或函数指针数组 | | **存储方式** | 函数代码在内存中 | 指针变量存储在或堆中,其值是一个函数地址 | | **类型检查** | 函数本身的类型在编译时确定 | 指针类型必须严格匹配函数签名(例如,返回类型和参数) | - **深入理解**: - 函数类型不能直接赋值给变量(C语言中函数名隐式转换为地址,但类型是`函数名`本身)。 - 函数指针类型(如`char (*)(char*, char*)`)允许间接调用函数,这在引用[5]中被解释为“基类型”,指针变量`pfun`的类型依赖于指向函数的返回值和参数类型[^5]。 - 在引用[3]中,字符串指针操作展示了指针如何存储地址[^3],函数指针类似。 #### 4. 完整代码示例 以下是一个综合示例,展示两者如何协同工作: ```c #include <stdio.h> // 函数声明 char* concat_str(char* str1, char* str2) { static char res[100]; sprintf(res, "%s%s", str1, str2); return res; } int main() { // 函数调用 (直接) char* direct_result = concat_str("Hello", "C"); printf("直接调用结果: %s\n", direct_result); // 输出: HelloC // 函数指针声明和使用 char (*pfun)(char*, char*) = &concat_str; // 函数地址赋值 char* ptr_result = pfun("Function ", "Pointer"); printf("指针调用结果: %s\n", ptr_result); // 输出: Function Pointer return 0; } ``` #### 注意事项 - 函数指针语法要求括号:`(*pfun)`确保`pfun`被解释为指针,而不是函数返回指针(如`char *pfun(...)`会是错误声明)。 - 在内存中,函数指针的值是函数入口地址(类似于引用[1]中`pf = &a`的操作[^1])。 - 如果您在代码中遇到字符串常量问题(如引用[3]),确保函数指针的签名目标函数一致,以避免运行时错误[^3]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值