Char ** usage and printing
Asked Answered
M

3

9

In C, I am using a char ** to hold a series of strings.

Here is my code:

char ** c;
//now to fill c with data ????

//cannot change:
printf ("%*s%s", 0, "", *c);
while (*++w)
    printf (" %s", *c);

I do not know how to fill c with data. What is the proper way? I cannot change the 3 printing lines because they are in an external function.

Main answered 28/1, 2013 at 2:52 Comment(2)
The proper way depends on what data you want to put in there. What's your expected input and output?Introgression
I have found the answer but cannot post as a reply for 8 hours because I am a new user: char ** c; int row = 3; int col = 10; c = calloc(row, sizeof (char[col])); c[0] = "cat\0"; c[1] = "dog\0"; c[2] = "mouse\0"; //cannot change: printf ("%*s%s", 0, "", *c); while (*++w) printf (" %s", *c); free(c);Main
O
8

The terminology is important here, I think. The char ** doesn't "hold" a series of strings at all (unlike container objects in higher-level languages than C). The variable c is just a pointer to a pointer to a character, and that character is going to be the first character in a nul-terminated string.

This line of thinking leads directly to the solution: If c is a pointer to a pointer to a character, that means we have to allocate some memory in which to actually hold the array of strings.

@DB_Monkey's solution posted as a comment seeks to do this but isn't quite right because it implies that code like c[0] = "cat" copies "cat" into c[0], which isn't so -- the assignment applies to the pointer, not to the string. A better way would be:

int rows = 3;
char **c = calloc (rows,sizeof(char*));
c[0] = "cat";
c[1] = "dog";
c[2] = "mouse";

This also shows that it isn't necessary to show the explicit nul termination of each string.

Overplay answered 28/1, 2013 at 3:11 Comment(0)
O
4

your char** is actually a number which thinks that number is an address of a number which is an address of a valid character...

to put it simply:

// I am a number that has undefined value, but I pretend to point to a character.
char *myCharPointer;
// | The statement below will access arbitrary memory
// |   (which will cause a crash if this memory is not allowed to be accessed).
char myChar = *myCharPointer; 

To make use of this pointer, you have to initialize it.

char *myCharPointer = (char *)malloc(10 * sizeof(char));

now, you can use this pointer in the same way you deal with arrays, or due pointer arithmetic if you want.

Note that malloc does not set all values in the "array" to 0, their values are undefined by default.

In order to do what you want to do, you have to do the following:

// I can store 10 "strings"
char **myArrayOfStrings = (char **)malloc(10 * sizeof(char *));
char *str0 = "Hello, world0";
char *str1 = "Hello, World1";
char *str2 = "Hello, World2";
char *str3 = "Hello, world3";
char *str4 = "Hello, world4";
char *str5 = "Hello, world5";
char *str6 = "Hello, world6";
char *str7 = "Hello, world7";
char *str8 = "Hello, world8";
char *str9 = "Hello, world9";
myArrayOfStrings[0] = str0;
myArrayOfStrings[1] = str1;
myArrayOfStrings[2] = str2;
myArrayOfStrings[3] = str3;
myArrayOfStrings[4] = str4;
myArrayOfStrings[5] = str5;
myArrayOfStrings[6] = str6;
myArrayOfStrings[7] = str7;
myArrayOfStrings[8] = str8;
myArrayOfStrings[9] = str9;
// the above is the same as
// *(myArrayOfStrings + 9) = str9

You don't have to have the strings of same length of anything, suppose str[0..9] are actually numbers that store the address of where the first character of these strings is located in memory, eg

str0 = (char *)&9993039;
str1 = (char *)&9993089;

myArrayOfStrings is actually also a number which stores the address of the first string location, in particularmyArrayOfStrings = (char **)&str0;

Obviously, you will not do this explicitly as I shown, but this can be done at runtime without much issue, just store a string from the user in the buffer, then append it to the list, hoping that it doesn't run out of space (there are techniques to avoid that).

Hopefully this helped.

Oppidan answered 28/1, 2013 at 3:39 Comment(0)
I
2

What you have is an pointer to a pointer to char. This means that you have reserved space enough for referring to a variable that might (more must) be another pointer. This doesn't allow you to save actual chars in it before you reserve space for those chars.

So, now, you need a two step allocation of memory so you can have your chars, or strings, if you prefer, in your c variable.

You do this with malloc, sizeof and a for loop.

First you need to alloc space for your vector of strings (wich, in C, are just vectors of chars, so, really, you'll be allocating space for your vector of pointers to vectors of chars):

char **c = malloc(NUMBER_OF_STRINGS * sizeof(char*));

This makes your c variable pointing to NUMBER_OF_STRINGS, wich is a integer, pointers to char.

Now, you can either choose a maximum size for your strings and alloc all the space you'll need for your them or you can do that every time you need to put a new string:

/*All the space with MAX_STR= maximum string size*/
 for(i=0;i<NUMBER_OF_STRINGS;i++){
    c[i] = malloc(MAX_STR * sizeof(char));
 }

And now you can copy your strings to c[i] wich holds a string with MAX_STR size, or even get an actual char from the string by doing c[i][j] wich gives you the j character from the i string.

/*Alloc when you have the string*/
  while(fgets(buff, BUFFSIZE, stdin) != NULL){   //This is just an example of an input reading from the keyboard
       c[i] = malloc(strlen(buff) * sizeof(char));
       i++;
  }

I used a function strlen to get the size of buff(buff is just a string). Check string.h for string manipulation functions.

So I hope this solves your problem. One more thing, after each malloc you should check if malloc didn't returned NULL wich happens when you runed out of process virtual memory.

Hope this helps.

Insular answered 28/1, 2013 at 3:35 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.