C为什么形参是一个指向指针的指针,传一个指向int的指针实参进去也编译通过的???

踏踏步 发布于 2016/08/22 18:33
阅读 335
收藏 0

如下面代码,我想不通为什么形参是一个指向指针的指针,

传一个指向int的指针实参进去也编译通过的???,就好似strtol()函数,它的函数原型是

long strtol(const char * restrict nptr, char ** restrict endptr, int base )

在实际运用的时候输入了 未定义的char* end 作为实参都可以编译通过,这是什么回事啊

/* 使用strtol函数的例子,可以以某进制位数转换成十进制的数字输出  */
#include <stdio.h>
#include <stdlib.h>
#define LIM 30
char * s_gets(char * st, int n);

int main()
{
	char number[LIM];
	char * end;
	long value;

	puts("Enter a number:");
	while(s_gets(number, LIM) && number[0] != '\0')  /*如果用户输入Enter就结束程序*/
	{
		value = strtol(number, &end, 10);  /* base 10 */
		printf("base 10 input, base 10 output: %ld, stopped at %s (%d)\n",value, end, *end);
		puts("next num:");
	}
	puts("Bye!\n");

	return 0;
}
/*获取用户输入函数*/
char * s_gets(char * st, int n)
{
	char * ret_val;
	int i = 0;

	ret_val = fgets(st, n, stdin);
	if (ret_val)
	{
		while (st[i] != '\n' && st[i] != '\0')
			i++;
		if (st[i] == '\n')
			st[i] = '\0';
		else // must have words[i] == '\0'
			while (getchar() != '\n')
				continue;
	}
	return ret_val;
}



加载中
0
大止刀口
大止刀口

你大概可以这么理解,strtol这个函数其实是想返回2个值,一个转换后的long整数,另一个是指向后面未被识别的第一个字符(这个char指针就是end)。由于C语言只能返回一个值,定义strtol时又不想定义个一包含long和char*的新结构来作为返回值类型,所以干脆要一个char**来给end赋值,而end由调用strtol的人来给出。

不要传递其他类型的指针,大点的类型还好,如果太小会改写到该对象临近的内存。

endptr的用意我举个栗子,其实就是利用指针达到返回的效果,以下两种 i 都为7:

//第一种
int func(){return 7;}
int i = func();

//第二种
void func(int *rp){ *rp = 7; }
int i;
func(&i);



0
SVD
SVD

其实楼主说的

未定义的char* end 作为实参都可以编译通过

是因为char* end只需要声明一下,在函数的运行中,end将接收一个值,即函数返回的非法地址值,不过通常情况下,一般会默认设置成NULL.

对于char类型的指针输出即为字符串,因此对于接收参数endptr来说,即可以引用这些字符的地址即为指针的指针.即为双重指针.

这里传递的实参一定是char*,而不是int*.

#include <iostream>
using namespace std;

int main()
{
    char a[] = "hello";
    char *p = a;

    cout << "p = " << p << endl
         <<"p = " << (void *) p << endl
         << "*p = " << *p << endl;
        
        
    for(int i = 0 ; i < 5; i++)
    {
        cout << "&a[" << i << "] = "<< (void *)&a[i] << endl;
    }
    return 0;
}



注意字符数组和字符指针的特殊性.

0
踏踏步
踏踏步

引用来自“SVD”的评论

其实楼主说的

未定义的char* end 作为实参都可以编译通过

是因为char* end只需要声明一下,在函数的运行中,end将接收一个值,即函数返回的非法地址值,不过通常情况下,一般会默认设置成NULL.

对于char类型的指针输出即为字符串,因此对于接收参数endptr来说,即可以引用这些字符的地址即为指针的指针.即为双重指针.

这里传递的实参一定是char*,而不是int*.

#include <iostream>
using namespace std;

int main()
{
    char a[] = "hello";
    char *p = a;

    cout << "p = " << p << endl
         <<"p = " << (void *) p << endl
         << "*p = " << *p << endl;
        
        
    for(int i = 0 ; i < 5; i++)
    {
        cout << "&a[" << i << "] = "<< (void *)&a[i] << endl;
    }
    return 0;
}



注意字符数组和字符指针的特殊性.

对了! 可能我水平不高搞糊涂了,看到你提醒突然想起

"abc" 这样的字符串是一个指针喔!

char * pa = "abc"  //这是一个指向指针的指针好似没毛病喔!

返回char **类型也是对的

因为char **和char *[]等价,都是字符数组

谢谢你,谢谢各位,如果认同我的我就结贴了  : )

0
踏踏步
踏踏步

引用来自“士止刀口”的评论

你大概可以这么理解,strtol这个函数其实是想返回2个值,一个转换后的long整数,另一个是指向后面未被识别的第一个字符(这个char指针就是end)。由于C语言只能返回一个值,定义strtol时又不想定义个一包含long和char*的新结构来作为返回值类型,所以干脆要一个char**来给end赋值,而end由调用strtol的人来给出。

不要传递其他类型的指针,大点的类型还好,如果太小会改写到该对象临近的内存。

endptr的用意我举个栗子,其实就是利用指针达到返回的效果,以下两种 i 都为7:

//第一种
int func(){return 7;}
int i = func();

//第二种
void func(int *rp){ *rp = 7; }
int i;
func(&i);



谢谢回复,我有点不是很明白您说的

"不要传递其他类型的指针,大点的类型还好,如果太小会改写到该对象临近的内存。"

可以举个简单例子嘛

踏踏步
踏踏步
回复 @士止刀口 : 其实我打错了.不好意思哈,我以为你说的是好似泛型那种,不具体指明类型或是超出了字符数组大小那种野指针,,,
大止刀口
大止刀口
我是看到你这一句“传一个指向int的指针实参进去也编译通过的???,”。怕你真的用强制类型转换传个其他类型的指针过去。这个函数会改写这个char**指针指向的内存(也就是一个char*的值)。
返回顶部
顶部