繁体   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