Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

GoKyu

macrumors 65816
Original poster
Feb 15, 2007
1,169
24
New Orleans
Hi all,

I've been getting back into the basics of C, and I'm remembering a lot more than I thought I would (the last time I had a class in C was around 10 years ago.)

All of the simple programs I'm writing at the moment are just that - simple, and only require a main() function that looks like this:

Code:
main() 
{
   // code goes here
}

I know that you can pass arguments inside the parentheses, but I don't understand much about it yet.

I'm currently writing code in an editor in Terminal and using gcc to compile. When I go through Xcode, it sets up this code for me:

Code:
int main (int argc, const char * argv[])
{
  // Code goes here
}

I know that the 'int' in front of main is generally optional, because main assumes int as its type.

But my question is...what the heck is all that other stuff in there, and why does Xcode just assume that I need it?

Thanks,

-Bryan
 

autorelease

macrumors regular
Oct 13, 2008
144
0
Achewood, CA
The 'other stuff' you're talking about is what allows main() to receive arguments from the command line.

You don't have to understand it exactly now, since you're just starting out, and it's perfectly acceptable to use "int main()." Feel free to delete it for now.

In case you're curious:

When you run a program from your terminal, all the arguments you specify get put into a a list. So if you execute a command like this
Code:
$ myProgram -input file1.txt -output file2.txt

then 'myProgram' receives a list containing the strings "myProgram," "-input," "file1.txt," "-output," and "file2.txt." The program is then free to use the arguments from the list as it pleases.

The main() function receives two arguments. The first is called "argc" and it is an integer. argc means "argument count": it's the number of argument strings that were passed to the program, including the program's name. So in the example above, argc would be 5.

The second argument, "argv," is the actual text data of the arguments. It is an array of strings (pointers to characters.) It would take too long to explain how pointers and strings work here, but I'm sure you'll learn about them soon. :)
 

notjustjay

macrumors 603
Sep 19, 2003
6,056
167
Canada, eh?
Code:
$ myProgram -input file1.txt -output file2.txt

For the sake of completion, here's what you'd get for the above example:

argc = 5

argv[0] = pointer to char array "myProgram"
argv[1] = pointer to char array "-input"
argv[2] = pointer to char array "file1.txt"
argv[3] = pointer to char array "-output"
argv[4] = pointer to char array "-file2.txt"
 

Cromulent

macrumors 604
Oct 2, 2006
6,817
1,102
The Land of Hope and Glory
I know that the 'int' in front of main is generally optional, because main assumes int as its type.

This is incorrect now. C99 (the latest C standard) now requires all functions to explicitly declare their return type. Implicit declarations should be treated as errors by compilers (but often aren't). As a beginner it is probably best just to get in the habit of always using int main(void) if you don't need any of the other stuff.

But my question is...what the heck is all that other stuff in there, and why does Xcode just assume that I need it?

Thanks,

-Bryan

int argc is the number of command line arguments supplied to your program (the program name counts as one so the total command line arguments is always argc -1).

char *argv[] stores the actual arguments themselves as pointed out much clearer than I could write it above :).

Hope that helps.
 

GoKyu

macrumors 65816
Original poster
Feb 15, 2007
1,169
24
New Orleans
Thanks for all the great info - I have read up to character arrays, and am starting to know a little about them, like:

Code:
char month[10];  // Reserve enough space for the longest month name, plus the null zero (\0).

If I've read correctly, C doesn't have string variables, so you need to use a character array to perform the same function.

char *argv[] stores the actual arguments themselves as pointed out much clearer than I could write it above :).

Hope that helps.

That does help a lot, thanks :) I think the '*' marks that particular variable 'argv' as a pointer, doesn't it?

I've read over pointers, but it's very abstract to me right now. They talk about pointers being links to an already existing variable somewhere in memory.

C programmers don't know exactly what memory location their programs will be running in, do they? I mean, what's the point (sorry, no pun intended...) of having a pointer to a variable..why not just use the value of that variable?

Code:
int age;
int *pAge;
age = 21;
pAge = &age;

If you already know that age = 21, what purpose would it serve to have a link to it as pAge?

Sorry if this went from beginner to seriously intermediate :) I probably won't be using pointers for awhile, but even as easy as this beginner's C book is, pointers seem to be quite tricky.

Thanks again for all the replies, I appreciate it :)

-Bryan
 

Cromulent

macrumors 604
Oct 2, 2006
6,817
1,102
The Land of Hope and Glory
C programmers don't know exactly what memory location their programs will be running in, do they? I mean, what's the point (sorry, no pun intended...) of having a pointer to a variable..why not just use the value of that variable?

Because you can do some very clever things with pointers.

For instance using your example above:

Code:
char month[10];
this array can hold only one month in it at a time but if we declare it like this:

Code:
char *month[12];
we can now dynamically allocate as much memory as we require for each pointer in that array (month is now an array of pointers) and therefore store all twelve months.

There are many other things you can do such as dynamic multidimensional arrays.
 

lee1210

macrumors 68040
Jan 10, 2005
3,182
3
Dallas, TX
It is pretty rare to have a pointer to a single primitive variable. Normally they are used to point to larger things, such as arrays (an array is really just a pointer to the base element), or a very large structure. In the case of a large structure, and you need to pass the structure around, it is more efficient to pass a 4 or 8 byte pointer than the whole structure by value. Also, if you have a great giant structure you may not want to keep it on the stack (don't worry for now), but on the heap (again, don't worry) instead, which requires that you allocate some memory for it. When you allocate that memory, you have to assign the address to something and that something has to be a pointer.

You said you're not quite there yet, so a lot of this might not make sense yet, but pointers are absolutely essential once you get a bit further along.

-Lee
 

SydneyDev

macrumors 6502
Sep 15, 2008
346
0
If you already know that age = 21, what purpose would it serve to have a link to it as pAge?

Pointers are very useful in function calling. Functions can return only 1 value usually, but by passing pointers as arguments (instead of values) the function is able to return a lot more. The arguments in effect become read/write.
 

GoKyu

macrumors 65816
Original poster
Feb 15, 2007
1,169
24
New Orleans
Code:
char month[10];
this array can hold only one month in it at a time but if we declare it like this:

Code:
char *month[12];
we can now dynamically allocate as much memory as we require for each pointer in that array (month is now an array of pointers) and therefore store all twelve months.

I just had a quick followup question here...

When you say "...but if we declare it like this...."

Do you mean that:

Code:
char *month[12];

should be its own variable (*instead* of the original char month[10]; ), or that it's now added onto that one, making it more flexible?

As I understand it (not very well, admittedly), you can't have a pointer variable unless you already have another variable for it to actually point to.

Thanks :)

-Bryan
 

Cromulent

macrumors 604
Oct 2, 2006
6,817
1,102
The Land of Hope and Glory
As I understand it (not very well, admittedly), you can't have a pointer variable unless you already have another variable for it to actually point to.

Thanks :)

-Bryan

You can have a pointer that is later set to point to something tangible using functions like malloc.

So for instance:

Code:
char *p;
p = (char *) malloc (128);
Makes the pointer p point to a 128 bytes of memory. When you are finished with that memory you must call free like so otherwise you get a memory leak:
Code:
free(p);
you can also dynamically resize the amount of memory that p points too using the realloc function.

I hope I am not confusing you further. Pointers are widely regarded as the most confusing aspect of C.
 

autorelease

macrumors regular
Oct 13, 2008
144
0
Achewood, CA
Here's a diagram I often show to people who have difficulty with pointers.

A pointer is basically just an 32-bit (or 64-bit) unsigned integer. However, with a pointer, its numeric value is interpreted as a memory address. So pointers just contain the locations in memory of other variables. That way, instead of passing huge chunks of data back and forth between functions in your code, you can just pass a memory address (a pointer) and operate on the data at that address (dereference the pointer).

The attached file shows a code snippet that declares some variables and some pointers to them. The diagram on the right shows a simplified version of what what the program's memory might look like after the code has executed. Each cell in the grid is one byte. Remember, ints take 4 bytes, doubles take 8, chars take 1, and pointers (regardless of type) take 4 bytes on a 32-bit machine.

Note that the 'type' of a pointer is used to tell the compiler what kind of data is at that memory location. That way, when you dereference a pointer, the computer knows how many bytes to fetch from that memory address. For example, dereferencing an int * will get the contents of the 4 bytes starting at that address, and dereferencing a double * will get the contents of the 8 bytes starting at that address.

Since the value of a pointer is always a number, every pointer points "somewhere." However, an uninitialized pointer might contain garbage, and point to some restricted area of memory; trying to dereference it would likely cause a crash. A NULL pointer has a value of 0 (that is, it points to memory address 0) and is, by convention, used to mean "this pointer points to nothing."
 

Attachments

  • pointers.png
    pointers.png
    122.2 KB · Views: 84

GoKyu

macrumors 65816
Original poster
Feb 15, 2007
1,169
24
New Orleans
Here's a simple program I wrote, but I'm having trouble with one particular line, which is commented out for the moment.

If I add that line back it, it gives me a compile error:

error: invalid operands to binary +

I was trying to add the different lengths together with strlen(), but I thought it needed to be typecast to be an int, so I'm not sure what needs to be done to fix this.

The program runs without the line, but it gives me a result of like 4096 characters, which is obviously wrong :)

Any help would be appreciated.

-Bryan

Code:
// This program will take input from the user and tell them how
// many characters they typed.

// Preprocessor directives
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main (void)
{
	int charAmount;
	char firstName[15];
	char lastName[20];

	system("clear"); // Clear the screen

	printf("Please enter your first name: "); 
	scanf(" %s", firstName);

	printf("\nPlease enter your last name: ");
	scanf(" %s", lastName);
	
//	charAmount = (int)strlen(firstName + lastName);

	printf("\n\nYour name is %s %s ",firstName, lastName); 
	printf("and you typed %d characters.", charAmount);

	return 0;
}
 

ChOas

macrumors regular
Nov 24, 2006
139
0
The Netherlands
Code:
//	charAmount = (int)strlen(firstName + lastName);

you can't just concatenate strings like that. A quick solution in this case would be:

Code:
 charAmount = strlen(firstName) + strlen(lastName);

This adds the lengths of the two stings together.

Check for strcat and strncat to learn more about concatenating strings.
 

GoKyu

macrumors 65816
Original poster
Feb 15, 2007
1,169
24
New Orleans
you can't just concatenate strings like that. A quick solution in this case would be:

Code:
 charAmount = strlen(firstName) + strlen(lastName);

This adds the lengths of the two stings together.

Check for strcat and strncat to learn more about concatenating strings.

Thanks, that worked perfectly :) Not too bad for my first attempt at anything more than a "Hello World" program...

One other question I had about printf() that I haven't seen in my book....

My original code looked like this:

Code:
printf("\n\nYour name is %s %s ",firstName, lastName, "and you typed %d characters.", charAmount);

I thought you could do this....it compiles this way, but it stops after printing the name and never hits the "and you typed...." part.

Is there a way to put everything into one printf() statement, or do you need to break it into multiple statements and only have one set of argument lists per printf() ?

Thanks again for your help :)

-Bryan
 

lee1210

macrumors 68040
Jan 10, 2005
3,182
3
Dallas, TX
Code:
printf("\n\nYour name is %s %s ",firstName, lastName, "and you typed %d characters.", charAmount);

I thought you could do this....it compiles this way, but it stops after printing the name and never hits the "and you typed...." part.


Code:
printf("\n\nYour name is %s %s and you typed %d characters.",firstName,lastName,charAmount);

Multiple format strings doesn't jive as far as I know. You could print another string literal using the %s format specifier, but I can't think of a compelling reason to do so.

-Lee
 

GoKyu

macrumors 65816
Original poster
Feb 15, 2007
1,169
24
New Orleans
Lee:

Wow, ok, it's been a long time since I last was learning C regularly...I should've thought of just doing it the way you showed.

Thanks again,

-Bryan
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.