0

My program doesn't seem to be updating the unsigned char[ ] in main after calling the changecontents function because it's printing out the same value for storage[13] as the one before the call. This is not my entire code however--I copied the general functionality to here.

Update: Sorry I forgot to indicate that data1[13] is initialized--indices 0 to at least 200 contain values.

Update2: Added readfile function that initialized data1 in main.

Update3: Checked for a NULL return from fopen() function in readfile; file.gif exists.

#include <stdio.h>
int main()
{
    unsigned char data1[4000] = {0};  
    readfile(data1, 4000, "file.gif");    // filled 3022 indices in data1; file.gif exists
    printcontents(data1);       // prints the array contents as desired here 
    changecolor(data1);     // doesn’t change the array contents 
    printcontents(data1);       // prints the same array contents as original      
    return 0;
}
int printcontents(unsigned char storage[ ])
{
    printf(“%X”, storage[13]);  // data1 passed in function call in main
    return 0;
}
int changecolor (unsigned char storage[ ])
{
    storage[13] = storage[13] >> 2;     // data1 passed in function call in main
    return 0;
}
int readfile(unsigned char storage[ ], int capacity, char filename[ ])
{
    FILE * content = fopen(filename, "r");
    if (content != NULL)
    {
        size_t numElements, bytesPer = sizeof(unsigned char);
        fseek(content, 0, SEEK_END);
        numElements = ftell(content);
        rewind(content);
        fread(storage, bytesPer, numElements, content);   // returned 3022
        fclose(content);
    }
    return 0;
}
9
  • You should init data1[13]. Commented Nov 4, 2018 at 6:00
  • Since you don't initialize the array, its contents are indeterminate and any use of the uninitialized values leads to undefined behaviour. Anything is possible with undefined behaviour. So, you've not yet made a case for there being a problem. You need to declare functions (or define them) before you use them in any version of C that's been standard during the current millennium. Not using a compiler that enforces that is hurting your chances of learning to program decently in C.' Commented Nov 4, 2018 at 6:01
  • Sorry, I forgot to indicate in my code that the entire data1 array is initialized, including data1[13]. Commented Nov 4, 2018 at 6:02
  • 1
    Please create an MCVE (minimal reproducible example). You may just be able to delete the lines with 3 dots on them, and add something to initialize the data that you claim is initialized. At the moment, your claims are not easily substantiated. You probably don't need to use 4000 in an MCVE; 20 would be sufficient, and could be reduced further if you changed 13 to, say, 3. Of course, the problem must be reproducible on the small scale. Your code doesn't use capacity1; it won't appear in an MCVE. Commented Nov 4, 2018 at 6:08
  • Also, if data1[13] == 0 before the call, it won't change after the call. Since you've not shown us how the variable is initialized, or what the outputs are, we can't tell whether that's part of the trouble. Commented Nov 4, 2018 at 6:11

3 Answers 3

2

The updated code doesn't use capacity in readfile(). The function doesn't explicitly report an error when it fails to open the file — that cost me some time.

Here's a variant of your code which produces the output I expect:

#include <stdio.h>
int printcontents(unsigned char storage[ ]);
int changecolor (unsigned char storage[ ]);
int readfile(unsigned char storage[ ], size_t capacity, char filename[ ]);
int main(void)
{
    unsigned char data1[4000] = {0};  
    readfile(data1, 4000, "file.gif");    // filled 3022 indices in data1; file.gif exists
    printcontents(data1);       // prints the array contents as desired here 
    changecolor(data1);     // doesn’t change the array contents 
    printcontents(data1);       // prints the same array contents as original      
    return 0;
}
int printcontents(unsigned char storage[ ])
{
    printf("%#X\n", storage[13]);  // data1 passed in function call in main
    return 0;
}
int changecolor (unsigned char storage[ ])
{
    storage[13] = storage[13] >> 2;     // data1 passed in function call in main
    return 0;
}
int readfile(unsigned char storage[ ], size_t capacity, char filename[ ])
{
    FILE * content = fopen(filename, "r");
    if (content != NULL)
    {
        size_t numElements, bytesPer = sizeof(unsigned char);
        fseek(content, 0, SEEK_END);
        numElements = ftell(content);
        if (numElements > capacity)
            numElements = capacity;
        rewind(content);
        if (fread(storage, bytesPer, numElements, content) != numElements)
            printf("Bogus input\n");    // returned 3022

        printf("Got %zu bytes\n", numElements);
        for (int i = 0; i < 16; i++)
            printf(" 0x%.2X", storage[i]);
        putchar('\n');
        fclose(content);
    }
    else
        fprintf(stderr, "failed to open file '%s'\n", filename);
    return 0;
}

I used a random number generator to create the file.gif file. When I ran the program on that file, I got:

Got 3023 bytes
 0x62 0x66 0x74 0x77 0x76 0x62 0x66 0x6E 0x6D 0x72 0x70 0x62 0x63 0x66 0x71 0x7A
0X66
0X19

As you can see, the value in position 13 of the array (between 0x63 and 0x71) changes from 0x66 (102) to 0x19 (25), which is the correct 'divide by 4' value.

It's not possible to guess from here what's going wrong in your version. The simplest guess is that the file file.gif isn't there, despite your assertions to the contrary. Your code doesn't show that the fread() succeeded.

Most of the changes I made were those necessary to get the code pass my default compiler warnings. I'm using clang from XCode 10.1 on Mojave 10.14.1, and I compiled arr41.c to arr41 using:

/usr/bin/clang -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes \
    -Wstrict-prototypes arr41.c -o arr41

I also added the diagnostic code to warn when the file wasn't opened, and to print the amount of data read, the first 16 bytes of that data, and tidied up the formatting of the printed values (end outputs with newlines, in general).

I note in passing that this is not an MCVE (Minimal, Complete, Verifiable Example). An MCVE might be:

#include <stdio.h>

static void printcontents(unsigned char storage[]);
static void changecolor(unsigned char storage[]);

int main(void)
{
    unsigned char data1[20] = "ABCDEFGHIJKLMNOPQRS";
    printcontents(data1);
    changecolor(data1);
    printcontents(data1);
    return 0;
}

static void printcontents(unsigned char storage[])
{
    printf("%#X\n", storage[13]);
}

static void changecolor(unsigned char storage[])
{
    storage[13] = storage[13] >> 2;
}

Output:

0X4E
0X13

Again, this is clearly correct.

Sign up to request clarification or add additional context in comments.

Comments

2

Your problem is one of validation which is usually an afterthought for new programmers, but in reality should be a primary focus of your approach to coding. The code you have shown (and had before you updated and replaced[1] the original code in your question) provided zero validation of any of the necessary function calls made by your program.

Even after adding the check if (content != NULL) you have no way to tell if that code was executed or your function simply returned 0 because there are no diagnostics output upon failure and you make no meaningful use of the return from readfile (no matter if it succeeds or fails -- it always just returns 0)

Choose a meaningful return type for each function. If you do not need to make use of the return from a function, then make that function type void.

Adding meaningful return types and values will identify exactly where your program fails. For example providing meaningful returns and fully validating your code you could do similar to:

#include <stdio.h>

#define FNAME "file.gif"    /* if you need constants, #define one (or more) */
#define MAXC 4000

/* select proper/meaningful return types for your functions */
void printcontents (const unsigned char *storage);
void changecolor (unsigned char *storage);
int readfile (unsigned char *storage, int capacity, char *filename);

int main (void) {

    unsigned char data1[MAXC] = {0};  

    if (!readfile(data1, MAXC, FNAME))  /* validate all necessary calls */
        return 1;

    printcontents(data1);
    changecolor(data1); 
    printcontents(data1);

    return 0;
}

void printcontents (const unsigned char *storage)
{
    printf("%X", storage[13]);
}

void changecolor (unsigned char *storage)
{
    storage[13] >>= 2;
}

int readfile (unsigned char *storage, int capacity, char *filename)
{
    size_t numElements, bytesPer = sizeof(unsigned char);
    FILE *content = fopen (filename, "r");

    if (!content) {
        perror ("fopen-filename");
        return 0;
    }
    if (fseek (content, 0, SEEK_END) == -1) {
        perror ("fseek-content");
        return 0;
    }

    if ((long)(numElements = ftell(content)) == -1) {
        perror ("ftell-content");
        return 0;
    }

    rewind(content);

    if (numElements > capacity * bytesPer)
        fprintf (stderr, "warning - file size exceeds read capacity.\n");

    if (fread (storage, bytesPer, numElements, content) != numElements) {
        fprintf (stderr, "error: less than %zu elements read from %s\n",
                numElements, filename);
        return 0;
    }

    fclose (content);

    return 1;
}

(note: don't use magic numbers or hard-coded strings in your code. If you need constants, the #define them. That makes your code easier to read and maintian)

footnotes:

1. do not replace or delete portions of your original question. That renders all comments and answers prior to your changes irrelevant. Instead add to your question by including edits at the bottom of the original. That way all comments and answers will continue to make sense. (I know you are new -- so no dings for it this time -- but don't do it going forward)

Comments

0

Initialize data1 as below:

unsigned char data1[4000] = { 0 };

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.