Небольшая проблема с программой на C для преобразования строчных букв в прописные для stdout - PullRequest
0 голосов
/ 04 октября 2019

Я изучаю системные вызовы в Linux и написал быструю программу для копирования стандартного ввода в стандартный вывод.

Я хочу преобразовать строчные буквы стандартного ввода в прописные, прежде чем они будут написаны.

Я реализовал функцию с указателем на массив для заглавных букв. Это только заглавная буква первого письма, хотя я не понимаю, почему. Из того, что я понимаю, мне не понадобится цикл for из-за системного вызова read ().

#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;
    }
}

Ответы [ 4 ]

1 голос
/ 04 октября 2019

Ваш charToUpper получает указатель на char, и вы отправили его buf, который затухает до указателя на char первого символа в buf, отсюда ваш результат.

Помните, что в c вы не получаете размер массива, который вы передаете бесплатно - вы также должны передать его. Учтите, что все ваши операции в charToUpper выполняются на *a, который имеет тип char, один символ. Чтобы исправить это, измените объявление на

char charToUpper(char *, unsigned int size);

, чтобы знать, сколько символов вы на самом деле прочитали и что нужно изменить. Попробуйте изменить свою программу сейчас, чтобы она соответствовала этому. Один намек - вашему return, вероятно, придется двигаться, например.

0 голосов
/ 11 октября 2019

Что ж, вы слишком усложнили вещи, самостоятельно буферизовав входные данные, в то время как вы могли бы использовать getchar() и putchar() уже буферизующие функции. Кроме того, использование цифр вместо символьных литералов скрывает фактическую цель вашего кода (преобразование в верхний регистр, против добавления вычитающих странных магических значений в ваш код) и связывает его также со средами кодов 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); */
        }
    }
}
0 голосов
/ 05 октября 2019

Следующий предложенный код:

  1. безупречная компиляция
  2. правильно завершает входной массив символов
  3. правильно меняет все символы нижнего регистра на верхний регистр, используясредство: toupper() из заголовочного файла: ctype.h
  4. выполняет желаемую функциональность

и теперь предлагаемый код:

#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] = '\0';

        // 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] );
    }

}
0 голосов
/ 04 октября 2019

Программа прекрасно работает, за исключением части цикла.

char* charToUpper(char *a){
    char *t=p;
    while(*a!='\0'){
    if ((*a > 96) && (*a <123)) 
        *a = *a-32;
    a++;
    }
    return t;
}

Вы не увеличивали цикл. сделай это, и ты получишь

...