Automatic export of symbols array in C debugging (teaching purpose) - c

I need to teach C to children (10-15 years old, teaching is through a website) and I want to be able to show them a step by step execution of a program but I don't want them to use a debugger directly (too complex for them, they are total beginners).
My idea was to pre-compute all the needed data and to show it to them (with a cool javascript animation, with the current line in the code, the values of the variables and the standard output).
What I need is a way to run a debugger on a C code and to export the values of the variables at each possible step (no struct, just basic variables and arrays).
Is there any interface to gdb or some other debugger that can to that ?
For some context : we are training students for the IOI (International Olympiad in Informatics) though a website with courses, exercices (automatically corrected)...
The code (in C) can be edited , compiled, tested and submitted online (with a javascript editor). This way no need to install anything (at first) so more people can just "try it".
The basic "step by step" debugging was only to show the beginners how variables are modified, how a "for" or a "while" are working. The kind of stuff you can do on a whiteboard as a teacher. More advanced students will install some IDE and will/or not use the debugger.
So for the beginners we want them to be able to play, on the website, with some basic code (affectations, maths operations, function call,for,while,if) to "see things".

If you're limited to programs with specific input, or without input at all, you can maybe use gdb scripting, in something like this:
try.c (the input program):
#include <stdio.h>
int main()
{
int i;
for (i = 0; i < 10; i++)
{
printf("the number now is %d\n", i);
i++;
}
return 0;
}
trace.gdb (a basic gdb script):
break main
run
while 1
info locals
step
end
quit
the results of gdb -x trace.gdb -batch try
Breakpoint 1 at 0x40053c: file try.c, line 6.
Breakpoint 1, main () at try.c:6
6 for (i = 0; i < 10; i++)
i = 0
8 printf("the number now is %d\n", i);
i = 0
the number now is 0
9 i++;
i = 0
6 for (i = 0; i < 10; i++)
i = 1
8 printf("the number now is %d\n", i);
i = 2
the number now is 2
9 i++;
i = 2
6 for (i = 0; i < 10; i++)
i = 3
8 printf("the number now is %d\n", i);
i = 4
the number now is 4
9 i++;
i = 4
6 for (i = 0; i < 10; i++)
i = 5
8 printf("the number now is %d\n", i);
i = 6
the number now is 6
9 i++;
i = 6
6 for (i = 0; i < 10; i++)
i = 7
8 printf("the number now is %d\n", i);
i = 8
the number now is 8
9 i++;
i = 8
6 for (i = 0; i < 10; i++)
i = 9
11 return 0;
i = 10
12 }
i = 10
0x000000300161ebbd in __libc_start_main () from /lib/libc.so.6
No symbol table info available.
Single stepping until exit from function __libc_start_main,
which has no line number information.
Program exited normally.
trace.gdb:6: Error in sourced command file:
No frame selected.
There are ways to change gdb's output so you can perhaps tune the script to make the output parsable in a way that will allow you to make it something playable by javascript.
And you'll also need to make sure the program does not loop endlessly, probably by using convenience variables to limit number of while loops in the script.

Related

Standard C function is slower at the first call, how to solve this properly?

I want to make timing tests for learning how to benchmark using "time.h". But I noticed the first test is always longer.
0 1 2 3 4 5 6 7 8 9
time 0.000138
0 1 2 3 4 5 6 7 8 9
time 0.000008
0 1 2 3 4 5 6 7 8 9
time 0.000007
If I want to do several tests in the same main() function the results will be unreliable.
Here is the stupid code who prints the output above.
#include <stdio.h>
#include <time.h>
const int COUNT = 10;
void test() {
clock_t start = clock();
for(int i = 0; i < COUNT; i++) {
printf("%d ", i);
}
printf("\ntime %lf\n", (double)(clock() - start) / (double)CLOCKS_PER_SEC );
}
int main() {
test();
test();
test();
return 0;
}
I solved this by ignoring the first "test" function. Also, writing a first "printf" who prints some integer before the tests works too. But I guess it's not a proper solution.
CPU has cache. When code and data are not in cache, the code takes longer to run.
It's standard practice to discard the result of first run (or first few runs) when measuring performance. It's sometimes called "cache warmup".

How to step through a C program in Anjuta?

I need to step through this program, but the icons related to debugging are greyed out, even if I set the configuration to 'debug'. Any idea how this is supposed to work?
#include <stdio.h>
int main( void )
{
int number = 7;
printf ( "%d", number % 2 );
number = number / 2;
printf ( "%d", number % 2 );
number = number / 2;
printf ( "%d", number % 2 );
number = number / 2;
printf ( "\n" );
return 0;
}
OS: Fedora 20
Debugger gdb
I created a general C project (minimal)
Found out how to do it:
At least there needs to be a Makefile which can be used by gdb. The one created by Anjuta when creating a new C Makefile project can be used as basis.
Also, gdb needs to be enabled in the settings window.
1.Click "Add breakpoint" in the toolbar
2.Execute > Debug program
Then the buttons become sensitive and you can step trough the code

Visual Studios 2010: 'File location'.exe is not recognized as internal or external command... (C program)

My Thermo professor assigned our class a computational project in which we have to calculate some thermodynamic functions. He provided us with some code to work off of which is a program that essentially finds the area under a curve between two points for the function x^2. The code is said to be correct and it looks correct to me. However, I've been having FREQUENT problems with all of my programs giving me the error "'File location'.exe is not recognized as internal or external command, operable programs or batch files." upon initial running of a project or [mostly] reopening projects.
I've been researching the problem for many hours. I tried adjusting the environmental variables like so many other sites suggested, but I'm either not doing it right or it's not working. All I keep reading about is people explaining the purpose of an .exe file and that I have to locate that file and open that. The problem is that I cannot find ANY .exe file. There is the project I created with the source.c file I created and wrote the program in. Everything else has lengthy extensions that I've never seen before.
I'm growing increasingly impatient with Visual Studios' inconsistent behavior lately. I've just made the switch from MATLAB, which although is an inferior programming language, is far more user friendly and easier to program with. For those of you interested in the code I'm running, it is below:
#include <stdio.h>
#include <iostream>
#include <math.h>
using namespace std;
double integration();
double integration()
{
int num_of_intervals = 4, i;
double final_sum = 0, lower_limit = 2, upper_limit = 3, var, y = 1, x;
x = (upper_limit - lower_limit) / num_of_intervals; // Calculating delta x value
if(num_of_intervals % 2 != 0) //Simpson's rule can be performed only on even number of intervals
{
printf("Cannot perform integration. Number of intervals should be even");
return 0;
}
for(i = 0 ; i < num_of_intervals ; i++)
{
if(i != 0) //Coefficients for even and odd places. Even places, it is 2 and for odd it is 4.
{
if(i % 2 == 0)
y = 2;
else
y = 4;
}
var = lower_limit + (i * x);// Calculating the function variable value
final_sum = final_sum + (pow(var, 2) * y); //Calculating the sum
}
final_sum = (final_sum + pow(upper_limit , 2)) * x / 3; //Final sum
return final_sum;
}
int main()
{
printf("The integral value of x2 between limits 2 and 3 is %lf \n" , integration());
system("PAUSE");
return 0;
}
Thanks in advance,
Dom

Dump debug steps in C, Linux

Is it possible to dump the entire program steps to a file? I don't mean the value of the variables, I mean the jumping from on instruction to another, and if it's possible to use both, steps and the var values
I've used both gdb and GUI(ddd), and I use the regular step all the time but sometimes I have a loop and network application so I don't want to affect the flaw of the program, I just want to see what happened exactly after everything is done.
For instance,
1 #include<stdio.h>
2
3 int main()
4 {
5
6 int i = 0, y = 0;
7
8 for (y; y< 10; y++) {
9 i++;
10 printf("%d\n", i)
11 }
12 return 0;
13
14 }
So the dump file will contain all the steps from int main() to return 0, like below for example
1. on 1
2. on 2
...
...
8. on 8
9. on 9
10. on 10
11. on 8
12. on 9
... and so on until the loop finishes and then hit return and exit.
Using GDB you could use process record and replay. Another option is Jockey which functions as a record/replay preload library.

C Primer 5th - Task 14-6

A text file holds information about a softball team. Each line has data arranged as follows:
4 Jessie Joybat 5 2 1 1
The first item is the player's number, conveniently in the range 0–18. The second item is the player's first name, and the third is the player's last name. Each name is a single word. The next item is the player's official times at bat, followed by the number of hits, walks, and runs batted in (RBIs). The file may contain data for more than one game, so the same player may have more than one line of data, and there may be data for other players between those lines. Write a program that stores the data into an array of structures. The structure should have members to represent the first and last names, the at bats, hits, walks, and RBIs (runs batted in), and the batting average (to be calculated later). You can use the player number as an array index. The program should read to end-of-file, and it should keep cumulative totals for each player.
The world of baseball statistics is an involved one. For example, a walk or reaching base on an error doesn't count as an at-bat but could possibly produce an RBI. But all this program has to do is read and process the data file, as described next, without worrying about how realistic the data is.
The simplest way for the program to proceed is to initialize the structure contents to zeros, read the file data into temporary variables, and then add them to the contents of the corresponding structure. After the program has finished reading the file, it should then calculate the batting average for each player and store it in the corresponding structure member. The batting average is calculated by dividing the cumulative number of hits for a player by the cumulative number of at-bats; it should be a floating-point calculation. The program should then display the cumulative data for each player along with a line showing the combined statistics for the entire team.
team.txt (text file I'm working with):
4 Jessie Joybat 5 2 1 1
4 Jessie Joybat 7 3 5 3
7 Jack Donner 6 3 1 2
11 Martin Garder 4 3 2 1
15 Jaime Curtis 7 4 1 2
2 Curtis Michel 3 2 2 3
9 Gillan Morthim 9 6 6 7
12 Brett Tyler 8 7 4 3
8 Hans Gunner 7 7 2 3
14 Jessie James 11 2 3 4
12 Brett Tyler 4 3 1 3
Since I'm a beginner in C, either I misinterpreted the task from what was asked originally or it's unfairly complex (I believe the former is the case). I'm so lost that I can't think of the way how could I fill in by the criteria of index (player number) every piece of data, keep track of whether he has more than one game, calculate and fetch bat average and then print.
What I have so far is:
#define LGT 30
struct profile {
int pl_num;
char name[LGT];
char lname[LGT];
int atbat[LGT/3];
int hits[LGT/3];
int walks[LGT/3];
int runs[LGT/3];
float batavg;
};
//It's wrong obviously but it's a starting point
int main(void)
{
FILE *flx;
int i,jc,flow=0;
struct profile stat[LGT]={{0}};
if((flx=fopen("team.txt","r"))==NULL) {
fprintf(stderr,"Can't read file team!\n");
exit(1);
}
for( jc = 0; jc < 11; jc++) {
fscanf(flx,"%d",&i);
stat[i].pl_num=i;
fscanf(flx,"%s",&stat[i].name);
fscanf(flx,"%s",&stat[i].lname);
fscanf(flx,"%d",&stat[i].atbat[flow]);
fscanf(flx,"%d",&stat[i].hits[flow]);
fscanf(flx,"%d",&stat[i].walks[flow]);
fscanf(flx,"%d",&stat[i].runs[flow]);
flow++;
}
}
Advice 1: don't declare arrays like atbat[LGT/3].
Advice 2: Instead of multiple fscanf you could read the whole line in a shot.
Advice 3: Since the number of players is limited and the player number has a good range (0-18), using that player number as an index into the struct array is a good idea.
Advice 4: Since you need cumulative data for each player (no need to store his history points), then you don't need arrays of integers, just an integer to represent the total.
So:
#include <stdio.h>
#define PLAYERS_NO 19
typedef struct
{
char name[20+1];
char lastName[25+1];
int atbat;
int hits;
int walks;
int runs;
float batavg;
} Profile;
int main(int argc, char** argv)
{
Profile stats[PLAYERS_NO];
int i;
FILE* dataFile;
int playerNo;
Profile tmpProfile;
int games = 0;
for(i=0; i<PLAYERS_NO; ++i)
{
stats[i].name[0] = '\0';
stats[i].lastName[0] = '\0';
stats[i].atbat = 0;
stats[i].hits = 0;
stats[i].walks = 0;
stats[i].runs = 0;
}
dataFile = fopen("team.txt", "r");
if ( dataFile == NULL )
{
fprintf(stderr, "Can't read file team!\n");
exit(1);
}
for(i=0; i<PLAYERS_NO && !feof(dataFile); ++i, ++games)
{
fscanf(dataFile, "%d", &playerNo);
if ( playerNo <0 || playerNo > PLAYERS_NO )
{
fprintf(stderr, "Player number out of range\n");
continue;
}
fscanf(dataFile, "%s %s %d %d %d %d",
&tmpProfile.name,
&tmpProfile.lastName,
&tmpProfile.atbat,
&tmpProfile.hits,
&tmpProfile.walks,
&tmpProfile.runs);
printf("READ: %d %s %s %d %d %d %d\n",
playerNo,
tmpProfile.name,
tmpProfile.lastName,
tmpProfile.atbat,
tmpProfile.hits,
tmpProfile.walks,
tmpProfile.runs);
strcpy(stats[playerNo].name, tmpProfile.name);
strcpy(stats[playerNo].lastName, tmpProfile.lastName);
stats[playerNo].atbat += tmpProfile.atbat;
stats[playerNo].hits += tmpProfile.hits;
stats[playerNo].walks += tmpProfile.walks;
stats[playerNo].runs += tmpProfile.runs;
}
/* exercise: compute the average */
fclose(dataFile);
for(i=0; i<PLAYERS_NO; ++i)
{
if ( stats[i].name[0] == '\0' )
continue;
printf("%d %s %s %d %d %d %d\n",
i,
stats[i].name,
stats[i].lastName,
stats[i].atbat,
stats[i].hits,
stats[i].walks,
stats[i].runs);
}
return 0;
}
The first rule of programming: Divide and conquer.
So you need to identify individual operations. One such operation is "load one row of input", another is "look up a player". If you have some of those operations (more will come up as you go), you can start building your program:
while( more_input ) {
row = load_one_row()
player = find_player( row.name )
if( !player ) {
player = create_player( row.name )
add_player( player )
}
... do something with row and player ...
}
when you have that, you can start to write all the functions.
An important point here is to write test cases. Start with a simple input and test the code to read a row. Do you get the correct results?
If so, test the code to find/create players.
The test cases make sure that you can forget about code that already works.
Use a framework like Check for this.
If I were doing this, I'd start with a structure that only held one "set" of data, then create an array of those structs:
struct profile {
char name[NAMELEN];
char lname[NAMELEN];
int atbat;
int hits;
int walks;
int runs;
float batavg;
};
Since you're using the player's number as the index into an array, you don't need to store it into the structure too.
I think that will simplify the problem a little bit. You don't need to store multiple data items for a single player -- when you get a duplicate, you just ignore some of the new data (like the names, which should be identical) and sum up the others (e.g., at-bats, hits).

Resources