3. 數值字元串轉換函數

#include <stdlib.h>

int atoi(const char *nptr);
double atof(const char *nptr);
返回值:轉換結果

atoi把一個字元串開頭可以識別成十進制整數的部分轉換成int型,相當於下面要講的strtol(nptr, (char **) NULL, 10);。例如atoi("123abc")的返回值是123,字元串開頭可以有若干空格,例如atoi(" -90.6-")的返回值是-90。如果字元串開頭沒有可識別的整數,例如atoi("asdf"),則返回0,而atoi("0***")也返回0,根據返回值並不能區分這兩種情況,所以使用atoi函數不能檢查出錯的情況。下面要講的strtol函數可以設置errno,因此可以檢查出錯的情況,在嚴格的場合下應該用strtol,而atoi用起來更簡便,所以也很常用。

atof把一個字元串開頭可以識別成浮點數的部分轉換成double型,相當於下面要講的strtod(nptr, (char **) NULL);。字元串開頭可以識別的浮點數格式和C語言的浮點數常量相同,例如atof("31.4 ")的返回值是31.4,atof("3.14e+1AB")的返回值也是31.4。atof也不能檢查出錯的情況,而strtod可以。

#include <stdlib.h>

long int strtol(const char *nptr, char **endptr, int base);
double strtod(const char *nptr, char **endptr);
返回值:轉換結果,出錯時設置errno

strtolatoi的增強版,主要體現在這幾方面:

回想一下使用fopen的套路if ( (fp = fopen(...)) == NULL) { 讀取errno }fopen在出錯時會返回NULL,因此我們知道需要讀errno,但strtol在成功調用時也可能返回0x7fffffff,我們如何知道需要讀errno呢?最嚴謹的做法是首先把errno置0,再調用strtol,再查看errno是否變成了錯誤碼。Man Page上有一個很好的例子:

例 25.10. strtol的出錯處理

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

int main(int argc, char *argv[])
{
	int base;
	char *endptr, *str;
	long val;

	if (argc < 2) {
		fprintf(stderr, "Usage: %s str [base]\n", argv[0]);
		exit(EXIT_FAILURE);
	}

	str = argv[1];
	base = (argc > 2) ? atoi(argv[2]) : 10;

	errno = 0;    /* To distinguish success/failure after call */
	val = strtol(str, &endptr, base);

	/* Check for various possible errors */

	if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
	    || (errno != 0 && val == 0)) {
		perror("strtol");
		exit(EXIT_FAILURE);
	}

	if (endptr == str) {
		fprintf(stderr, "No digits were found\n");
		exit(EXIT_FAILURE);
	}

	/* If we got here, strtol() successfully parsed a number */

	printf("strtol() returned %ld\n", val);

	if (*endptr != '\0')        /* Not necessarily an error... */
		printf("Further characters after number: %s\n", endptr);

	exit(EXIT_SUCCESS);
}

strtodatof的增強版,增強的功能和strtol類似。