校验:_stund
自豪地采用谷歌翻译
使用printf
。第一个参数是格式字符串,其中包含要打印的数据的占位符。通用格式说明符是%s
将参数视为 c 字符串指针,保持打印所有字符,直到达到 NULL 字符; %d
将参数打印为整数; %p
将参数打印为内存地址。
一个简单的例子如下所示:
char *name = ... ; int score = ...;
printf("Hello %s, your result is %d\n", name, score);
printf("Debug: The string and int are stored at: %p and %p\n", name, &score );
// name已经是一个字符串指针,指向字符串的开头第一个字节的地址。
// 我们需要用“&”操作符来获取整数变量score的地址。
默认情况下,为了提高性能,printf
实际上不会写出任何内容(通过调用 write),直到其缓冲区已满或打印出换行符。
使用puts( name );
和putchar( c )
,其中 name 是指向 C 字符串的指针,c 只是char
使用fprintf( _file_ , "Hello %s, score: %d", name, score);
其中 file 是预定义的'stdout''stderr'或fopen
或fdopen
返回的 FILE 指针
是!只需使用dprintf(int fd, char* format_string, ...);
只记得可以缓冲流,因此您需要确保将数据写入文件描述符。
使用sprintf
或更好snprintf
。
char result[200];
int len = snprintf(result, sizeof(result), "%s:%d", name, score);
~~snprintf 返回写入的字符数,不包括终止字节。在上面的例子中,这最多为 199。~~snprintf 返回有足够的空间写入字符串的长度,不包括末尾NULL字节。
char x[5];
int size = snprintf(x, 5, "%s%s%s", "12", "34", "56"); // writes "1234" + null
printf("%d\n", size); // output 6
使用fflush( FILE* inp )
。将写入文件的内容。如果我想写没有换行的“Hello World”,我可以像这样写。
int main(){
fprintf(stdout, "Hello World");
fflush(stdout);
return 0;
}
假设您有一个失败的函数调用(因为您检查了手册页,它是一个失败的返回码)。 perror(const char* message)
会将错误的英文版本打印到 stderr
int main(){
int ret = open("IDoNotExist.txt", O_RDONLY);
if(ret < 0){
perror("Opening IDoNotExist:");
}
//...
return 0;
}
使用long int strtol(const char *nptr, char **endptr, int base);
或long long int strtoll(const char *nptr, char **endptr, int base);
。
这些函数的作用是将指针指向您的字符串*nptr
和base
(即二进制,八进制,十进制,十六进制等)和可选指针endptr
,并返回一个解析的 int。
int main(){
const char *num = "1A2436";
char* endptr;
long int parsed = strtol(num, &endptr, 16);
return 0;
}
但要小心!错误处理有点棘手,因为该函数不会返回错误代码。如果你传入一个会返回0的字符串而不是一个数字,这意味着你不能区别出一个合格的“0”和一个不合格的字符串。查看参考手册页去获得更多的关于strtol的不合法行为和超出边界的值。一个安全的替代是使用sscanf
(并且检查返回值)。
int main(){
const char *input = "0"; // or "!##@" or ""
char* endptr;
long int parsed = strtol(input, &endptr, 10);
if(parsed == 0){
// 不管输入的字符串是一个合格的10进制数还是真的是0
}
return 0;
}
使用scanf
(或fscanf
或sscanf
)分别从默认输入流,任意文件流或 C 字符串获取输入。检查返回值以查看解析了多少项是个好主意。 scanf
函数需要有效的指针。传递不正确的指针值是常见的错误来源。例如,
int *data = (int *) malloc(sizeof(int));
char *line = "v 10";
char type;
// 好习惯:确保scanf解析了line并读取了两个值
int ok = 2 == sscanf(line, "%c %d", &type, &data); // pointer error
我们想将字符值写入 c,将整数值写入 malloc 内存。但是我们传递了数据指针的地址,而不是指针指向的地址!所以sscanf
会改变指针本身。即,指针现在将指向地址 10,因此该代码稍后将失败,例如当调用 free(数据)时。
以下代码假定 scanf 不会将超过 10 个字符(包括终止字节)读入缓冲区。
char buffer[10];
scanf("%s",buffer);
您可以包含一个可选的整数来指定排除终止字节的字符数:
char buffer[10];
scanf("%9s", buffer); // 读取至多9个字符从输入(第十个字节是留给终止字节的)
以下代码容易受到缓冲区溢出的影响。它假定或信任输入行不超过 10 个字符,包括终止字节。
char buf[10];
gets(buf); // 请记住数组名代表着数组的第一个字节
gets
在 C99 标准中已弃用,已从最新的 C 标准(C11)中删除。程序应使用fgets
或getline
代替。
每个都分别具有以下结构:
char *fgets (char *str, int num, FILE *stream);
ssize_t getline(char **lineptr, size_t *n, FILE *stream);
这是一种简单,安全的读取单行的方法。超过 9 个字符的行将被截断:
char buffer[10];
char *result = fgets(buffer, sizeof(buffer), stdin);
如果出现错误或文件结束,则结果为 NULL。注意,与gets
不同,fgets
将换行符复制到缓冲区中,您可能要将其丢弃 -
if (!result) { return; /* no data - don't read the buffer contents */}
int i = strlen(buffer) - 1;
if (buffer[i] == '\n')
buffer[i] = '\0';
getline
的一个优点是将在足够大小的堆上自动(重新)分配缓冲区。
// ssize_t getline(char **lineptr, size_t *n, FILE *stream);
/* 初始化buffer和size的值,它们会被getline所改变 */
char *buffer = NULL;
size_t size = 0;
ssize_t chars = getline(&buffer, &size, stdin);
// 如果有换行符,就丢弃换行符
if (chars > 0 && buffer[chars-1] == '\n')
buffer[chars-1] = '\0';
// 读取另外一行
// 存在的缓冲区会被重复使用,如果有必要它会被释放并分配一个更大的缓冲区
chars = getline(&buffer, &size, stdin);
// 最后,不要忘了释放缓冲区内存
free(buffer);