Register forum user name Search FAQ

Gammon Forum

Notice: Any messages purporting to come from this site telling you that your password has expired, or that you need to verify your details, confirm your email, resolve issues, making threats, or asking for money, are spam. We do not email users with any such messages. If you have lost your password you can obtain a new one by using the password reset link.

Due to spam on this forum, all posts now need moderator approval.

 Entire forum ➜ Programming ➜ General ➜ Multi-Dimensional Char Arrays -- HELP!!

Multi-Dimensional Char Arrays -- HELP!!

It is now over 60 days since the last post. This thread is closed.     Refresh page


Pages: 1  2 3  4  

Posted by TheTraveller   (23 posts)  Bio
Date Reply #15 on Wed 16 Jan 2008 08:03 AM (UTC)
Message
I tried a few educated guesses on my own, but they all resulted in Mr. Segmentation Fault again. I'm sure this is an extremely simple question, but I'm completely stumped!
Top

Posted by Isthiriel   (113 posts)  Bio
Date Reply #16 on Thu 17 Jan 2008 06:58 AM (UTC)
Message
Ok, least code possible:
text_to_buffer( sock_new, xpfile->xrowdata_head->next->next->next->next->xdata[2]);


Of course that will segfault if you don't actually have five rows or three fields, and is a nuisance if you're actually trying to walk the list.

So... what I'd do is make a helper function that walks the list for you and returns a sensible error condition if it runs off the end.
void *walk_list(void *head, int len)
{
    while (0 < len-- && NULL != head)
        head = head->next;
    return head;
}

Or, more specifically:
char **mysql_data_from_xmysql(XMYSQL *xmysql, int row)
{
    struct mysql_xrow *xrow = NULL;
    xrow = xmysql->xrowdata_head;
    while (0 < row-- && NULL != xrow)
        xrow = xrow->next;
    if (NULL == xrow)
        return NULL;
    return xrow->xdata;
}

Which can then be used like so:
text_to_buffer( sock_new, mysql_data_from_xmysql( xpfile, 4 )[2] );


You can, of course choose your own (less verbose) name for the function.

It may be more useful to return the actual xrow object rather than the data array, as with the xrow object you can continue walking the list (making it useful to skip some number of rows at the beginning of the list).

It is also trivially modified to use negative numbers to indicate an offset from the end of the list (ie. -1 is the tail, -2 is tail->prev ...)


If mysql_xquery is doing the query, you should probably make it analogous to the mysql_query/mysql_free_result pair, so mysql_xquery (and that's kind of an odd name, wouldn't xmysql_query make more sense?) does the allocation of the xmysql object and xmysql_free_result would then deallocate it (code provided already, as "free_xmysql").

Also, if you only want the one result from a resultset that might span several hundred rows, copying the entire resultset into your object and then promptly destroying is wasteful of cpu cycles. That's why the mysql api has so many functions like fetch_row, fetch_result, ... so you only retrieve the minimum you need. (It helps to tailor your sql too, you should never SELECT * unless you actually need all of the data in the table.)


And, might I add, the space-inside-parentheses style is particularly ugly :P
Top

Posted by David Haley   USA  (3,881 posts)  Bio
Date Reply #17 on Thu 17 Jan 2008 07:38 PM (UTC)
Message
Quote:
And, might I add, the space-inside-parentheses style is particularly ugly :P

Or particularly nice and readable, in some cases...

David Haley aka Ksilyan
Head Programmer,
Legends of the Darkstone

http://david.the-haleys.org
Top

Posted by Isthiriel   (113 posts)  Bio
Date Reply #18 on Thu 17 Jan 2008 09:59 PM (UTC)
Message
I always put space outside parentheses unless it's a function, or a stack of parentheses together.

The only time that's an issue is if you're editing code with a variable width font that makes parentheses to be 2px wide... and that's a problem with your editor :P

Oh, and in LISP/Scheme I'll break up stacked closing parentheses into groups of four to make counting them easier. Not that I write much outside of an editor that knows how to match parentheses.
Top

Posted by David Haley   USA  (3,881 posts)  Bio
Date Reply #19 on Thu 17 Jan 2008 10:53 PM (UTC)
Message
Yes, I was talking about stacks of parentheses, but it bothers me even if I have a fixed-width font. (Well, I never fail to have a fixed-width font when programming, so that point is kind of moot.) It's also not a question of an editor that can match parentheses; it's a question of being able to visually see extremely quickly where an expression breaks into sub-expressions and where those start and stop without needing to use the editor to tell me.

(Arguably, you shouldn't often have complex expressions with sub-expressions, but it does happen sometimes...)

Although, I make a motion to drop this tangent and not hijack the thread, I perhaps should not have started it but I took some exception to your statement. :-P

David Haley aka Ksilyan
Head Programmer,
Legends of the Darkstone

http://david.the-haleys.org
Top

Posted by TheTraveller   (23 posts)  Bio
Date Reply #20 on Fri 18 Jan 2008 05:51 AM (UTC)

Amended on Fri 18 Jan 2008 05:56 AM (UTC) by TheTraveller

Message
Lol I've found that everyone has their own unique style of programming. I always leave a space within the parentheses for functions to differentiate from parentheses used in arithmetic operations. I'm partially blind so every little bit helps.

I'll take a look at your suggestion.
Top

Posted by TheTraveller   (23 posts)  Bio
Date Reply #21 on Fri 18 Jan 2008 10:49 AM (UTC)
Message
It didn't work. I did everything you suggested, no compile errors, but now I'm getting a segmentation fault again.

Specifically, I added this function to mysql.c:

char **mysql_get_xrowdata( XMYSQL *xmysql, int row )
{
struct mysql_xrow *xrow = NULL;
xrow = xmysql->xrowdata_head;
while ( 0 < row-- && NULL != xrow )
{
xrow = xrow->next;
}
if ( NULL == xrow )
{
return NULL;
}
return xrow->xdata;
}


Then I have these 3 lines in the greeting section of socket.c:

sprintf( qtxt, "select * from players where playerid=1" );
xpfile = (XMYSQL *) mysql_xquery( qtxt );
text_to_buffer( sock_new, mysql_get_xrowdata( xpfile, 1 )[2] );



What am I doing wrong now??
Top

Posted by TheTraveller   (23 posts)  Bio
Date Reply #22 on Fri 18 Jan 2008 10:15 PM (UTC)
Message
I did some debugging and narrowed the Segmentation Fault to this line in function mysql_xquery in mysql.c:

/* output fields of each row */
while ( ( row = mysql_fetch_row( res ) ) != NULL )
{



How can that possibly be causing a Segmentation Fault?!?! It worked before I put in the new code you suggested, and I haven't even touched it! Why would it now all of a sudden causing a crash when it's exactly the same as when it worked??
Top

Posted by TheTraveller   (23 posts)  Bio
Date Reply #23 on Fri 18 Jan 2008 10:38 PM (UTC)

Amended on Fri 18 Jan 2008 10:40 PM (UTC) by TheTraveller

Message
Ok I fixed THAT bug on my own. Apparently your function used a variable named row of type int, which was already being used by the xquery function but as a different type. I changed the variable name and that took care of it.

However, later on in the xquery function, I'm getting another Segmentation Fault. Again, the entire function used to work perfectly before I added that other function, so I'm not sure why it would suddenly be not working, unless there's another variable conflict I'm not seeing.

Here's the chunk of code in question:

/* output fields of each row */
while ( ( row = mysql_fetch_row( res ) ) != NULL )
{
struct mysql_xrow *xrow;
column = 0;
xrow = (struct mysql_xrow *) malloc(sizeof(struct mysql_xrow));
xrow->xdata = (char **) malloc(sizeof(char *) * res->field_count);
while ( column < res->field_count )
{
xrow->xdata[column] = (char *) malloc(sizeof(char) * (1 + strlen(row[column])));
if ( totalcols == 9 )
{
exit( 0 );
}
strcpy(xrow->xdata[column], row[column]);
column++;
totalcols++;
}
sqlrow++;
if (NULL == xmysql->xrowdata_tail)
{
xmysql->xrowdata_head = xmysql->xrowdata_tail = xrow;
xrow->next = xrow->prev = NULL;
continue;
}
xrow->prev = xmysql->xrowdata_tail;
xrow->prev->next = xrow;
xrow->next = NULL;
xmysql->xrowdata_tail = xrow;
}


Pay particular attention to this part:

if ( totalcols == 9 )
{
exit( 0 );
}


That's a debug I added to determine exactly where the Segmentation Fault was occuring. It wasn't occuring anywhere in that where loop, not even at the end, but right after its ending bracket it was. So I put in the ifcheck, starting at 1, and kept re-compiling until I got a seg fault, then I subtracted one and started moving it down line-by-line until I hit a seg fault again.

By using this method, I've determined that the following line is causing the Segmentation Fault, but only when the execution reaches the 10th iteration:

xrow->xdata[column] = (char *) malloc(sizeof(char) * (1 + strlen(row[column])));


Could this be evidence of some kind of array buffering problem? But why then did it work before? I don't get it. Doesn't make any sense....
Top

Posted by Isthiriel   (113 posts)  Bio
Date Reply #24 on Sat 19 Jan 2008 (UTC)
Message
Quote:
Apparently your function used a variable named row of type int, which was already being used by the xquery function but as a different type. I changed the variable name and that took care of it.

If the two variables are declared in separate functions there shouldn't be an issue as they exist in non-overlapping scopes...

Quote:
That's a debug I added to determine exactly where the Segmentation Fault was occuring. It wasn't occuring anywhere in that where loop, not even at the end, but right after its ending bracket it was. So I put in the ifcheck, starting at 1, and kept re-compiling until I got a seg fault, then I subtracted one and started moving it down line-by-line until I hit a seg fault again.

That's what trace-writes are for.

Quote:
By using this method, I've determined that the following line is causing the Segmentation Fault, but only when the execution reaches the 10th iteration:

Write the contents of all the variables to somewhere visible (either the mud's built in logging functions, or our friend printf()), one variable / printf statement so the first printf statement that doesn't get printed is the variable access that failed. (In particular you want to see the values of res->field_count, column, row, xrow->xdata[column], row[column] and strlen(row[column]).)

In this case, I'd have to guess that either res->field_count is lying or row[9] is not a valid string... does the table include any NULLs in the 10th column? I think strlen(NULL) might segfault. (What does the C API return for a (SQL) NULL value anyway?)
Top

Posted by TheTraveller   (23 posts)  Bio
Date Reply #25 on Sat 19 Jan 2008 01:29 AM (UTC)

Amended on Sat 19 Jan 2008 01:33 AM (UTC) by TheTraveller

Message
Alrighty, that was what I needed. The 10th column is NULL. As soon as you mentioned that, I knew that had to be it, and sure enough....

Of course, there's now yet ANOTHER Segmentation Fault now (does C ever return any other runtime errors????). The mysql_xquery function is now fine. Now it's coming from the function you provided.

I've narrowed it down this time to this line of your function in mysql.c:

if ( NULL == xrow )
{
return NULL;
}


The code that's calling it is here in socket.c:

sprintf( debugbuf, "%s", mysql_get_xrowdata( xpfile, 1 )[2] );


Obviously, it's crashing because it's passing a NULL value to debugbuf in sprintf, right? First of all, that row/column is not a NULL value, so why is it coming up as NULL in the first place? And secondly, would it be possible to perhaps have it return some kind of string error message (like "ERROR - Data not found!") or something instead of NULL?


--TT

P.S. Here's the entire function again for easy reference:

char **mysql_get_xrowdata( XMYSQL *xmysql, int rownum )
{
struct mysql_xrow *xrow = NULL;
xrow = xmysql->xrowdata_head;
while ( 0 < rownum-- && NULL != xrow )
{
xrow = xrow->next;
}
if ( NULL == xrow )
{
return NULL;
}
return xrow->xdata;
}

Top

Posted by Isthiriel   (113 posts)  Bio
Date Reply #26 on Sat 19 Jan 2008 02:56 AM (UTC)
Message
Right, xrow is NULL iff rownum > number of results returned.

In this case, you either have 0 or 1 result(s) and you're asking for the second result. Which means mysql_get_xrowdata returns NULL and you then attempt to dereference that with the [] operator which segfaults.

I think passing NULL to sprintf is actually handled fairly gracefully?

Alternatively you have < 3 fields. (And the segfault is then because the char ** is valid, but the [2] runs past the end of the array.)

While it's possible to return a string error message, it's kind of difficult.

To start with you're returning a char ** which should be an array of strings, not a single string. Secondly, unless you are going to check for the error message and free it appropriately after the function returns, the memory the string is residing in has to have a lifetime longer than the function returning it, which implies a static variable, and then you have to do the managing of it inside the function which will cause problems if your mysql_get_xrowdata function is called more than once in the same statement (ie multiple entries in a row getting put in the same printf) though that can be lived with since most of the other string functions in C muds have the same caveat.

Of course, if you're checking for the string error message, it's cheaper to check for NULL.


C doesn't have "runtime errors" because there is no runtime interpreter to handle them (which is why C programs are faster and smaller than interpreted languages). Segmentation fault is a signal passed to the executable by the operating system when it detects an out-of-segment memory access. There are other signals (about twenty or so iirc) and some of them are more informational than fatal, others are instructional, like SIGHUP which is used to tell daemons to reread their configuration.
Top

Posted by TheTraveller   (23 posts)  Bio
Date Reply #27 on Sat 19 Jan 2008 04:43 AM (UTC)
Message
Oh wait, so you mean I have the rows/columns backwards??

I was assuming it was like this:

mysql_get_xrowdata( xpfile, row_number )[column_number];


In this case, row_number is 1 and column_number is 2, which means it's supposed to grab the second column (player's name) from the first row (result). Are you saying it's the other way around? This would be confusing since the function declaration lists the int argument as "row" (which I changed to "rownum" to fix the previous bug). Would this then work if I simply switched the syntax to be like this:

mysql_get_xrowdata( xpfile, column_number )[row_number];


....?
Top

Posted by Isthiriel   (113 posts)  Bio
Date Reply #28 on Sat 19 Jan 2008 04:59 AM (UTC)

Amended on Sat 19 Jan 2008 05:01 AM (UTC) by Isthiriel

Message
*sigh*

Did you add the tracewrites like I suggested?

This is C and just like PHP (which I thought you said you had some skill at?) all arrays are indexed from 0.

Strictly the arr[n] operator is a short hand for *(arr + n * sizeof(type)), so the first element is located at (arr + 0 * sizeof(type)).

If you read the code in the mysql_get_xrowdata you should have seen that rownum == 0 returns xmysql->xrowdata_head which is the first row. The 'rownum' dictates how many times it tries to follow the ->next pointer.

So, to get the second field of the first row: mysql_get_xrowdata(xpfile, 0)[1]

What are you using as your C language reference?
Top

Posted by TheTraveller   (23 posts)  Bio
Date Reply #29 on Sat 19 Jan 2008 05:23 AM (UTC)
Message
Lol yes I'm well aware that arrays are indexed at 0 by default. But as a general practice, at least in PHP, the key (index) is setup to match its reference as closely as possible. In other words, [0] would be skipped, and I would've started it at [1]. In PHP this is very easy (in fact you can even set strings as the array key), but maybe it's different in C I dunno.

I learned C on my own many years ago, spent about 3 years screwing around with a SMAUG codebase, etc. But it was a long time ago and I have no formal training to fall back on, plus PHP has spoiled me lol. :P
Top

The dates and times for posts above are shown in Universal Co-ordinated Time (UTC).

To show them in your local time you can join the forum, and then set the 'time correction' field in your profile to the number of hours difference between your location and UTC time.


138,449 views.

This is page 2, subject is 4 pages long:  [Previous page]  1  2 3  4  [Next page]

It is now over 60 days since the last post. This thread is closed.     Refresh page

Go to topic:           Search the forum


[Go to top] top

Information and images on this site are licensed under the Creative Commons Attribution 3.0 Australia License unless stated otherwise.