6

Let's say I'm working with this C program.

  • I have three strings that's stored in dynamically allocated memory.
  • I'm storing the addresses to those strings in dynamically allocated pointer to pointers variable.
#include <string.h>
#include <stdlib.h>

int     main(void)
{
    char    *p0 = strdup("red..");
    char    *p1 = strdup("green");
    char    *p2 = strdup("blue.");
    char    *p3 = NULL;
    char    **pp = malloc(sizeof(char *) * 4); /* I want to watch this in VSCode debugger */

    pp[0] = p0;
    pp[1] = p1;
    pp[2] = p2;
    pp[3] = p3;

  /* do something */

    return (0);
}

What I want to achieve

In the watch view of VSCode debugger, how do I get it to display the char values (and addresses if possible) of the strings pointed by each pointers like the following?

<watch_expression_for_pp>: <address of pp>
   |- pp[0]: [6] <address of pp[0]>
   |     |--- [0]: 'r'
   |     |--- [1]: 'e'
   |     |--- [2]: 'd'
   |     |--- [3]: '.'
   |     |--- [4]: '.'
   |     |--- [5]: '\0'
   |
   |- pp[1]: [6] <address of pp[1]>
   |     |--- [0]: 'g'
   |     |--- [1]: 'r'
   |     |--- [2]: 'e'
   |     |--- [3]: 'e'
   |     |--- [4]: 'n'
   |     |--- [5]: '\0'
   |
   |- pp[2]: [6] <address of pp[2]>
   |     |--- [0]: 'b'
   |     |--- [1]: 'l'
   |     |--- [2]: 'u'
   |     |--- [3]: 'e'
   |     |--- [4]: '.'
   |     |--- [5]: '\0'
   |
   |- pp[3]: [6] <0x0000000000000000>
         |--- [0]: 'r'
         |--- [1]: 'a'
         |--- [2]: 'n'
         |--- [3]: 'd'
         |--- [4]: 'o'
         |--- [5]: 'm'

What I already know

I know that if I add (char(*)[6])pp[0] as an watch expression, I will be able to view the 6 char values from pp[0][0] to pp[0][5], but that's not an ideal solution if I'm dealing with hundreds of pointers and need to go through the values quickly.

watch char values of a single string

I'm looking for a way to add one watch expression, and be able to get a view like above, just like when I'm watching a linked list in the debugger.
Or, a completely different approach, like using an extension.

6
  • that's not an ideal solution if I'm dealing with hundreds of pointers and need to go through the values quickly at that level modify your program to produce a log during its execution, may be under a condition on the value of a variable you set through your debugger, but do you really want to check by eyes hundreds of pointers/strings ? Commented Aug 6, 2020 at 9:45
  • Thanks for the suggestion! I agree. You're saying that I should make use of conditional breakpoints, correct? Commented Aug 6, 2020 at 13:55
  • yes and no, you can have a global variable V valuing 0 by default and somewhere in the code if (V) { ...debug printing or something else... } and when needed though your debugger you change V value or putting a breakpoint on the test force PC to do the if body etc Commented Aug 6, 2020 at 14:03
  • @bruno To watch a global variable in VSCode debugger, you need to manually add a watch expression in the watch view. But the values of the variables that has been added to the watch view cannot be modified by the user during debugging. I kind of understand the technique you're trying to explain, but not fully. I also don't understand what you mean by "test force PC". I would appreciate it if you could give me a more detailed explanation. Thanks. Commented Aug 6, 2020 at 14:23
  • I never used that debugger but looking at its documentation I can see when the program is stopped (breakpoint ...) you are able to modify the value of a variable through the Set Value action from the variable's context menu . PC contains the address of the next instruction to execute, it is common for a debugger to allow to modify it to continue the execution elsewhere than the next instruction on breakpoint, so in tha case I speak about to not do if (V) (which is false) but to continue at the beginning of the body of the if. Commented Aug 6, 2020 at 14:41

1 Answer 1

8

This should do the job (but also see below for a cleaner solution):

(char (*(*)[4])[6])pp

enter image description here

As you can see, you were already really close!

Of course, the strings you use may not have a fixed size so the second dimension [6] would not be accurate and should probably match the longest string that you expect. Hence for shorter strings, you might see some gibberish from the adjacent memory locations.

Edit: As I later figured out, you can also drop the second dimension and use this much cleaner version:

(char (*(*)[N]))pp

where N is the number of strings you have in your array.

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

2 Comments

Thank you! This is exactly what I was looking for. I want to confirm one thing to make sure that I'm understanding this correctly. If I were to describe this type casting in an English sentence, it would be: "Type cast pp to a pointer to an array of 4 pointers to an array of 6 chars.". Correct?
@KIYZ Yes, that is exactly what it means. Although, as I later realized, you can drop the second dimension and have just: (char (*(*)[4]))pp, which works as well!

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.