簡體   English   中英

在C中將char轉換為unsigned short

[英]Converting char to unsigned short in C

我在將char值保存到unsigned short類型的結構字段時遇到了一些麻煩。

---編輯:這是輸入.pgm-

P2
6 10

255

255 255 255 255 10 255

255 255 255 255 20 255

255 255 255 255 30 255

255 255 255 255 40 255

255 255 255 255 50 255

255 255 255 255 60 255

110 255 255 255 70 255

255 100 90 80 255 255

255 255 255 255 255 255

255 255 255 255 255 255

因此,我們假設要保存一個由0和1或其他數字組成的矩陣。 結構如下:

typedef struct{
    unsigned short rgb[3];   
}PIXEL_T;

typedef struct{
    int format;
    int nrows;
    int ncolumns;
    int max_color;
    PIXEL_T **pixels;   
}PBM_T;

這是將1或0個字符保存到適當的結構字段中的代碼。

void pbmMatrixASCII(char* line, size_t len, FILE* file_stream, PBM_T *img_struct) {

    int i = 0, j = 0;
        char *token;

    while(getline(&line, &len, file_stream) != EOF) {
        token = strtok(line, " \n\t");
        while (token != NULL) {
            //DEBUG("%s", token);
            img_struct->pixels[i][j].rgb[0] = strtol(token, NULL, 0);
            token = strtok(NULL, " \n\t");
            printf("%hu ", img_struct->pixels[i][j].rgb[0]);
            j++;
        }
        printf("\n");   
        i++;
    }
}

現在,這非常適合0和1。 問題是,當我們必須保存一個值在1到255之間的矩陣時,它會保存並打印垃圾。 我們嘗試了幾種鑄造方法。 例如:

img_struct->pixels[i][j].rgb[0] = (unsigned short) token;

他們不工作。 我們該如何解決? (此外,是否存在一種正確的方法來實際轉換值,這同時解決了兩個問題?)

----編輯以回應一些反饋意見----

我們正在讀取pbm和pgm文件。 第二行是矩陣的大小,然后我們將其讀取為img_struct->nrowsimg_struct->ncolumns 這是代碼:

//Detects the filetype and reads the matrix size (also reads max color in case of pgm)

//Reads the first line to determine the magic number    

    getline(&line, &len, file_stream);
    sscanf(line, "P%d", &aux_format);

    //Verifies if the format is valid. Exits if not

    if(aux_format > 6 || aux_format < 1) {
        ERROR(ERR_FORMAT,"Invalid format\n");
    }

    img_struct->format = aux_format; //Saves the format into the structure, after being verified

    int size_is_read = 0; //Variable used to verify if the size has been read (a makeshift boolean)

        while(getline(&line, &len, file_stream) != EOF){

            if (hasCommentsOrEmptyLines(line))
                continue;

    //Reads the size of the matrix

            if(size_is_read == 0) {
                sscanf(line,"%d %d",&columns,&rows);
                size_is_read = 1;
            }

            if(img_struct->format == 1 || img_struct->format == 4) { //P1 and P4 are .pbm files and therefore don't have  a maximum colour field
                break;

            } else if(img_struct->format == 2 || img_struct->format == 5){ //Every other file type needs to have its maximum colour field read

                while(getline(&line, &len, file_stream) != EOF) {

                    if(hasCommentsOrEmptyLines(line))
                        continue;

    //reads the max color                   
                    sscanf(line,"%d",&(img_struct->max_color));

                break;
            }

        }
        break;
    }

然后,進行內存分配,然后調用矩陣讀取器函數(請參見上文):

//Save the image size in the appropriate structure fields   
img_struct->nrows = rows;
img_struct->ncolumns = columns;

//Allocates the appropriate size of the matrix to save the bitmap

img_struct->pixels = MALLOC(sizeof(PIXEL_T *)*rows);
if (img_struct->pixels == NULL)
    ERROR(ERR_ALLOC,"Error allocating memory for the bitmap matrix");

for(i = 0; i < rows; i++) {
    img_struct->pixels[i] = MALLOC(sizeof(PIXEL_T)*columns);
}


//Iterate each position of the line array and convert it to an unsigned short 

switch(img_struct->format) {

    case 1:
        pbmMatrixASCII(line, len, file_stream, img_struct);
    break;

    case 2:
        printf("teste\n");
        pgmMatrixASCII(line, len, file_stream, img_struct);
    break;

因此,在您的文件格式中,您有:行= 6列= 10

內容是:

RGBRGB

RGBRGB

行值不是像素數,而是像素數*3。因此,每行2個像素。

您將像素數據存儲為: Pixel_t **data; ->包含3個無符號短褲的靜態數組的結構的指針。

您可以這樣分配數據:

data = malloc(sizeof(Pixel_t*) * row);

所以現在數據是大小為'row'的pixel_t指針數組

然后您分配pixel_t的每個指針:data [n] = malloc(sizeof(pixel_t)* column); 因此,現在每行基本上都有一個數組,該數組的大小為3個無符號的短*列,這使其變得太大了3倍,因為您為每列分配了一個像素。

當您遍歷數據時,您始終會寫入:

data[y][x].rgb[0]

就像:

*(data[y][x])

這使您的結構無用,因為每次您訪問數組的第一個元素時...因此,根據輸出數據的方式,您將在數組末尾產生垃圾,因為您從未實際使用它,因為它是3次太大。

同樣,在您的情況下,使用strtok和strtol並將其存儲到unsigned short中也可以正常工作,因此解析不是問題。

#include <string.h>
#include <stdio.h>

int main()
{
    char *str = strdup("255 42 25 255 67 89\n");
    char *token = strtok(str, " \n");
    while (token)
    {
        unsigned short val = strtol(token, 0, 0);
        token = strtok(0, " \n");
        printf("%hu\n", val);
    }

    return 0;
}

此代碼輸出正確的數據。

與其使用C函數來標記字符串,不如嘗試簡單地遍歷它,如下所示:

void pbmMatrixASCII(char* line, size_t len, FILE* file_stream, PBM_T *img_struct) {
    int i = 0;

    while(getline(&line, &len, file_stream) != EOF) {
        // Extract all pixel entries.
        int nFound = getPixels(line, img_struct->ncolumns, img_struct->pixels[i]);

        // Print out what we found.
        // int j = 0;
        // for (j = 0; j < nFound; j++) {
        //     printf("%hu %s",
        //         img_struct->pixels[i][j].rgb[0],
        //         ((j + 1) == nFound ? "\n": ""));
        // }

        // Go to the next row of pixels if we found values.
        if (nFound == img_struct->ncolumns)
            i++;
    }
}

並具有另一個函數來解析您讀入的每一行:

int getPixels(char * line, int numExpected, PIXEL_T * pixelRow) {
    int max                = strlen(line);
    int counter            = 0;
    PIXEL_T * currentPixel = pixelRow;
    char * linePtr         = line;

    while (counter < numExpected) {
        // Reach the first non-whitespace character.
        while (linePtr[0] == ' ') {
            if ((linePtr - line) >= max)
                return (counter);

            linePtr++;
        }

        if (linePtr[0] == '\n')
            return (counter);

        // Grab the unsigned short value.
        int numFound = sscanf(linePtr, "%hu", &currentPixel->rgb[0]);

        // Make sure we found something.
        if (numFound > 0)
            currentPixel++, counter++;
        // Error happened with sscanf! Return what we found so far.
        else if (numFound < 0)
            return (counter);

        // Reach the first non-NON-whitespace character. Double negative ;)
        while (linePtr[0] != ' ') {
            if ((linePtr - line) >= max)
                return (counter);

            linePtr++;
        }
    }
    return (counter);
}

這樣,您就不必實際從字符中轉換值了。 sscanf(...)將其讀取為無符號的短型。

-編輯:以下內容用於讀取PPM文件-

注意: numExpected是您將看到的預期RGB 三元組的數量。 傳遞2的值表示那里應該有2個像素,每個像素3個值,總計讀入行中的6個實際條目。這對應於PPM文件本身頂部的寬度值。

int getPixels(char * line, int numExpected, PIXEL_T * pixelRow) {
    int max                = strlen(line);
    int counter            = 0;
    int currentValue       = 0;
    PIXEL_T * currentPixel = pixelRow;
    char * linePtr         = line;

    while (counter < numExpected) {
        while (currentValue < 3) {
            // Reach the first non-whitespace character.
            while (linePtr[0] == ' ') {
                if ((linePtr - line) >= max)
                    return (counter);

                linePtr++;
            }

            if (linePtr[0] == '\n') {
                return (counter);
            }

            // Grab the unsigned short value.
            int numFound = sscanf(linePtr, "%hu", &currentPixel->rgb[currentValue]);

            // Make sure we found something.
            if (numFound == 1)
                currentValue++;

            // Error happened with sscanf! Return what we found so far.
            else if (numFound < 0)
                return (counter);

            // Reach the first non-NON-whitespace character. Double negative ;)
            while (linePtr[0] != ' ') {
                if ((linePtr - line) >= max)
                    return (currentValue == 3 ? counter + 1 : counter);

                linePtr++;
            }
        }

        counter++, currentPixel++, currentValue = 0;
    }
    return (counter);
}

抱歉,我無法發表評論,只能提供答案。 您是否曾經嘗試過使用調試器? 它是為此目的而制成的。 您可以遍歷代碼的每一行,並查看變量的當前數據。 讀取0/1時查看發生了什么,讀取其他值時再次查看。 然后,您可以准確定位錯誤。

MFG

只是稍微修改了您的讀取功能,然后在我的設備上嘗試了一下:

static const char filename[] = "ok.pgm";
FILE *file = fopen ( filename, "r" );

while(fgets(line, sizeof line, file) != NULL) {
    token = strtok(line, " \n\t");

    while(token != NULL) {
        //DEBUG("%s", token);
        long int t = strtol(token, NULL, 0);
        token = strtok(NULL, " \n\t");
        printf("%hu ", t);
        j++;
    }
    printf("\n");
    i++;
}

輸出:

0
6 10
255
255 255 255 255 10 255
255 255 255 255 20 255
255 255 255 255 30 255
255 255 255 255 40 255
255 255 255 255 50 255
255 255 255 255 60 255
110 255 255 255 70 255
255 100 90 80 255 255
255 255 255 255 255 255
255 255 255 255 255 255

Process returned 0 (0x0)   execution time : 0.016 s
Press any key to continue.

將其寫入無符號的short可以提供相同的輸出。 看來您的結構有問題...

順便說一句:代碼不好,如果閱讀有效,請舉一個例子。

在代碼行中:

img_struct->pixels[i][j].rgb[0] = (unsigned short) token;

您正在分配令牌,它是指向無符號short的指針。 強制轉換時,將指針轉換為unsigned int。 那看起來像是垃圾。 您可以通過以下方式修復它:

unsigned int value = (unsigned int)atoi(token);
img_struct->pixels[i][j].rgb[0] = value;

在下面的代碼段中,循環計數器j始終遞增。 因此,在讀取第二條大行並訪問像素陣列時會發生崩潰。

int i = 0, j = 0;
    char *token;

while(getline(&line, &len, file_stream) != EOF) {
    token = strtok(line, " \n\t");
    j = 0;                                          // <-- FIXED
    while (token != NULL) {
        //DEBUG("%s", token);
        img_struct->pixels[i][j].rgb[0] = strtol(token, NULL, 0);
        token = strtok(NULL, " \n\t");
        printf("%hu ", img_struct->pixels[i][j].rgb[0]);
        j++;
    }
    printf("\n");   
    i++;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM