2

我在将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->nrowsand img_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;
4

4 回答 4

2

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

内容是:

RGBRGB

RGBRGB

.

.

.

行值不是像素数,而是像素数 * 3。所以每行 2 个像素。

您将像素数据存储为: Pixel_t **data;-> 包含 3 个无符号短裤的静态数组的结构指针的指针。

您以这种方式分配数据:

data = malloc(sizeof(Pixel_t*) * 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;
}

此代码输出正确的数据。

于 2013-11-08T05:36:57.427 回答
1

不要使用 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);
}
于 2013-11-07T23:48:52.877 回答
0

对不起,我不能发表评论,只是一个答案。你有没有试过使用调试器?它为此目的而制造。您可以单步执行每一行代码并查看变量的当前数据。查看读取 0/1 时发生的情况,以及读取其他值时发生的情况。然后就可以准确定位错误了。

制造

刚刚修改了您的读取功能并在我的设备上进行了尝试:

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.

将其写入 unsigned short 会提供相同的输出。看来你的结构有问题......

顺便说一句:代码很糟糕,如果阅读有效,这只是一个例子。

于 2013-11-07T21:59:51.527 回答
0

在代码行中:

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

您正在分配令牌,它是指向 unsigned short 的指针。当您转换它时,您将指针转换为无符号整数。这可能看起来像垃圾。您可以通过以下方式修复它:

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++;
}
于 2013-11-07T22:01:12.207 回答