# Array of char* confusion (array of strings)



## caesius (Jan 14, 2011)

I have a list of categories seperated by newlines in a file cats.txt

I'm trying to write code that takes each category name and adds it to an array (of category strings). You can see from the output that it isn't doing what it should be.

Here is the file cats.txt

```
apples
oranges
bananas
```

And here is main.c

```
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[])
{
    FILE * fp = fopen("cats.txt", "r");
    
    char * line = malloc(80);
    
    char * *category_list = malloc(100); // 100 chosen arbitrarily...
    
    int i = 0;
    
    while (fgets(line, MAX_STRING_LENGTH, fp) != 0) {
        
        /* Remove trailing '\n' from line */
        *(line + strlen(line) - 1) = '\0';
        
        /* Add string to array */
        *(category_list + i) = line;
        
        i++;
        
    }
    
    printf("first line: %s\n", *(category_list + 0));
    printf("second line: %s\n", *(category_list + 1));
    printf("third line: %s\n", *(category_list + 2));
    
    fclose(fp);

    return 0;
}
```

And when I run it...

```
> ./main
first line: bananas
second line: bananas
third line: bananas
```

Can anyone explain what is going on?


----------



## expl (Jan 14, 2011)

You get bananas all over the place because you assign same pointer to every array member, pointer's memory being overwritten with each line. strdup() will malloc a duplicate string, however you will need to free them separately.


```
...
*(category_list + i) = strdup(line);
...
```


----------



## caesius (Jan 14, 2011)

I have another questions about allocating memory to category_list.

At the moment I allocate 100 because it's big an just works.

```
char * *category_list = malloc(100); // 100 chosen arbitrarily...
```

But what should this number be really? Should it be the number of lines in cats.txt?

Cheers.


----------



## expl (Jan 15, 2011)

caesius said:
			
		

> I have another questions about allocating memory to category_list.
> 
> At the moment I allocate 100 because it's big an just works.
> 
> ...



should be


```
char * *category_list = malloc(sizeof(char*) * lines_in_file);
```
since pointer would be 2 to 8 bytes each depending on platform.


----------



## caesius (Jan 15, 2011)

Hmm now I have a new problem. I am actually trying to write a function that takes as an argument a char ** and fills this with the strings from the file. Something like this:


```
/**
    @param cats Assume this has been allocated enough memory */
void
expense_cats_get(char ** cats, const char * filename)
{
     FILE * fp = fopen(filename, "r");
    
    char * line = malloc(80);
    
    int lines_in_file = get_num_filelines();

    char * *category_list = malloc(sizeof(char*) * (lines_in_file + 1));
    
    int i = 0;
    
    while (fgets(line, MAX_STRING_LENGTH, fp) != 0) {
   
        // Remove trailing '\n' from line
        *(line + strlen(line) - 1) = '\0';
        
        char * category = malloc(80);
        strcpy(category, line);
        
        *(category_list + i) = category;
        
        i++;
        
    }
    
    *(category_list + i) = NULL;
    
    fclose(fp);
    
    cats = category_list;
    printf("DEBUG addrees of cats: %d\n", cats);
    printf("DEBUG addrees of category_list: %d\n", category_list);
}
```

And the function that calls it:

```
void Money::testSlot()
{
    /* I'll worry about allocating the correct amount later.. */
    char ** categories = (char **)malloc(100);
    
    expense_cats_get(categories, "categories.txt");
    
    printf("DEBUG: address (in calling function) = %d\n", categories);
    
}
```

Here's the output:

```
> ./money
DEBUG addrees of cats: 694194720
DEBUG addrees of category_list: 694194720
DEBUG: address (in calling function) = 694758400
Segmentation fault (core dumped)
```

Why oh why oh why are the two memory addresses different?


----------



## expl (Jan 15, 2011)

You really need to understand how functions work, all arguments are pushed to the function's stack. So basically if you pass something to the function it will duplicate it in its stack. If you modify it, it will not modify the memory caller was using. What happened you passed a pointer, ok you can put something to the memory it is pointing to, but if you modify the pointer itself you will just change your duplicate and original pointer will stay the same. So to go around this you either need to return new pointer or pass pointer of a pointer as an argument.


----------



## caesius (Jan 15, 2011)

expl said:
			
		

> You really need to understand how functions work, all arguments are pushed to the function's stack. So basically if you pass something to the function it will duplicate it in its stack. If you modify it, it will not modify the memory caller was using. What happened you passed a pointer, ok you can put something to the memory it is pointing to, but if you modify the pointer itself you will just change your duplicate and original pointer will stay the same. So to go around this you either need to return new pointer or pass pointer of a pointer as an argument.



Thanks for reply again. 

> ..or pass pointer of a pointer as an argument.

But aren't I already doing this?


```
expense_cats_get(char ** cats, const char * filename)
```

cats is a "pointer of a pointer" right?

Cheers.


----------



## expl (Jan 15, 2011)

It is... Well let me rephrase myself, "pointer of a pointer of a pointer" in your case


----------



## caesius (Jan 15, 2011)

Ahh I see. Thank you very much for your help


----------



## Alt (Jan 15, 2011)

```
char * category = malloc(80);
        strcpy(category, line);
```
Do not do that. You should do like this
	
	



```
char * category = malloc(strlen(line)+1);
        strcpy(category, line);
```
or this
	
	



```
char * category = malloc(80);
        strncpy(category, line, 80);
```


----------

