-1

I'm stuck in C array pointer and passing it as argument into c functions. Here is the code where issues are involved:

char *src_filename1 = NULL;
AVFrame *frame = NULL;
AVFrame *frames_video1[3];
AVFrame *frames_video2[3];

int decode_packet(int *got_frame, int cached, AVFrame *frames_video[])
{
    ...
    frames_video[video_frame_count] = frame; //video_frame_count is 2 at the moment
    ...
}

int main()
{
    decode_video(src_filename1, frames_video1);
    ...
    printf("frames_video1[i]->pkt_size: %d\n", frames_video1[i]->pkt_size);
    ...
}
int decode_video(char *src_filename, AVFrame *frames_video[])
{
    ...
    decode_packet(&got_frame, 0, frames_video);
    ...
}

I could compile the code, but when I executed it, I encountered segmentation fault caused by frames_video1[i]->pkt_size How shall I pass arguments in this context? I find when dealing with char*[] and char** especially when using them as function arguments, my hands always get dirty...

EDIT NEW CODE: (which works!)

char *src_filename1 = NULL;
AVFrame *frame = NULL;
AVFrame frames_video1[3];
AVFrame frames_video2[3];

int decode_packet(int *got_frame, int cached, AVFrame frames_video[])
{
    ...
    AVFrame tmp;
    tmp = *frame;
    frames_video[video_frame_count] = tmp;
    ...
}

int main()
{
    decode_video(src_filename1, frames_video1);
    ...
    printf("frames_video1[i].pkt_size: %d\n", frames_video1[i].pkt_size);
    ...
}
int decode_video(char *src_filename, AVFrame frames_video[])
{
    ...
    decode_packet(&got_frame, 0, frames_video);
    ...
}

Let me briefly summarize the main issue of the old code: It had little to do with initialization, the main problem was the passing array of pointers as argument, was really about passing argument all the way properly: after hearing the suggestion from @SF., I changed the argument from AVFrame *frames_video[] to AVFrame frames_video[], and supprisingly everything worked well! It also means AVFrame frames_video1[] has been finally successfully "received" by decode_packet function... "Arrays behave as pointers in so many ways that you're getting drowned in pointer-to-pointer bog.", that's what he said. Actually, I still don't quite really understand how c pointers (especially when associated with arrays) work in a deeply sense...

Kindermann
  • 343
  • 4
  • 15
  • 1
    `frames_video1[]` has been declared, not initialized. So you cannot do `frames_video1[i]->pkt_size`. – abhishek_naik May 18 '16 at 12:12
  • @BatCoder but in the decode_packet function, frames_video1 items are assigned by frame, meaning frames_video1[0] points to a frame, frames_video1[1] points to an other frame, and so on. They are not NULL – Kindermann May 18 '16 at 13:16
  • "Array pointer" or "array **of** pointer**s**" is a great difference! – too honest for this site May 18 '16 at 13:56
  • @Olaf don't be that literal :) – Kindermann May 18 '16 at 14:05
  • @Kindermann There is a specific, technical term in C called _array pointer_. It is different from regular pointers only in one way, namely that it can point at a whole array, rather than just pointing at the first object. Therefore your question is a bit strangely worded, as there is no array pointer in this code. – Lundin May 18 '16 at 14:35

4 Answers4

4

In your code, frames_video1[] has just been defined, but its values (pointers) were not explicitly initialized*. So you cannot dereference them - do frames_video1[i]->pkt_size. This results in undefined behavior.

* they were implicitly initialized to NULL, attempting dereferencing which still causes UD.

SF.
  • 12,380
  • 11
  • 65
  • 102
abhishek_naik
  • 1,232
  • 2
  • 15
  • 25
  • 1
    That is not true. `AVFrame *frames_video1[3];` is a valid definition of a variable. Had that been true, it would not be an undefined behavior. It would be a linker error. – Shachar Shemesh May 18 '16 at 12:15
  • @ShacharShemesh, by writing `AVFrame *frames_video1[3];`, the OP has just declared the array. It has not been initialized so he cannot access `pkt_size` – abhishek_naik May 18 '16 at 12:19
  • `AVFrame *frames_video1[3];` is a definition of an array of pointers to AVFrame structures. These structures have never been defined. frames_video1 is a valid variable - a variable that contains an array of uninitialized pointers. Dereferencing these pointers (through `->`) causes undefined behavior. – SF. May 18 '16 at 12:34
  • @SF., I totally agree with you. But I am not sure what you are trying to imply with your comment. Feel free to edit the answer, if that is what you expect. – abhishek_naik May 18 '16 at 12:53
  • @BatCoder: [Declaration vs Definition](http://stackoverflow.com/questions/1410563/what-is-the-difference-between-a-definition-and-a-declaration). Initialization is often performed together with definition, and the definition can serve as declaration, but a variable that's been just declared but not defined can't be initialized. In this case the variable is defined. If it was anything else than pointers, reading it would yield an unpredictable value but not cause undefined behavior. But it's not being read - it's being dereferenced. This causes the undefined behavior - or specifically, crash. – SF. May 18 '16 at 13:02
  • @BatCoder, you are confusing definition and declaration. Your original, pre-edit, answer said the array was declared but not defined. That was not true. The array was defined, but was not initialized. Also, the answer currently states that this means its values are invoking UD. This is not so. Uninitialized global (as opposed to automatic) vars in C are well defined to be zero initialized. – Shachar Shemesh May 18 '16 at 13:05
  • @ShacharShemesh: Dereferencing a NULL pointer, in practice universally means causing segfault and nothing else, but the standard doesn't differentiate it from dereferencing any invalid pointer - it's still considered Undefined Behavior. Did I clarify it with my edit better? – SF. May 18 '16 at 13:15
  • @SF. I will concede that point. Dereferencing a NULL pointer is, indeed, UD. I just wanted to to point out that it is a NULL, and not something else. – Shachar Shemesh May 18 '16 at 13:18
  • how to initialize frames_video1[3] in this context? – Kindermann May 18 '16 at 13:18
  • @Kindermann, that completely depends on what you are trying to do. You did not give us enough context to answer that. You might want to allocate them with malloc, or something. – Shachar Shemesh May 18 '16 at 13:19
  • 1
    @Kindermann: `AVFrame f; frames_video1[3] = &f;` initializes the third element. If you want dynamic initialization, `video1[3] = malloc(sizeof(AVFrame));` (then handle `malloc` returning NULL on failed allocation, a possible runtime error). – SF. May 18 '16 at 13:20
  • 1
    ...personally, I'd entirely drop one layer of indirection. `AVFrame frames_video1[3];`, `int decode_packet(int got_frame, int cached, AVFrame frames_video[])`, `memcpy(frames_video[video_frame_count], frame, sizeof(frame));` `frames_video1[i].pkt_size`. Arrays behave as pointers in so many ways that you're getting drowned in pointer-to-pointer bog. – SF. May 18 '16 at 13:27
  • I still don't quite understand: frames_video1[] is firstly passed to decode_video(), there it's further passed to decode_packet(), and finally it's supposed to be assigned by frame. Is the passing of frames_video1[] from main function all the way to decode_packet function where each item of it shall be assigned by frame variable clear to you? – Kindermann May 18 '16 at 13:38
  • or do you mean that before each item of frams_video1[] can be assigned by frame, it must be initialized? frames_video1[] is NOT null at the end of the day unless it's wrongly passed... – Kindermann May 18 '16 at 13:45
  • I'm more concerned with whether frams_video1[] was actually correctly passed to decode_packet()... – Kindermann May 18 '16 at 13:46
  • All the debate over initialization misses the fact that the variables in question are declared at file scope, and therefore have static duration. Supposing that there is no other declaration that provides an explicit initializer, these objects are subject to default initialization. This will initialize all the pointers to NULL, including those that are array elements. This is *totally different* from those values being unintialized. – John Bollinger May 18 '16 at 13:47
  • firstly forget about initialization issues. I wonder if *frame_video1[] can be passed into decode_packet() correctly... I want to get back a *frame_video1[] variable full with pointers to frames... – Kindermann May 18 '16 at 13:51
1

You did not provide the entire code, but I believe your problem is that you are sending the function an array of pointers, but your not initializing that array. You are probably passing an array of NULLs, and then trying to dreference them.

Shachar Shemesh
  • 7,371
  • 4
  • 20
  • 50
1

How shall I pass arguments in this context?

The code you presented is fine, as far as it goes. The arguments to the function calls agree with the functions' parameters (and surely you could induce your compiler to warn you of any cases where that was not so). Moreover, if you pass an array as a function argument then the called function will see the same element values as the caller, and if it sets different values for any of that array's elements then the effect will be visible to the caller.

I'm uncertain why you are confident that the segmentation fault arises from evaluating the expression frames_video1[i]->pkt_size, but perhaps you determined it via a debugger. In that case, there are only two likely explanations:

  1. variable i is either less than 0 or greater than 2, so that you are trying to access an out-of-bounds array element. Check your loop bounds, and be especially aware that the maximum index for an N-element array is N-1, not N.

  2. frames_video1[i] is not a valid pointer. It might never have been set to a valid pointer, or it might be a pointer to dynamic memory that since has been freed, or its value may have been corrupted. Certainly the initialization issues discussed in the other answers and in the comments on them point to one avenue by which this alternative could be exercised, but since you seem to discount that as a possible cause, I will not cover that ground again.

Overall, you present only skeleton code, not a working example by which the problem can actually be demonstrated. The answers you will receive are necessarily constrained by that.

John Bollinger
  • 121,924
  • 8
  • 64
  • 118
  • I believe your second explanation hit the issue. I'll work on it further to find it out the exact cause any way. – Kindermann May 19 '16 at 07:55
0

First of all, all pointers must be initialized properly before they can be dereferenced. So to write frames_video1[i]->pkt_size you must somehow initialize pointer under frames_video1[i] (either using malloc or storing address to already existing structure AVFrame with the right scope).

Secondly, after passing array to function you are losing information about it's size, so it has to be passed as argument together with an array, so e.g.:

int decode_video(char *src_filename, AVFrame *frames_video[])

should be changed to:

int decode_video(char *src_filename, AVFrame *frames_video[],
                 int frames_count)

frames_count gives you information how far can you iterate other frames_video (e.g. index i = 3 is already too big, frames_video doesn't contain such element). So in your case to those functions you pass frames_count = 3 and iterate from 0 to i < 3.

zoska
  • 1,515
  • 10
  • 20