C 程序将标准输出的小写字母转换为大写字母的小问题
Small Issue with C program to convert lowercase to uppercase for stdout
我正在学习 linux 中的系统调用,我编写了一个快速程序来将 stdin 复制到 stdout。
我想在写入标准输入之前将小写字母转换为大写字母。
我用一个指向数组的指针实现了一个函数来将字符大写。它只大写了 write 的第一个字母,我不明白为什么。据我了解,由于 read() 系统调用,我不需要 for 循环。
#include <unistd.h>
#define SIZE 512
char charToUpper(char *);
int main () {
int nread;
char buf[SIZE];
while (nread = read(0, buf , SIZE)) {
charToUpper(buf);
write(1,buf,nread);
}
return 0;
}
char charToUpper(char *a){
if ((*a > 96) && (*a <123)) {
*a = *a-32;
return *a;
}
}
你的 charToUpper
收到一个指向 char
的指针,你发送它 buf
,它衰减到指向 char
中第一个字符的指针=13=],因此你的结果。
请记住,在 c
中,您无法免费获得要传递的数组的大小 - 您还必须传递它。考虑你在 charToUpper
中的所有操作都在 *a
上,它是 char
类型,单个字符。因此,要解决此问题,请将声明更改为
char charToUpper(char *, unsigned int size);
所以知道你知道你实际阅读了多少字符并且需要更改。现在尝试更改您的程序以适应这种情况。一个提示 - 例如,您的 return
可能需要移动。
除了循环部分,程序完全没问题。
char* charToUpper(char *a){
char *t=p;
while(*a!='[=10=]'){
if ((*a > 96) && (*a <123))
*a = *a-32;
a++;
}
return t;
}
你没有增加循环。这样做你会得到
建议代码如下:
- 干净地编译
- 正确终止输入字符数组
- 使用工具将所有小写字符正确更改为大写:
toupper()
来自头文件:ctype.h
- 执行所需的功能
现在,建议的代码:
#include <unistd.h>
#include <ctype.h> // toupper()
#define SIZE 512
void charToUpper(char *);
int main ( void )
{
ssize_t nread;
char buf[SIZE];
while ( (nread = read(0, buf , SIZE) ) > 0)
{
// NUL terminate the character string
buf[nread] = '[=10=]';
// convert all characters to uppercase
charToUpper(buf);
// output the (all uppercase) string to stdout
write(1,buf, (size_t)nread);
}
return 0;
}
void charToUpper( char buf[] )
{
for( size_t i = 0; buf[i]; i++ )
{
buf[i] = (char)toupper( buf[i] );
}
}
好吧,你已经把事情复杂化了,你自己缓冲输入数据,而你可以使用 getchar()
和 putchar()
已经缓冲的函数。同样使用数字而不是字符文字,隐藏代码的实际 objective(转换为大写,反对在代码中添加减去奇怪的魔法值),并将其也与 ASCII 字符代码环境相关联:
#include <stdio.h>
int main()
{
int c;
while((c = getchar()) != EOF) {
if (c >= 'a' && c <= 'z') /* char literals are your friends */
c += 'A' - 'a'; /* also here */
putchar(c);
}
return 0;
}
这段代码将完全按照您的尝试进行操作,透明地缓冲输入和输出,并以一种可移植到具有不同字符编码的其他环境的方式。毫无疑问,更好的方法是:
#include <stdio.h>
#include <ctype.h>
int main()
{
int c;
while((c = getchar()) != EOF) {
putchar(toupper(c));
}
return 0;
}
如果你用一个大的文本文件测试这两个程序,你会发现这个程序的响应比你写的要好,因为标准库已经自动为你选择了最佳的读写缓冲区大小,基于传递给它的文件描述符,而不是您在程序中使用的固定缓冲区大小(512 字节)。
在你的代码中,你将缓冲区指针传递给你的函数,它只将它的第一个字符大写......仅此而已,所以你只会得到每行的第一个字符(以防万一您的输入来自终端,因为在规范模式下从终端读取时输入在每一行结束)或每个 512 字节块的第一个字符,以防您从文件中读取。
为了让你的函数工作,你应该传递缓冲区,它的大小,因为读取数据的实际数量在里面是未知的,你需要在里面放一个 for
循环来处理每个字符...或在函数外部进行循环,并为缓冲区的每个字符位置调用函数,由 read(2)
.
填充
如果你想自己缓冲,如示例代码所示,你必须将读取字符的实际长度放入例程中并转换传递的数量,如:
#include <unistd.h>
#include <stdio.h> /* for printing errors to stderr */
#include <string.h> /* for strerror */
#include <errno.h> /* for errno definition */
#define SIZE 512
void charToUpper(char *, size_t);
int main () {
ssize_t nread, nwritten;
char buf[SIZE];
while ((nread = read(0, buf , SIZE)) > 0) {
charToUpper(buf, nread);
nwritten = write(1, buf, nread);
if (nwritten < 0) { /* check for writing errors */
fprintf(stderr,
"Error: write: %s\n",
strerror(errno));
return 1; /* write error */
}
}
if (nread < 0) { /* check for reading errors */
fprintf(stderr,
"Error: read: %s\n",
strerror(errno));
return 2; /* read error */
}
return 0; /* no error */
}
void charToUpper(char *a, size_t sz){ /* better declare it void, as we don't return anything */
/* this code assumes uppercase chars and lower case are together in the
* char map, and contiguous (this is false in EBCDIC mappings) so better
* to use toupper(*a) in all cases */
for(;sz--; a++) { /* for every char in a, up to sz chars. */
if ((*a >= 'a') && (*a <= 'z')) { /* if *a is lower case letter */
*a += 'A' - 'a'; /* convert to uppercase */
/* better if you use *a = toupper(*a); */
}
}
}
我正在学习 linux 中的系统调用,我编写了一个快速程序来将 stdin 复制到 stdout。
我想在写入标准输入之前将小写字母转换为大写字母。
我用一个指向数组的指针实现了一个函数来将字符大写。它只大写了 write 的第一个字母,我不明白为什么。据我了解,由于 read() 系统调用,我不需要 for 循环。
#include <unistd.h>
#define SIZE 512
char charToUpper(char *);
int main () {
int nread;
char buf[SIZE];
while (nread = read(0, buf , SIZE)) {
charToUpper(buf);
write(1,buf,nread);
}
return 0;
}
char charToUpper(char *a){
if ((*a > 96) && (*a <123)) {
*a = *a-32;
return *a;
}
}
你的 charToUpper
收到一个指向 char
的指针,你发送它 buf
,它衰减到指向 char
中第一个字符的指针=13=],因此你的结果。
请记住,在 c
中,您无法免费获得要传递的数组的大小 - 您还必须传递它。考虑你在 charToUpper
中的所有操作都在 *a
上,它是 char
类型,单个字符。因此,要解决此问题,请将声明更改为
char charToUpper(char *, unsigned int size);
所以知道你知道你实际阅读了多少字符并且需要更改。现在尝试更改您的程序以适应这种情况。一个提示 - 例如,您的 return
可能需要移动。
除了循环部分,程序完全没问题。
char* charToUpper(char *a){
char *t=p;
while(*a!='[=10=]'){
if ((*a > 96) && (*a <123))
*a = *a-32;
a++;
}
return t;
}
你没有增加循环。这样做你会得到
建议代码如下:
- 干净地编译
- 正确终止输入字符数组
- 使用工具将所有小写字符正确更改为大写:
toupper()
来自头文件:ctype.h
- 执行所需的功能
现在,建议的代码:
#include <unistd.h>
#include <ctype.h> // toupper()
#define SIZE 512
void charToUpper(char *);
int main ( void )
{
ssize_t nread;
char buf[SIZE];
while ( (nread = read(0, buf , SIZE) ) > 0)
{
// NUL terminate the character string
buf[nread] = '[=10=]';
// convert all characters to uppercase
charToUpper(buf);
// output the (all uppercase) string to stdout
write(1,buf, (size_t)nread);
}
return 0;
}
void charToUpper( char buf[] )
{
for( size_t i = 0; buf[i]; i++ )
{
buf[i] = (char)toupper( buf[i] );
}
}
好吧,你已经把事情复杂化了,你自己缓冲输入数据,而你可以使用 getchar()
和 putchar()
已经缓冲的函数。同样使用数字而不是字符文字,隐藏代码的实际 objective(转换为大写,反对在代码中添加减去奇怪的魔法值),并将其也与 ASCII 字符代码环境相关联:
#include <stdio.h>
int main()
{
int c;
while((c = getchar()) != EOF) {
if (c >= 'a' && c <= 'z') /* char literals are your friends */
c += 'A' - 'a'; /* also here */
putchar(c);
}
return 0;
}
这段代码将完全按照您的尝试进行操作,透明地缓冲输入和输出,并以一种可移植到具有不同字符编码的其他环境的方式。毫无疑问,更好的方法是:
#include <stdio.h>
#include <ctype.h>
int main()
{
int c;
while((c = getchar()) != EOF) {
putchar(toupper(c));
}
return 0;
}
如果你用一个大的文本文件测试这两个程序,你会发现这个程序的响应比你写的要好,因为标准库已经自动为你选择了最佳的读写缓冲区大小,基于传递给它的文件描述符,而不是您在程序中使用的固定缓冲区大小(512 字节)。
在你的代码中,你将缓冲区指针传递给你的函数,它只将它的第一个字符大写......仅此而已,所以你只会得到每行的第一个字符(以防万一您的输入来自终端,因为在规范模式下从终端读取时输入在每一行结束)或每个 512 字节块的第一个字符,以防您从文件中读取。
为了让你的函数工作,你应该传递缓冲区,它的大小,因为读取数据的实际数量在里面是未知的,你需要在里面放一个 for
循环来处理每个字符...或在函数外部进行循环,并为缓冲区的每个字符位置调用函数,由 read(2)
.
如果你想自己缓冲,如示例代码所示,你必须将读取字符的实际长度放入例程中并转换传递的数量,如:
#include <unistd.h>
#include <stdio.h> /* for printing errors to stderr */
#include <string.h> /* for strerror */
#include <errno.h> /* for errno definition */
#define SIZE 512
void charToUpper(char *, size_t);
int main () {
ssize_t nread, nwritten;
char buf[SIZE];
while ((nread = read(0, buf , SIZE)) > 0) {
charToUpper(buf, nread);
nwritten = write(1, buf, nread);
if (nwritten < 0) { /* check for writing errors */
fprintf(stderr,
"Error: write: %s\n",
strerror(errno));
return 1; /* write error */
}
}
if (nread < 0) { /* check for reading errors */
fprintf(stderr,
"Error: read: %s\n",
strerror(errno));
return 2; /* read error */
}
return 0; /* no error */
}
void charToUpper(char *a, size_t sz){ /* better declare it void, as we don't return anything */
/* this code assumes uppercase chars and lower case are together in the
* char map, and contiguous (this is false in EBCDIC mappings) so better
* to use toupper(*a) in all cases */
for(;sz--; a++) { /* for every char in a, up to sz chars. */
if ((*a >= 'a') && (*a <= 'z')) { /* if *a is lower case letter */
*a += 'A' - 'a'; /* convert to uppercase */
/* better if you use *a = toupper(*a); */
}
}
}