I ? (true expression) : (false expression)[/I]

Its a shortcut for:

[I]if (condition) (true expression); else (false expression);[/I]

char Result = (x==2)?"correct":"incorrect";
is the same as...
if (x==2)
Result = "correct";
Result = "incorrect";
Its sometimes easier to read, and useful when you need to perform last minute conditional expressions in "tight spaces", such as within other more complex expressions. When the compiler encounters either of these methods, it converts it to the exact same assembly code.

Think of the [?:] shortcut in the same family as [++] and [+=] shortcuts. It just allows you to do more in a complex expression.

bug fix:
for(i = strlen(temp)-1; i>=0; i--) bin[j++] = temp[i];
You might also want to copy ints to the bin array, rather than char representations of ints, like this:
for(i = strlen(temp)-1; i>=0; i--) bin[j++] = (temp[i]=='1')?1:0;

Since I made this in a hurry, I programed it assuming I was going to use a format pointer, but I didn't need it. So your right, its useless.

As for the argv[x][y] thing, if your first parameter was "hex", then arv[0][1] would be 'e', the second letter of the first parameter. Therefore, its argv[param count][character]

By the way, I just caught a few errors with the code, specifically in the binary conversion sections. Simple mistakes. I will now repost the code with all the corrections including some additional comments to help you understand what I am actually doing. Thanks for your patience.

int num[2], // Where we will store both numbers
Result; // Where the result is stored
char Temp[256]; // Used in the binary conversions
int t, i; // Loop iterators

// Read and convert numbers.
// We are dealing with 2 parameters,
// so loop through them
for (t=0;t<2;t++)

// Grab the first letter of parameter 0,
// then parameter 3
switch (argv[t*3][0]) {

 // Convert Hex to Int
 case 'h': sscanf(argv[(t*3)+1], "%x", &num[t]); break;

 // Convert Octal to Int
 case 'o': sscanf(argv[(t*3)+1], "%o", &num[t]); break;

 // Read an Int
 case 'i': sscanf(argv[(t*3)+1], "%d", &num[t]); break;

 // Convert Binary to Int
 case 'b': {

     // Start the converted number at zero
     num[t] = 0;

     // Grab the binary string
     sscanf(argv[(t*3)+1], "%s", Temp); 

     // loop through the binary string in reverse order
     // since the least significant digit is on the
     // right side.
     for (i=strlen(Temp)-1;i>=0;i--) ...
mi.mac.rules commented: Thanks, you were a lot of help. +1

A few corrections:

Line 40 should be case 'i', not case 'd'.

Line 45 should be Result!=0, not Result==0.

I haven't tested this code, I just threw it together in a few minutes. It should do everything you need, and its extremely efficient.

The parameters would be like this:

./program <Number #1 hex/int/bin/oct> <Number #1> <div/add/mul/sub> <Number #2 hex/int/bin/oct> <Number #2> <Result hex/int/bin/oct>

Its not a fix to your program, but I figured this model could be a start to a better design for your app.

int num[2], Result;
char Temp[256];
char *format;

// Read and convert numbers
for (int t=0;t<2;t++)
switch (argv[t3][0]) {
// Convert Hex to Int
case 'h': sscanf(argv[(t
3)+1], "%x", &num[t]); break;
// Convert Octal to Int
case 'o': sscanf(argv[(t3)+1], "%o", &num[t]); break;
// Read an Int
case 'i': sscanf(argv[(t
3)+1], "%d", &num[t]); break;
// Convert Binary to Int
case 'b': {
num[t] = 0;
sscanf(argv[(t*3)+1], "%s", Temp);
for (i=strlen(Temp)-1;i>=0;i--)
if (Temp[i]=='1') {
num[t] |= 1;
num[t] <<= 1;
} break;

// Do math
switch (argv[2][0]) {
// divide
case 'd': Result = num[0] / num[1]; break;
// multiply
case 'm': Result = num[0] * num[1]; break;
// add
case 'a': Result = num[0] + num[1]; break;
// subtract
case 's': Result = num[0] - num[1]; break;

// Display Result
switch (argv[5][0]) {
case 'd': printf("\nResult in Integer: %d\n", Result); break;
case 'h': printf("\nResult in Hex: %x\n", Result); break;
case 'o': printf("\nResult in Octal: %o\n", Result); break;
case 'b':
printf("\nResult in Binary: ");
for (;Result==0;) {
if (Result & 1) printf("1");
else printf("0");
Result >>= 1;

Here is a way to do it. Convert the [B]TestInput[/B] to your [B]scanf[/B] implementation. Also not included in this example is a main function, the includes, and the [B]free[/B] functions which free the memory created by [B]realloc[/B] and [B]calloc[/B].

define MAX_STRING_SIZE 256

typedef struct { // This structure will store a single line
char *Line;
} DS;

char TestInput[] = "Hi How Are you?"; // Here is a sample string

DS *Data = NULL;

int i, // The index of the current character in the sample string
new = 1, // A flag which tells the parser to create a new line if "1"
lines = 0; // Number of lines created in "Data"

for (i=0; i<strlen(TestInput); i++)
switch (TestInput[i]) {
case ' ': // ignore spaces
case '\t': // ignore tabs
case '\n': // ignore new lines
new = 1; // remind the parser that the next string will be new
// if this is a new string, prepare a space for it in the array
if (new==1) {
// No longer new since we are creating it
new = 0;
// Expand the array's memory for the new line
Data = realloc(Data, sizeof(DS) * (++lines));
// Create some empty memory for the line string
Data[0].Line = calloc(MAX_STRING_SIZE);
// Append this "approved" character to the current line
strncat(Data[lines-1].Line, &TestInput[i], 1);
After the loop, Data will contain the follwing:

Data[0].Line contians "Hi"
Data[1].Line contians "How"
Data[2].Line contians "Are"
Data[3].Line contians "you?"

lines ...

[B]fscanf[/B] is a perfectly fine function to use for a configuration file with an absolute fixed format. I use it all the time. Wonderful function.

Here is an example which could be very relevant to you. This assumes linux. In windows, use the CR/LF combination.

This is the data structure.
typedef struct {
char IP[16];
int Port;
char FileName[255];
int Min, Max;
} DataStructure;
This is the code which performs the import. [B]fscanf[/B] used properly makes the import extremely painless.
DataStructure Data;
FILE *f = fopen("connect.conf","r");

if (fscanf(f, "%s\n%d\n%s\n%d\n%d", Data.IP, &Data.Port, Data.FileName, &Data.Max, &Data.Min)!=5) {
fprintf(stderr,"File not in correct format");
return -1;

[B]>> If the input file format is not fixed then this is a hard problem [/B]

Nothing is hard in C. If the file was not a fixed format, you just add a loop, int and switch.

[b]Person person = *p1;[/b]

This is copying the pointer address to the first 4 bytes of [b]firstName[/b] in the newly created instance of [b]Person[/b], and then completely undone by line 27:

[b]strcpy(person.firstName, "Modified1");[/b]

Which overwrites the 4 bytes written by the previous line of code with the given string constant.

If so, the compiler is ultimately treating line 26 as this:

[b]Person person;[/b]

So the pointer to [b]p1[/b] is not even involved here, which explains why it does not change the values pointed to by [b]p1[/b] as [b]jay1648[/b] explained.

Here is my explanation on the different ways to access a pointer:

void ModifyPerson(Person *p1)
// This technique, which you used in your code,
// is the pointer dereferencing method to access
// the contents of p1. Since the compiler knows
// p1 is a pointer, putting an asterisk in front
// of it tells the compiler that you want the
// value of the memory pointed to by the pointer.
// The parenthesis are a way to isolate the
// dereferenced pointer from the name of the
// element of that structure you want to access.
// The compiler knows the size and type of p1
// so it also knows what you are trying to say
// when you write "firstName" and "lastName"

strcpy((*p1).firstName, "Modified");
strcpy((*p1).lastName, "Modified"); 

    // This technique is accessing a pointer as 
    // an array. All variables in C are really 
    // instances of an array of one element. When 
    // you have any ...
jay1648 commented: Nice explanation ! +0

I will just add that if this is a new project, using an XML configuration file format or using the registry could be better solution than using INI files to store software settings.

If [b]malloc()[/b] is crashing instead of returning NULL then you have a memory overrun somewhere else in the code which is messing with the [b]malloc[/b] runtime table. You might need to retrace your steps and figure out where the memory overlaps are occurring. I don't see anything wrong with your code up to the crash point.

I beleive you do something like this in windows XP. (Since I am logged into Ubuntu right now I cant test this).. Right after you execute the command in a batch program, the ERRORLEVEL environment variable should be assigned the last returned code, so doing this should show you that return code.


Look at this link for some good information on the subject:


[b]1. Is it always necessary for a return value of main() to be an integer.[/b]

In C, the compiler may allow [b]main()[/b] to return a void, but its behaviour is undefined and therefore its highly not recommended. As a reference, the C++ standard explicitly prohibits returning void, and some compilers would ignore your void and convert it to an int returning zero.

[b]2. What happens if the return value of main() is not integer.[/b]

Well, if its a void, the consequences of such a program are technically unpredictable, but it is likely it would just return 0. If its a char or any other kind of non-int, assuming the compiler will even allow this, the compiler would probably attempt to cast it into an int, but this all entirely dependant on the compiler. All this speculation is avoided by using the standard int.

[b]3. When a return value other than 0 is returned - does it always indicate that an error has occurred ?

  1. If the answer to '3' is yes then what steps does the OS take ?[/b]

The meaning of the return value always depends on the context of the call. For instance, if you make a program to run from a batch script, you might want its return integer be a part of a switch of some kind with all non-zero actions that do different things to the script.

Normally, the Operating system will treat zero as good and non-zero as bad, but honestly it doesn't ...

// ...

define BUFFESIZE 80

// ...

int linemax = 5;
char pa = (char )malloc(sizeof(char) * linemax);

// Now pa has 5 bytes of memory

char buffer[BUFFESIZE];

// Now buffer has 80 bytes of memory

// ...

int n = 0;

// ...

if (n < linemax) {

// n is 0, so it goes in...


// Copies the string to buffer, which has 80 bytes in it

strcpy(pa+(n(BUFFESIZE sizeof(char))),buffer); // <---

// Here is what it looks like simplified:

strcpy(pa + (0 (80 1)), buffer);

// simplified further...

strcpy(pa, buffer);

// Remember how pa had 5 bytes of memory? How will buffer = 80 fit inside pa = 5?

In other words, [b]realloc()[/b] was not the problem, it was your logic.


if you cast malloc like this:
i = (int*) malloc(10);
You are creating an array of ints. Problem is, 10 doesn't go into 4 nicely, so your third element in the int array is going to give you a runtime error... if your lucky.

The propper use of what you just did there is this...
i = (int) malloc(3 sizeof(int));

You can cast malloc to anything.. If the space you allocated is BIGGER than your cast, you automatically created an array. If its smaller, then you either made a mistake or you just need to pointer and don't care about how its being stored... for instance:
char *Buf;

Buf = (char *)malloc(sizeof(some_struct));

// ...

[b]As long as you recognize that your argument boils down to "I like it this way because it makes more sense to me", it's all good[/b]

You are correct, its a preference. Weather I think its better is a matter of pure debate, and in a language like C, its a futile debate since C is all about being completely in control.

[b]The problem here is that there's no ambiguity[/b]

I see it more as "consistency". malloc() doesn't need it but other places do, so I like being consistent so I don't end up regretting it when a customer complains about some weird error, and im forced to hunt down the problem in the debug logs only to find that somewhere in the code I was copying a void pointer to an incompatible pointer. If I had casted it, my INTENDED type would have been in the code, and the compiler would have warned me about the attempt to copy one type into another incompatible type. It doesn't happen very often and most of the time I catch it but I highly value consistency.

[b]It's a compliment (you strike me as a skilled programmer). Would you rather I said your statement was the kind of stupid thing beginners believe and left it at that?[/b]

I figured that's how you felt but the way you said it was initially interpreted with a different level of respect. Written English suffers from this common issue.

[b]> I find not needing to type out a redundant cast and not needing to mention the target data type at all somewhat compelling[/b]
[b]> The only time it's necessary to cast malloc in standard C is when writing code that needs to be compilable as both C and C++[/b]

I strongly believe the more details you enter in your code, the less ambiguous your meaning is, especially when working with open source code where others will try to interpret your meaning to various things. Additionally, any unnecessary casts are ignored by the compiler. To me its all about "best practice" and it seems that omission without any added benefit is like encrypting variable names instead of make them meaningful. Please correct me if i'm wrong with my thought process here.

[b]One of my pet peeves is programmers who think compiler writers are incompetent. [/b]

By no means do I believe that the compiler is incompetent. I just don't think it can always correctly interpret my meaning if I chose the path of assumptions and ambiguity for the sake of saving a few extra characters of code.

[b]I'm kind of surprised, to be honest. You seem like you know what you're doing.[/b]

Not sure what your trying to prove and who your trying to prove it to with this statement. Either way, water under the bridge.

[B]> In C, you don't need to cast return value from malloc(), and moreover, you shouldn't do that. [/B]

I looked over that link attached to your warning that it shouldn't be done. Its just saying that it helps prevent problems when you dont include a file. Is that a strong enough reason not to cast your malloc results to your target? I always cast results so the compiler knows my destination size. It may not always be necessary but I think its good practice to cast as a way to help the compiler out. Sometimes the compiler can be stupid.

Just curious, is there a reason why you need to bounce around in the file? Is it such a large file that it can't be loaded to RAM? Why not use file mapping to map it to a series of struct's or arrays of struct's so you dont ever need to bounce around the file?