在C中将char转换为unsigned short

时间:2013-11-07 21:20:47

标签: c pointers casting struct

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

4 个答案:

答案 0 :(得分:2)

因此,您的文件格式为: row = 6 column = 10

内容为:

R G B R G B

R G B R G B

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

您将像素数据存储为: Pixel_t **data; - &gt;包含3个unsigned short的静态数组的结构指针的指针。

您可以通过以下方式分配数据:

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

此代码输出正确的数据。

答案 1 :(得分: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);
}

答案 2 :(得分:0)

抱歉,我无法发表评论,只是回答。 你有没有试过使用调试器?它是为此目的而制作的。您可以单步执行每行代码并查看变量的当前数据。 查看读取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.

将其写入无符号短路提供相同的输出。你的结构似乎有问题......

BTW:代码很糟糕,只是一个例子,如果阅读有效。

答案 3 :(得分:0)

在代码行中:

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

您正在分配令牌,该令牌是指向unsigned 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++;
}