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
| Isthiriel
(113 posts) Bio
|
| Date
| Reply #30 on Sat 19 Jan 2008 05:48 AM (UTC) |
| Message
| While PHP lumps them all together under 'array' there is a lot of difference between an array that is a sequence of values and an associative array (aka map) that holds key => value pairs.
You can implement associative arrays in C (PHP's associative arrays are implemented in C) but it's a lot of work. C arrays are a block of memory that you address as if it holds a series of objects. They do not have 'keys' as they are not maps.
I've also written PHP (more than C and much more recently, the last time I wrote a serious C program would be > 10 years ago). I don't reindex arrays so they start from 1 unless there is a very good reason. mysql_fetch_row() in PHP indexes from 0.
Why you would suddenly assume that we're indexing from 1 (when the code that builds the array indexes from 0), I do not know :P
And decent tracewrites would have made it obvious what was going on... | | Top |
|
| Posted by
| TheTraveller
(23 posts) Bio
|
| Date
| Reply #31 on Sat 19 Jan 2008 06:02 AM (UTC) |
| Message
| In PHP I typically index the MySQL results as $results_arr[$resultnum][$fieldname], where $resultnum starts at 1. I then use 0 to store the number of results, so it ultimately comes out like this:
$fieldname = mysql_field_name( $resultvar, $col );
$results_arr[$col_value[0]][$fieldname] = $col_value;
$results_arr[0]++;
| | Top |
|
| Posted by
| David Haley
USA (3,881 posts) Bio
|
| Date
| Reply #32 on Sat 19 Jan 2008 06:17 AM (UTC) |
| Message
| If n is the number of results, you can't just allocate an array of size n and then, starting from index 1, write n results. That is an error as you will be writing one index beyond the maximum. If n is the size of 'array', array[n] is one past the last legal byte.
Best-case scenario, this will immediately crash so you know something is wrong. Worst-case scenario, you will overwrite something else in your memory and have very subtle and hard-to-debug problems crop up over time.
When working with C you may as well throw out most conceptions of how arrays and stuff work in PHP. You can't just grow arrays by adding new indices. In fact, the notion of "array" is a funny one to begin with as it really means "block of memory". It's not a semantic structure that grows, contracts, etc. As Ithiriel said, C arrays are literally just blocks of memory. That point absolutely must be understood before this kind of programming becomes tractable.
You also cannot mix types without a fair bit of extra work. You can't have an array of results and then start sticking in numbers. This makes sense if you think about it from the 'block of memory' point of view.
I also would like to stress Isthiriel's suggestion of using debugging tools to debug this stuff. It will save you a lot of time in the long run. |
David Haley aka Ksilyan
Head Programmer,
Legends of the Darkstone
http://david.the-haleys.org | | Top |
|
| Posted by
| Isthiriel
(113 posts) Bio
|
| Date
| Reply #33 on Sat 19 Jan 2008 06:45 AM (UTC) Amended on Sat 19 Jan 2008 06:46 AM (UTC) by Isthiriel
|
| Message
|
Quote: In PHP I typically index the MySQL results as $results_arr[$resultnum][$fieldname], where $resultnum starts at 1.
I am yet to see a problem where copying the entire resultset from the MySQL memory space to the PHP memory space before processing is a Good Idea. It's slower, wasteful of memory and has less scalability than the by-row method.
I'm not sure I'm reading that code correctly, you've got a 3D array? Or is $col_value[0] supposed to be $results_arr[0]? And if that's the case, why not use $results_arr[]?
At which point, isn't something like:
$results_arr = array();
while (false !== ($row = mysql_fetch_assoc($r)))
$results_arr[] = $row;
array_unshift($results_arr, mysql_num_rows($r));
Equivalent to what you have written?
I'm yet to use mysql_field_name myself. | | Top |
|
| Posted by
| TheTraveller
(23 posts) Bio
|
| Date
| Reply #34 on Sat 19 Jan 2008 10:29 AM (UTC) Amended on Sat 19 Jan 2008 10:37 AM (UTC) by TheTraveller
|
| Message
| Actually $col_value isn't an array at all. The code I displayed wasn't complete. I've found that everyone has their own preferred methods with things like MySQL query gathering, so here's an example of the way I like to do it:
$query = "select * from table where col1='val1' AND col2='val2'"; //The MySQL query.
$resultTL1 = mysql_query( $query ) or die( "Query '$query' failed for resultTL1 in script_file.php : " . mysql_error() ); //I started using unique result variables and error messages like this when I worked for this web engineering company a couple years back and we dealt with some MASSIVE web-based applications.... MySQL errors don't typically give a line number, so this allows me to *quickly* (time = money) determine exactly where in the code the error is occuring if one happens.... The naming scheme I typically use is $result + upper( first two letters of function name, or "TL" for top-level ) + how many results are already being returned previously coded into the function plus one. It may require some extra typing initially but it's a HUGE time-saver when debugging database issues! Of course, when security may be an issue with regard to the error message being too detailed, I'll censor it accordingly.
$results_arr = array( 0 ); //Just a basic initialization, good practice. Also sets 0 key value to 0.
/* Fetches data into an array, then parses into an array whose dimensions/properties are set according to what's best and most maleable for whatever it's being used for. */
while ( $line = mysql_fetch_array( $resultTL1, MYSQL_ASSOC ) )
{
$results_arr[0]++;
$colnum = 0;
foreach ( $line as $col_value )
{
$fieldname = mysql_field_name( $resultTL1, $colnum );
$results_arr[$results_arr[0]][$fieldname] = $col_value;
$colnum++;
}
}
| | Top |
|
| Posted by
| David Haley
USA (3,881 posts) Bio
|
| Date
| Reply #35 on Sat 19 Jan 2008 11:28 AM (UTC) |
| Message
| I would tend to agree with Isthiriel that it is very rarely a good idea to read an entire DB query result-list into memory instead of processing one result at a time, but then again I don't know what your application is so perhaps you do have a case where it's relevant. I don't really view it as a matter of personal preference, though, unless efficiency is not a concern (for instance, the database (or result list) is quite small).
Still, if you want to do this in C, you have two main options: (1) figure out how many results there are, allocate an appropriately sized buffer, and store them in that buffer (indexing from zero). (2) create a small buffer initially and grow it dynamically. Option (2) requires more knowledge of dealing with C memory management; option (1) requires that you know how to get that information from MySQL. |
David Haley aka Ksilyan
Head Programmer,
Legends of the Darkstone
http://david.the-haleys.org | | Top |
|
| Posted by
| Isthiriel
(113 posts) Bio
|
| Date
| Reply #36 on Sat 19 Jan 2008 10:42 PM (UTC) |
| Message
|
Quote: I started using unique result variables and error messages like this when I worked for this web engineering company a couple years back and we dealt with some MASSIVE web-based applications.... MySQL errors don't typically give a line number, so this allows me to *quickly* (time = money) determine exactly where in the code the error is occuring if one happens...
...
You have heard of __FILE__, __LINE__, __FUNCTION__, trigger_error() and debug_backtrace()?
die() terminates relatively silently :( And trigger_error()'s reporting can be turned on and off globally with a single line (error_reporting()).
I always wrap the mysql_* functions. Partly for the improved error reporting (and code reuse advantages of having it localized to one source file), partly because I have a basic db profiler built into those same functions, and partly because the increased abstraction allows for the hypothetical changing of DBMs at some point in the future.
It also means I can change the input types and hide some of the processing, like for a query that I only want one row from I can feed the query string directly to $db->fetch_row() and it does the actual query() call and the free_result() call afterward.
And your 11 lines of code are functionally identical to my 4... only slower because you're doing iteration in PHP that would best be done in C.
Anyway, we're a fair way off topic, how is your C code going? | | Top |
|
| Posted by
| TheTraveller
(23 posts) Bio
|
| Date
| Reply #37 on Sun 20 Jan 2008 01:44 AM (UTC) Amended on Sun 20 Jan 2008 01:47 AM (UTC) by TheTraveller
|
| Message
| Lol just FYI, in most cases the result set from each query will be fairly small, i.e. the MUD will almost never need to do a "select *" or retrieve all the rows. But this way I can if I need to without a bunch of modifications. Also, holding on to all the data in memory typically is much faster than doing a series of multiple queries to the MySQL server, particularly if it's located on a different server host. 11 lines of PHP code vs 4 lines really doesn't make any difference in script execution speed, unless you're counting a fraction of a millisecond. So really the only practical difference in our methods is style. My style is much easier for me to read and edit later on, and can be easily modified to suit any type of query.
But yeah anyway, back on topic, the C code is working now that I subtracted 1 from the row/column number. I already included variables in the results structure to track the number of rows and columns, so I should just be able to use that to avoid any future seg faults caused by parsing non-existant results. Now I can finally move on to converting all pfile save data to the database.
And did one of you say it would be easy for me to compile the MUD in C++? I know I'd have to rename the files to .cpp, and possibly make some change to the Makefile, but is that all? Or are there potentially C directives in the code that would be incompatible with C++? I would definitely like to convert it if it's not too much trouble, as I could definitely use the improved flexibility.
--TT
| | Top |
|
| Posted by
| TheTraveller
(23 posts) Bio
|
| Date
| Reply #38 on Sun 20 Jan 2008 02:12 AM (UTC) |
| Message
| I am getting one really ANNOYING warning error on every single file during compile:
/usr/include/mysql/mysql.h:111: warning: ISO C89 does not support `long long'
I tried Googling but couldn't find any help there. I thought it might be a typo and tried getting rid of the second "long", but that just messed it up really bad, so I changed it back. It doesn't seem to be causing any problems, it's just really spammy whenever I compile. Is there any way for me to make this particular warning message shut the hell up? =)
| | Top |
|
| Posted by
| David Haley
USA (3,881 posts) Bio
|
| Date
| Reply #39 on Sun 20 Jan 2008 02:17 AM (UTC) |
| Message
| man gcc
search for 'long long'
You'll find a reference to the flag -Wno-long-long.
As for having it compile in C++, it is usually a fairly easy task. You have to do things like rename variables called 'class' because it's a reserved keyword in C++. Usually the process is straightforward and involves just stepping through the errors one at a time. I'd recommend backing up your C code before starting, though... :-) |
David Haley aka Ksilyan
Head Programmer,
Legends of the Darkstone
http://david.the-haleys.org | | Top |
|
| Posted by
| TheTraveller
(23 posts) Bio
|
| Date
| Reply #40 on Sun 20 Jan 2008 04:10 AM (UTC) |
| Message
| Lol thanks, already got a few backups hehe. Is there any kind of manual out there for this, or is it pretty much just checking for any variables named "class"?
Also, is there any function in C that's equivalent to the PHP function is_numeric()? I know there's isalpha, but I can't seem to figure out what an equivalent for numeric would be.
| | Top |
|
| Posted by
| David Haley
USA (3,881 posts) Bio
|
| Date
| Reply #41 on Sun 20 Jan 2008 06:09 AM (UTC) |
| Message
| The only manuals that I know of are things like language specs which are probably not at all what you want to see. :) But frankly, most of it is just compiling, looking at the errors, and changing reserved keywords.
As for is_numeric, if you do 'man isalpha' you will see a long list of functions, among which is isdigit. |
David Haley aka Ksilyan
Head Programmer,
Legends of the Darkstone
http://david.the-haleys.org | | Top |
|
| Posted by
| TheTraveller
(23 posts) Bio
|
| Date
| Reply #42 on Sun 20 Jan 2008 06:27 AM (UTC) |
| Message
| Ahh ok, thanks! Off the top of your head, any idea what (if anything) I'd need to do to the Makefile to get it to compile in C++? I know I'd be changing .c to .cpp and gcc to g++, but is there anything else that you know of?
| | Top |
|
| Posted by
| TheTraveller
(23 posts) Bio
|
| Date
| Reply #43 on Sun 20 Jan 2008 07:10 AM (UTC) Amended on Sun 20 Jan 2008 07:11 AM (UTC) by TheTraveller
|
| Message
| Lol ok, I made a valiant attempt to convert this thing to C++, but so far not so good. Here's the output I got:
[root@localhost src]# ls
action_safe.cpp event-handler.cpp io.cpp Makefile mud.h_old.h save.cpp stack.h xmysql.h
event.cpp help.cpp list.cpp mccp.cpp mysql.c_old.c socket.cpp strings.cpp
event.h interpret.cpp list.h mud.h mysql.cpp stack.cpp utils.cpp
[root@localhost src]# make
g++ -c -Wall -g -pedantic -ansi socket.cpp
In file included from mud.h:12,
from socket.cpp:22:
/usr/include/mysql/mysql.h:111: warning: ISO C++ does not support `long long'
In file included from socket.cpp:22:
mud.h:69: warning: redeclaration of C++ built-in type `bool'
In file included from socket.cpp:22:
mud.h:252: declaration of `char* crypt(const char*, const char*)' throws
different exceptions
/usr/include/unistd.h:964: than previous declaration `char* crypt(const char*,
const char*) throw ()'
mud.h:292: declaration of `char* strdup(const char*)' throws different
exceptions
/usr/include/string.h:126: than previous declaration `char* strdup(const char*)
throw ()'
mud.h:293: declaration of `int strcasecmp(const char*, const char*)' throws
different exceptions
/usr/include/string.h:288: than previous declaration `int strcasecmp(const
char*, const char*) throw ()'
socket.cpp: In function `bool new_socket(int)':
socket.cpp:318: warning: invalid conversion from `void*' to `D_SOCKET*'
socket.cpp:356: warning: invalid conversion from `void*' to `LOOKUP_DATA*'
socket.cpp: In function `bool read_from_socket(D_SOCKET*)':
socket.cpp:509: warning: comparison between signed and unsigned integer
expressions
socket.cpp: In function `void handle_new_connections(D_SOCKET*, char*)':
socket.cpp:1008: warning: invalid conversion from `void*' to `D_MOBILE*'
make: *** [socket.o] Error 1
I didn't change anything in the code except rename them from *.c to *.cpp. I also modified the Makefile slightly, as follows:
CC = g++
C_FLAGS = -Wall -g -pedantic -ansi
L_FLAGS = -lz -lpthread -lcrypt
O_FILES = socket.o io.o strings.o utils.o interpret.o help.o \
action_safe.o mccp.o save.o event.o event-handler.o \
list.o stack.o
all: $(O_FILES)
rm -f socketmud
$(CC) -o socketmud $(O_FILES) $(L_FLAGS)
$(O_FILES): %.o: %.cpp
$(CC) -c $(C_FLAGS) $<
clean:
@echo Cleaning code $< ...
@rm -f *.o
@rm -f socketmud
@rm -f *.*~
Lol any ideas? I have backups so no worries, but it would be really awesome if I could make this work in C++!....
| | Top |
|
| Posted by
| David Haley
USA (3,881 posts) Bio
|
| Date
| Reply #44 on Sun 20 Jan 2008 10:47 AM (UTC) |
| Message
|
Quote: mud.h:69: warning: redeclaration of C++ built-in type `bool'
Just remove the redeclaration.
Quote: /usr/include/mysql/mysql.h:111: warning: ISO C++ does not support `long long'
Use the flag I mentioned.
Quote: In file included from socket.cpp:22:
mud.h:252: declaration of `char* crypt(const char*, const char*)' throws
different exceptions
/usr/include/unistd.h:964: than previous declaration `char* crypt(const char*,
const char*) throw ()'
mud.h:292: declaration of `char* strdup(const char*)' throws different
exceptions
/usr/include/string.h:126: than previous declaration `char* strdup(const char*)
throw ()'
mud.h:293: declaration of `int strcasecmp(const char*, const char*)' throws
different exceptions
/usr/include/string.h:288: than previous declaration `int strcasecmp(const
char*, const char*) throw ()'
Remove the redeclarations; you don't need to repeat them if they're already in the standard headers. |
David Haley aka Ksilyan
Head Programmer,
Legends of the Darkstone
http://david.the-haleys.org | | 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.
172,345 views.
This is page 3, subject is 4 pages long:
1
2
3 4
It is now over 60 days since the last post. This thread is closed.
Refresh page
top