473,406 Members | 2,894 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,406 software developers and data experts.

char *arr[n] Vs. char **arr

I need to break a longer string (with strtok()) and store the smaller
strings in an array. since the number of small strings is not
fixed/known, I cannot use a declaration like char *format[n], so I
declared char** format = NULL;

Now the problem starts. Each time strtok() returns me a token (which is
char*), I call malloc() and I (want to) store the address returned in
the array format[], and copy the token to that address.

code snippet:
------------------
char **format = NULL;
char delim[] = ".-/:";
int i=0;

if ((tok = strtok(argv[1], delim)) != NULL)
{
if((format[i]=(char*)malloc(strlen(tok))) != NULL)
strcpy(format+i, tok);
}

for (i=1; tok; i++)
{
if ((tok = strtok(NULL, delim)) != NULL)
if((format[i]=(char*)malloc(strlen(tok))) != NULL)
strcpy(format+i, tok);
}

The malloc statement gives a segfault. In desparation, I have tried
various combinations of lvalue in malloc, but none of them were correct
(either I get a compiler warning like "invalid lvalue", or "assignment
makes an integer from pointer" etc.. or if compilation is successful,
run always fails with a segfault)

Q: Is above approach fundamentally incorrect? Can I declare something
as a pointer to pointer to char & treat like an array of strings? If
yes, what's wrong in above code? I have no hesitation in admitting that
my pointer fundamentals are not very clear yet -:)
~yogesh

Jul 17 '06 #1
10 4918
Yogesh,

if((format[i]=(char*)malloc(strlen(tok))) != NULL)
strcpy(format+i, tok);
For sake of simplicity if we assume format is 2-d array, i.e. array of
String, where string itself is array of char.
you are allocating memory @ ith element of format array. (line 1,
above)
you are copying the string @ format+i ---format[0]+i , i.e. on 1st
location.

I am not much more sure. but this may be the likely catch.

yes, what's wrong in above code? I have no hesitation in admitting that
my pointer fundamentals are not very clear yet -:)
~yogesh

Raxit

Jul 17 '06 #2
"yogeshmk" <yo***************@gmail.comwrote:
I need to break a longer string (with strtok()) and store the smaller
strings in an array.
This in itself has its snares; for example, you do know that strtok()
demolishes the string it works on, don't you?
char **format = NULL;
char delim[] = ".-/:";
int i=0;

if ((tok = strtok(argv[1], delim)) != NULL)
{
if((format[i]=(char*)malloc(strlen(tok))) != NULL)
Two problems in this line. First, there is no need to cast malloc(), and
in fact doing so can hide the error of forgetting to #include
<stdlib.h>, which causes undefined behaviour.
Second, you want to allocate memory for the string _including_ its
terminating null character.
So this line should be:

if ((format[i]=malloc(strlen(tok)+1)) != NULL)

Ditto later on.
The major problem, however, is that you do allocate memory for the
individual strings, but not for the array (format) that contains all the
pointers themselves. So while would you copy the strings OK, everything
you write _to_ format itself goes to limbo.

This FAQ might help: <http://c-faq.com/aryptr/dynmuldimary.html>,
although in your case you don't know in advance how many strings you
have so you'd have to use realloc() on format as well.

Richard
Jul 17 '06 #3
Richard Bos wrote:
"yogeshmk" <yo***************@gmail.comwrote:
I need to break a longer string (with strtok()) and store the smaller
strings in an array.

This in itself has its snares; for example, you do know that strtok()
demolishes the string it works on, don't you?
you caught me- :) (but I'm not going to use argv[1] again so it should
not be a problem)
>
char **format = NULL;
char delim[] = ".-/:";
int i=0;

if ((tok = strtok(argv[1], delim)) != NULL)
{
if((format[i]=(char*)malloc(strlen(tok))) != NULL)

Two problems in this line. First, there is no need to cast malloc(), and
in fact doing so can hide the error of forgetting to #include
<stdlib.h>, which causes undefined behaviour.
I did not understand the above point.
Second, you want to allocate memory for the string _including_ its
terminating null character.
So this line should be:

if ((format[i]=malloc(strlen(tok)+1)) != NULL)

Ditto later on.
The major problem, however, is that you do allocate memory for the
individual strings, but not for the array (format) that contains all the
pointers themselves. So while would you copy the strings OK, everything
you write _to_ format itself goes to limbo.

This FAQ might help: <http://c-faq.com/aryptr/dynmuldimary.html>,
although in your case you don't know in advance how many strings you
have so you'd have to use realloc() on format as well.

Richard
I'm pasting the changed code

if ((tok = strtok(argv[1], delim)) != NULL)
{
format = (char**)malloc(1*sizeof(char*));
if((format[i]=(char*)malloc(strlen(tok)+1)) != NULL)
strcpy((char*)format+i, tok);
}
/*
* gdb shows the first token copied at 0th location of format .
*/
for (i=1; tok; i++)
{
if ((tok = strtok(NULL, delim)) != NULL)
if (format = (char**)realloc(format, (i+1)*sizeof(char*))
!= NULL)
if((format[i]=(char*)malloc(strlen(tok)+1)) != NULL)
strcpy((char*)format+i, tok);
}

realloc() changes the address of format (something like 0x1) and
subsequent malloc() fails giving a segfault. Still scratching my head!
What's wrong in the code?
~yogesh

Jul 17 '06 #4

yogeshmk wrote:
I need to break a longer string (with strtok()) and store the smaller
strings in an array. since the number of small strings is not
fixed/known, I cannot use a declaration like char *format[n], so I
declared char** format = NULL;

Now the problem starts. Each time strtok() returns me a token (which is
char*), I call malloc() and I (want to) store the address returned in
the array format[], and copy the token to that address.

code snippet:
------------------
char **format = NULL;
char delim[] = ".-/:";
int i=0;

if ((tok = strtok(argv[1], delim)) != NULL)
{
if((format[i]=(char*)malloc(strlen(tok))) != NULL)
strcpy(format+i, tok);
}

for (i=1; tok; i++)
{
if ((tok = strtok(NULL, delim)) != NULL)
if((format[i]=(char*)malloc(strlen(tok))) != NULL)
strcpy(format+i, tok);
}

The malloc statement gives a segfault. In desparation, I have tried
various combinations of lvalue in malloc, but none of them were correct
(either I get a compiler warning like "invalid lvalue", or "assignment
makes an integer from pointer" etc.. or if compilation is successful,
run always fails with a segfault)

Q: Is above approach fundamentally incorrect? Can I declare something
as a pointer to pointer to char & treat like an array of strings? If
yes, what's wrong in above code? I have no hesitation in admitting that
my pointer fundamentals are not very clear yet -:)
Yogesh.
You didn't allocated memory for double pointer.
You are mallocing only for the strings.

This will solve the problem.
test_string = (char **) malloc (sizeof(char *) * n);

But it will lead to the issue of the size of row.
~yogesh
Jul 17 '06 #5

yogeshmk wrote:
I need to break a longer string (with strtok()) and store the smaller
strings in an array. since the number of small strings is not
fixed/known, I cannot use a declaration like char *format[n], so I
declared char** format = NULL;

Now the problem starts. Each time strtok() returns me a token (which is
char*), I call malloc() and I (want to) store the address returned in
the array format[], and copy the token to that address.

code snippet:
------------------
char **format = NULL;
char delim[] = ".-/:";
int i=0;

if ((tok = strtok(argv[1], delim)) != NULL)
{
if((format[i]=(char*)malloc(strlen(tok))) != NULL)
strcpy(format+i, tok);
}

for (i=1; tok; i++)
{
if ((tok = strtok(NULL, delim)) != NULL)
if((format[i]=(char*)malloc(strlen(tok))) != NULL)
strcpy(format+i, tok);
}

The malloc statement gives a segfault. In desparation, I have tried
various combinations of lvalue in malloc, but none of them were correct
(either I get a compiler warning like "invalid lvalue", or "assignment
makes an integer from pointer" etc.. or if compilation is successful,
run always fails with a segfault)

Q: Is above approach fundamentally incorrect? Can I declare something
as a pointer to pointer to char & treat like an array of strings? If
yes, what's wrong in above code? I have no hesitation in admitting that
my pointer fundamentals are not very clear yet -:)
Try this code.
It's just a casual one. I din't freed malloced variable etc.

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

main(int argc, char *argv[])
{
/* Copy the constant into the memory
* pinted to by 'test_string'
*/
char **test_string;

/* if 'test_string' is declared as below and the program will
give a
* 'Segmentation fault' This is because test_string' is
pointing
* to a constant i.e. somethin that cant be changed.

char *test_string="string to split up"; */

char *sub_string;
int i=0;
/* Extract first string */

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

if ((sub_string = strtok(argv[1], "a")) != NULL){
*(test_string + i) = (char *) malloc (strlen(sub_string) + 1);
*(test_string + i) = sub_string;
printf ("%s\n", *test_string);
}
i++;
/* Extract remaining
* strings */
while ( (sub_string=strtok(NULL, "a")) != NULL)
{
*(test_string + i) = (char *) malloc (strlen(sub_string) + 1);
*(test_string + i) = sub_string;
printf("%s\t%s\n", *(test_string + i));
i++;
}
}
~yogesh
Jul 17 '06 #6
On 17 Jul 2006 06:49:23 -0700, "deepak" <de*********@gmail.comwrote:
>
yogeshmk wrote:
>I need to break a longer string (with strtok()) and store the smaller
strings in an array. since the number of small strings is not
fixed/known, I cannot use a declaration like char *format[n], so I
declared char** format = NULL;

Now the problem starts. Each time strtok() returns me a token (which is
char*), I call malloc() and I (want to) store the address returned in
the array format[], and copy the token to that address.

code snippet:
------------------
char **format = NULL;
char delim[] = ".-/:";
int i=0;

if ((tok = strtok(argv[1], delim)) != NULL)
{
if((format[i]=(char*)malloc(strlen(tok))) != NULL)
strcpy(format+i, tok);
}

for (i=1; tok; i++)
{
if ((tok = strtok(NULL, delim)) != NULL)
if((format[i]=(char*)malloc(strlen(tok))) != NULL)
strcpy(format+i, tok);
}

The malloc statement gives a segfault. In desparation, I have tried
various combinations of lvalue in malloc, but none of them were correct
(either I get a compiler warning like "invalid lvalue", or "assignment
makes an integer from pointer" etc.. or if compilation is successful,
run always fails with a segfault)

Q: Is above approach fundamentally incorrect? Can I declare something
as a pointer to pointer to char & treat like an array of strings? If
yes, what's wrong in above code? I have no hesitation in admitting that
my pointer fundamentals are not very clear yet -:)

Try this code.
It's just a casual one. I din't freed malloced variable etc.

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

main(int argc, char *argv[])
{
/* Copy the constant into the memory
* pinted to by 'test_string'
*/
char **test_string;

/* if 'test_string' is declared as below and the program will
give a
* 'Segmentation fault' This is because test_string' is
pointing
* to a constant i.e. somethin that cant be changed.

char *test_string="string to split up"; */

char *sub_string;
int i=0;
/* Extract first string */

test_string = (char **) malloc (sizeof(char *) * 10);
Don't cast the return from malloc. It never helps and can hide a
diagnostic regarding undefined behavior which you would really want to
see.
>
if ((sub_string = strtok(argv[1], "a")) != NULL){
*(test_string + i) = (char *) malloc (strlen(sub_string) + 1);
While *(test_string + i) is correct, the equivalent test_string[i] is
the more common and preferred idiom. But i is always zero in this
block of code anyway.
*(test_string + i) = sub_string;
Definitely not. This causes a memory leak by destroying the only
pointer to the allocated memory. If you went to all the trouble to
allocate space for the string pointed to by sub_string, then you want
strcpy(test_string[i], sub_string);
printf ("%s\n", *test_string);
}
i++;
/* Extract remaining
* strings */
while ( (sub_string=strtok(NULL, "a")) != NULL)
{
*(test_string + i) = (char *) malloc (strlen(sub_string) + 1);
*(test_string + i) = sub_string;
printf("%s\t%s\n", *(test_string + i));
i++;
}
}
>~yogesh

Remove del for email
Jul 17 '06 #7
On 17 Jul 2006 04:17:40 -0700, "yogeshmk"
<yo***************@gmail.comwrote:
>I need to break a longer string (with strtok()) and store the smaller
strings in an array. since the number of small strings is not
fixed/known, I cannot use a declaration like char *format[n], so I
declared char** format = NULL;

Now the problem starts. Each time strtok() returns me a token (which is
char*), I call malloc() and I (want to) store the address returned in
the array format[], and copy the token to that address.
As you note in a subsequent message, you don't use the original string
(in argv[1]) after strtok tokenizes it so the question is why copy
each token when you could use it in place.
>
code snippet:
------------------
char **format = NULL;
char delim[] = ".-/:";
int i=0;

if ((tok = strtok(argv[1], delim)) != NULL)
{
if((format[i]=(char*)malloc(strlen(tok))) != NULL)
format[i] requires format to be dereferenced. Where does format point
to?

strlen does not count the terminating '\0' but strcpy does copy it.
You are allocating one byte too few.

Don't cast the return from malloc. It never helps and can hide a
diagnostic regarding undefined behavior which you would really want to
see.
strcpy(format+i, tok);
The address of the allocated area is in format[i]. format+i is a
completely different location in memory. If you meant *(format+i), I
recommend using the syntactically equivalent but much easier to read
format[i].
}

for (i=1; tok; i++)
{
if ((tok = strtok(NULL, delim)) != NULL)
if((format[i]=(char*)malloc(strlen(tok))) != NULL)
strcpy(format+i, tok);
}

The malloc statement gives a segfault. In desparation, I have tried
various combinations of lvalue in malloc, but none of them were correct
(either I get a compiler warning like "invalid lvalue", or "assignment
makes an integer from pointer" etc.. or if compilation is successful,
run always fails with a segfault)
A desirable result since format was never initialized to point
somewhere. The best kind of undefined behavior is the kind that stops
your program when the behavior occurs rather than letting things
proceed till something else goes wrong.
>
Q: Is above approach fundamentally incorrect? Can I declare something
The approach is OK, you just missed some details.
>as a pointer to pointer to char & treat like an array of strings? If
Yes, after you initialize it properly.
>yes, what's wrong in above code? I have no hesitation in admitting that
my pointer fundamentals are not very clear yet -:)
~yogesh
You need to allocate space for format to point to N (some number) of
objects of type *format.

As you tokenize each string, you need to initialize the next available
object with the address of an allocated block large enough to hold the
token and its terminator. Then you copy the token into this memory.

When you are about to process the N+1th token, you need to reallocate
the memory format points to so that it points to more than N objects.
How much more is a design decision you get to make. Some increment by
1 or other small fixed quantity; some decide to double N. This
reallocation sets a new upper limit which you must continue to check
against as you continue copying tokens. Depending on the number of
tokens in your original string, you may need to perform this
reallocation multiple times.
Remove del for email
Jul 17 '06 #8
yogeshmk wrote:
Richard Bos wrote:
Two problems in this line. First, there is no need to cast
malloc(), and in fact doing so can hide the error of forgetting to
#include <stdlib.h>, which causes undefined behaviour.

I did not understand the above point.
http://c-faq.com/malloc/cast.html
http://c-faq.com/malloc/mallocnocast.html


Brian
Jul 17 '06 #9
yogeshmk wrote:
I'm pasting the changed code

if ((tok = strtok(argv[1], delim)) != NULL)
{
format = (char**)malloc(1*sizeof(char*));
Why not just write:
format = malloc(sizeof *format);

Here, format is a char **
*format is a char *
**format is a char

So, sizeof *format == sizeof (char*)
if((format[i]=(char*)malloc(strlen(tok)+1)) != NULL)
strcpy((char*)format+i, tok);
This is wrong! The fact that you needed a cast should be a big red flag,
indicating to you that what you are typing is wrong!

You don't want to copy to format+i. That's the start of the format
array, which can only hold sizeof(char*), probably just 4 bytes.

You want to copy to format[i]. That's the memory that you just allocated
with malloc.
}
/*
* gdb shows the first token copied at 0th location of format .
*/
As it should -- you told strcpy to copy there. Unfortunately you
probably also copied to some bytes past what was allocated to format,
which you had no right to write to.
for (i=1; tok; i++)
{
if ((tok = strtok(NULL, delim)) != NULL)
if (format = (char**)realloc(format, (i+1)*sizeof(char*))
!= NULL)
Please, for the love of God, get rid of the casts!

What you have written in the line above will work, but it's best
practise to send the result of realloc to a separate temporary variable,
so that if realloc fails, you don't lose your pointer to the original array.

I would write:
char **temp;
if(temp = realloc(format, (i+1) * sizeof *format)) != NULL)
{
format = temp;
...
}
else /* realloc failed */
{
return format;
}

if((format[i]=(char*)malloc(strlen(tok)+1)) != NULL)
strcpy((char*)format+i, tok);
Again, this should be strcpy(format[i], tok);
}

realloc() changes the address of format (something like 0x1) and
subsequent malloc() fails giving a segfault. Still scratching my head!
What's wrong in the code?
realloc often changes the address. This is how it usually works: it
first allocates a new block of memory, then copies the contents of the
old block into the new block, then returns the address of the new block.

The subsequent malloc fails because you wrote too far into the memory
allocated for format, clobbering the special data structures that are
used by the memory allocation system to keep track of your memory
allocations.

If you fix the bug with the strcpy, it should work.

--
Simon.
Jul 17 '06 #10

Barry Schwarz wrote:
On 17 Jul 2006 06:49:23 -0700, "deepak" <de*********@gmail.comwrote:

yogeshmk wrote:
I need to break a longer string (with strtok()) and store the smaller
strings in an array. since the number of small strings is not
fixed/known, I cannot use a declaration like char *format[n], so I
declared char** format = NULL;

Now the problem starts. Each time strtok() returns me a token (which is
char*), I call malloc() and I (want to) store the address returned in
the array format[], and copy the token to that address.

code snippet:
------------------
char **format = NULL;
char delim[] = ".-/:";
int i=0;

if ((tok = strtok(argv[1], delim)) != NULL)
{
if((format[i]=(char*)malloc(strlen(tok))) != NULL)
strcpy(format+i, tok);
}

for (i=1; tok; i++)
{
if ((tok = strtok(NULL, delim)) != NULL)
if((format[i]=(char*)malloc(strlen(tok))) != NULL)
strcpy(format+i, tok);
}

The malloc statement gives a segfault. In desparation, I have tried
various combinations of lvalue in malloc, but none of them were correct
(either I get a compiler warning like "invalid lvalue", or "assignment
makes an integer from pointer" etc.. or if compilation is successful,
run always fails with a segfault)

Q: Is above approach fundamentally incorrect? Can I declare something
as a pointer to pointer to char & treat like an array of strings? If
yes, what's wrong in above code? I have no hesitation in admitting that
my pointer fundamentals are not very clear yet -:)
Try this code.
It's just a casual one. I din't freed malloced variable etc.

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

main(int argc, char *argv[])
{
/* Copy the constant into the memory
* pinted to by 'test_string'
*/
char **test_string;

/* if 'test_string' is declared as below and the program will
give a
* 'Segmentation fault' This is because test_string' is
pointing
* to a constant i.e. somethin that cant be changed.

char *test_string="string to split up"; */

char *sub_string;
int i=0;
/* Extract first string */

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

Don't cast the return from malloc. It never helps and can hide a
diagnostic regarding undefined behavior which you would really want to
see.

if ((sub_string = strtok(argv[1], "a")) != NULL){
*(test_string + i) = (char *) malloc (strlen(sub_string) + 1);

While *(test_string + i) is correct, the equivalent test_string[i] is
the more common and preferred idiom. But i is always zero in this
block of code anyway.
*(test_string + i) = sub_string;

Definitely not. This causes a memory leak by destroying the only
pointer to the allocated memory. If you went to all the trouble to
allocate space for the string pointed to by sub_string, then you want
strcpy(test_string[i], sub_string);
Hello Shwarzer,
Thanks for the update.
I never digged about such a problem and from now onwards i'll follow
it.
>
printf ("%s\n", *test_string);
}
i++;
/* Extract remaining
* strings */
while ( (sub_string=strtok(NULL, "a")) != NULL)
{
*(test_string + i) = (char *) malloc (strlen(sub_string) + 1);
*(test_string + i) = sub_string;
printf("%s\t%s\n", *(test_string + i));
i++;
}
}
~yogesh


Remove del for email
Jul 18 '06 #11

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

4
by: muroogan | last post by:
I read a text file into a char variable char tchar; I want to trim leading spaces (Left trim).How can I do that in C++. Any input will be appreciated.
43
by: M-One | last post by:
See subject: how do I calloc (and free the memory, if that's not free(my_bytes);) this? TIA!
15
by: Gregg Woodcock | last post by:
My compiler (m68k-gcc) does not allow this (simplified example; not my real code) and I don't see why not: { char *arrayCharPtr1 = {"a", "ab", NULL}; char *arrayCharPtr2 = {"A", "AB", NULL};...
51
by: Pedro Graca | last post by:
I run into a strange warning (for me) today (I was trying to improve the score of the UVA #10018 Programming Challenge). $ gcc -W -Wall -std=c89 -pedantic -O2 10018-clc.c -o 10018-clc...
27
by: sam_cit | last post by:
Hi, I needed help in converting a character to the correspoding hexadecimal values, like the following example, ASCII value : ABC Hex Code Value : %41%42%43... whats the logic of conversion...
3
by: gevadas | last post by:
sample program #include <iostream> #include <vector> using namespace std; int find(char*& value,char** arr,int size) { for(int i = 0;i < size;i++)
9
by: Gregory.A.Book | last post by:
I am interested in converting sets of 4 bytes to floats in C++. I have a library that reads image data and returns the data as an array of unsigned chars. The image data is stored as 4-byte floats....
18
by: Pedro Pinto | last post by:
Hi there once more........ Instead of showing all the code my problem is simple. I've tried to create this function: char temp(char *string){ alterString(string); return string;
21
by: arnuld | last post by:
int main() { const char* arr = {"bjarne", "stroustrup", "c++"}; char* parr = &arr; } this gives an error: $ g++ test.cpp test.cpp: In function 'int main()': test.cpp:4: error: cannot...
6
by: Jai Prabhu | last post by:
Hi All, Consider the following piece of code: void func (void) { static unsigned char arr = "\x00\xAA\xBB"; fprintf (stderr, "0x%x\n", arr); fprintf (stderr, "0x%x\n", arr);
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.