954,480 Members — Technology Publication meets Social Media
Username:
Password:
Lost login information?
Have something to say? Contribute New Article Reply to this Article

char** for string array problem

Hi, I use char* for string handling because I read strings from a file and I don't know the length of these strings. The problem comes when I need to keep some strings in an array. I think char** is the best thing for that goal. But again since I don't know how many strings I will hold, I'm stuck in allocating memory for new strings to be hold. For example;

char* str;
    char** match_list;
while (fscanf(inp, "%s", str) != EOF) {
        if (matches(str)) {
            *match_list = (char**)malloc(sizeof(char*));
            *(match_list + i) = str;
            i++;
        }
    }


matches is the function checks the string for my intention. The line that malloc is included is a bit silly, I know :). I need to access the strings in future. I think I could explain my problem. I want to allocate a new char* space and bind my str to it. But how?
Thanks...

pdrino
Newbie Poster
10 posts since Dec 2007
Reputation Points: 11
Solved Threads: 0
 

Let's start by clearing up an obvious misunderstanding about pointers.

>char *str;
>fscanf(inp, "%s", str);
This is broken. An uninitialized pointer does not mean a pointer to unlimited space. It means you're not allowed to dereference that pointer or compare it to anything until you initialize it.

You still need to guesstimate a size for reading strings from input, even if that size is a chunk and you append the chunks using dynamic memory. Get that right and then you can worry about an array of strings, because the solution is very similar.

Narue
Bad Cop
Administrator
15,460 posts since Sep 2004
Reputation Points: 6,464
Solved Threads: 1,401
 

Well I really couldn't get what you meant but I will answer to the point I think you asked...k

Well you can allocate two dimensional array as follows:

char **array; //Your two dimensional array
int str_nos=10; //No of strings you want to have
int str_len=60; //Maximum length of each string
array=malloc( str_nos * sizeof(char *) );
//Above st allocates memory for no of char pointers or strings
for(i=0;i<str_nos;i++)
{
a[i]=malloc( str_len * sizeof(char *) );
}


In this way you can dynamically allocate the number of strings and also their lengths by just altering he str_nos and str_len .I hope this helps :)

csurfer
Posting Pro
568 posts since Jan 2009
Reputation Points: 485
Solved Threads: 88
 

Just a tip: since you are reallocating new memory when you run out of space, you probably want to use realloc . This will keep all the data you had copied into your array previously.

death_oclock
Posting Whiz
393 posts since Apr 2006
Reputation Points: 129
Solved Threads: 45
 

instead of using malloc() (or realloc) poorly.... might i suggest sticking with the tried and true:

char stringblock[MAX_NUM_LINES][MAX_LINE_LEN];

because i'm fairly certain you're not doing an embedded application that is limited for RAM.

but mangling malloc() like you're doing will certainly find the limits of your computer memory after you fill it full of leaks.

jephthah
Posting Maven
2,587 posts since Feb 2008
Reputation Points: 2,143
Solved Threads: 179
 

@Narue:
>char *str;
>fscanf(inp, "%s", str);
This is broken. An uninitialized pointer does not mean a pointer to unlimited space. It means you're not allowed to dereference that pointer or compare it to anything until you initialize it.

thanks for reply. although you said it is broken I initialize the str every time I read a word from the file. After initialziation I work with str and matches function work properly.

@csurfer:In this way you can dynamically allocate the number of strings and also their lengths by just altering he str_nos and str_len .I hope this helps

Thanks for reply but in your way I think i have to read file twice to have a correct size of match list. Isn't that a problem for performance when reading big files?

@jephthah:char stringblock[MAX_NUM_LINES][MAX_LINE_LEN];

Thanks for reply. I don't know what will be the values of MAX_NUM_LINES and MAX_LINE_LEN values before I read the file and changing these values is not possible after run time I think.

@death_oclock:Just a tip: since you are reallocating new memory when you run out of space, you probably want to use realloc. This will keep all the data you had copied into your array previously.

Is that possible I allocate one char* space beforehand and reallaocate space one by one after I found new words that matches my specifications? Using that way make sense but I have a char* named str and I want to keep that pointer in an array named match_list. As I wrote on the code it is char** type. I don't know how to tie these values. Thanks

pdrino
Newbie Poster
10 posts since Dec 2007
Reputation Points: 11
Solved Threads: 0
 
jephthah
Posting Maven
2,587 posts since Feb 2008
Reputation Points: 2,143
Solved Threads: 179
 
nm


nm?

pdrino
Newbie Poster
10 posts since Dec 2007
Reputation Points: 11
Solved Threads: 0
 

>although you said it is broken I initialize the str every time I read a word from the file.
Hmm, I can interpret this one of two ways:You're saying the code you posted isn't equivalent to the code you're actually using.
You're saying that I'm wrong and the code you posted isn't broken.
If it's the first case then I would highly recommend that you post equivalent examples to your real code if you want any useful help. If it's the second case then I pity you, because I'm very rarely wrong when it comes to the standard language/library, and when I am it's not the people asking beginner questions who are able to correct me successfully.

Arbitrary length input takes more work, and often the basic input functions are weak without a bit of scaffolding around them to get what you want. For example, here's a delimited string input function that can be used to read words:

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

#define GROW_BY 32 /* Arbitrary size */

char *reads ( FILE *in, char *delim )
{
    char *result = NULL;
    size_t size = 0;
    size_t capacity = 0;
    int ch;

    while ( ( ch = getc ( in ) ) != EOF ) {
        if ( size == capacity ) {
            char *temp;

            capacity += GROW_BY;
            temp = realloc ( result, capacity + 1 );

            if ( temp == NULL ) {
                /*
                  This is a weak solution because it results in
                  loss of data. Recommend better error handling
                */
                free ( result );
                result = NULL;
                break;
            }

            result = temp;
        }

        /* Order is important here; run *after* the resize step */
        if ( strchr ( delim, ch ) != NULL )
            break;

        result[size++] = ch;
    }

    if ( result != NULL )
        result[size] = '\0';

    return result;
}

int main ( void )
{
    char *s;

    while ( ( s = reads ( stdin, " \n" ) ) != NULL ) {
        printf ( ">%s<\n", s );
        free ( s );
    }

    return 0;
}

Take careful note of how I handled the memory, this is a common pattern that you can reuse for an array of pointers to char. You can use this example to neatly fix your broken codeand find the answer to the original problem of creating a dynamic array. You're welcome.

Narue
Bad Cop
Administrator
15,460 posts since Sep 2004
Reputation Points: 6,464
Solved Threads: 1,401
 

In fact it is 2nd case.

because I'm very rarely wrong when it comes to the standard language/library, and when I am it's not the people asking beginner questions who are able to correct me successfully.

Also if you have a big experience then you should know it is not a big deal that people can correct you. If you are uncomfortable with that using forums is not suitable for you. I'm not saying I am an expert but you are wrong about what you've written in previous post. Technically speaking, I initialize and reinitiaize str pointer with every word I read from file. It is not a char pointer array it is just a char pointer. After that I make comparison or whatever I need. At least I know that is possible and I suggest you to accept your fault. I don't want to be offending but if you want I could send you the code. Because it is one of my friend's project I prefer not to publish it here.

pdrino
Newbie Poster
10 posts since Dec 2007
Reputation Points: 11
Solved Threads: 0
 

since you apparently don't know how to use malloc without mangling it, i suggested you use

char stringblock[MAX_NUM_LINES][MAX_LINE_LEN];
and you replied I don't know what will be the values of MAX_NUM_LINES and MAX_LINE_LEN values before I read the file and changing these values is not possible after run time I think.
no, of course you cant change them at runtime. so since you dont know what the values are, use ridiculously high values that will cover any possible values. for instance

#define MAX_LINE_LEN     2024
#define MAX_NUM_LINES     512

memory is cheap. what's 1 Meg of memory when you've likely got 1 Gig of RAM? it's better than broken code full of memory leaks because so many programmers have no clue how to properly allocate dynamic memory.

but, really ... go on and use malloc to shoot yourself in the foot. i'm just sticking around for this:In fact it is 2nd case.
Also if you [Narue] have a big experience then you should know it is not a big deal that people can correct you. If you are uncomfortable with that using forums is not suitable for you. I'm not saying I am an expert but you are wrong about what you've written in previous post. Technically speaking, I initialize and reinitiaize str pointer with every word I read from file. It is not a char pointer array it is just a char pointer. After that I make comparison or whatever I need. At least I know that is possible and I suggest you to accept your fault.

*grabs the popcorn*

:D


.

jephthah
Posting Maven
2,587 posts since Feb 2008
Reputation Points: 2,143
Solved Threads: 179
 

Thanks for explanation. Apparently I don't know usage of malloc :) I'm not a c programmer just helping one of my friends. I used c 3 years ago for just a project. After that I've never used it. I have a different question about my topic. I finished the work but I saw a weird thing while coding. I get segmentation fault after adding some new lines and I delete one by one (of course logically:)). But the segmentation fault happens when I declare a new variable.
It was just int k=0; but adding this caused segmentation fault. As I know segmentation fault occurs when I try to an unallowed/unallocated space in memory. For example like int i=array[5]; while array has the length of 4 causes segfault. But declaring a new variable causes that? I didn't understand anything :S

pdrino
Newbie Poster
10 posts since Dec 2007
Reputation Points: 11
Solved Threads: 0
 
Apparently I don't know usage of malloc

welcome to Daniweb. i'd say of all the people who come in here asking questions that have malloc() somewhere in their code, 90% of them don't have any real concept of how to use it properly. But you're one of the lucky ones: admitting you're powerless is the First Step. now you can stop the abuse cycle, and start the recovery process.As I know segmentation fault occurs when I try to an unallowed/unallocated space in memory.

then why are you arguing with NARUE about your use of uninitialized pointers?

jephthah
Posting Maven
2,587 posts since Feb 2008
Reputation Points: 2,143
Solved Threads: 179
 

oh, I see you misunderstood me. Pointers work properly. My problem is when I add a new variable I get segfault. I just add

int k=0;

line and segfault occurs. I didn't even use it. Just declared it. Am i using too much memory?

edit: I forgot to say I tried to change the name and type of the variable.

pdrino
Newbie Poster
10 posts since Dec 2007
Reputation Points: 11
Solved Threads: 0
 

>Technically speaking, I initialize and reinitiaize str pointer with every word I read from file.
You clearly don't understand how memory works in C. Either you use static memory, in which case the compiler takes care of allocation and deallocation, or you have to take care of it yourself (dynamic memory). You can't just expect memory to be there if you're using pointers; if you want to store something with a pointer, the pointer needs to point to allocated memory. "Initializing the pointer" just isn't going to cut it. Afterward, it's your responsibility to deallocate the memory once you're done using it. If you can't handle this kind of responsibility, you shouldn't be using dynamic memory.

Bad memory management is just a segfault waiting to happen. Just because it doesn't occur with a sample of code doesn't mean that it's okay; often times another innocent declaration will be the final push to making your program crap out.

John A
Vampirical Lurker
Team Colleague
7,630 posts since Apr 2006
Reputation Points: 2,240
Solved Threads: 339
 

>Also if you have a big experience then you should
>know it is not a big deal that people can correct you.
It's not a big deal at all...when they're right. Just because you think you're right doesn't mean you are.

>I'm not saying I am an expert but you are wrong
>about what you've written in previous post.
Prove it. I can prove that until you initialize a pointer with an address to memory that you own (ie. an existing array or calling malloc), you invoke undefined behavior. Sometimes undefined behavior appears to work just fine, which is likely what's happening in your case. But "works for me" is a far cry from "correct and bug free".

So tell me, are you truly saying that you believe the following code is 100% correct, that scanf magically allocates memory to s or that s magically points to infinite memory, and that I'm completely wrong in saying that it's broken?

#include <stdio.h>

int main ( void )
{
  char *s;

  if ( scanf ( "%s", s ) == 1 )
    puts ( s );

  return 0;
}
Narue
Bad Cop
Administrator
15,460 posts since Sep 2004
Reputation Points: 6,464
Solved Threads: 1,401
 
char* str;
    char** match_list;
while (fscanf(inp, "%s", str) != EOF) {
        if (matches(str)) {
            *match_list = (char**)malloc(sizeof(char*));
            *(match_list + i) = str;
            i++;
        }
    }


You can try this one......

char* str;
    char** match_list;
     int len;
while (fscanf(inp, "%s", str) != EOF) {
        if (matches(str)) {
            len=strlen(str); 
            *(match_list+i) = (char*)malloc(len*sizeof(char*));
            strcpy(*(match_list+i),str);
            i++;
        }
    }
hiraksarkardg
Light Poster
27 posts since Sep 2008
Reputation Points: 5
Solved Threads: 3
 

>You can try this one......
Why try something that obviously won't work?

Narue
Bad Cop
Administrator
15,460 posts since Sep 2004
Reputation Points: 6,464
Solved Threads: 1,401
 
You can try this one...... char* str; while (fscanf(inp, "%s", str) != EOF) {


What size of memory isstr pointing to? You don't know. You haven't given it any meaningful space of memory. Therefore you cannot use it with fscanf(), because it will overwrite unknown memory.

Aia
Nearly a Posting Maven
2,392 posts since Dec 2006
Reputation Points: 2,224
Solved Threads: 218
 

This article has been dead for over three months

Post: Markdown Syntax: Formatting Help
You