Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
b0lt
Apr 29, 2005
^ :argh:

Hot Yellow KoolAid posted:

I'm having some trouble with a really simple C assignment dealing with pointers. It's supposed to be a review, but I'm not sure where I'm messing up. Here's my code: http://pastie.org/4894219

The program is supposed to tokenize a string into substrings and load them into a 2d char array. I'm not sure if the program doesn't move pointers between functions properly.

When I run it in GDB, I get the following crash:
code:
*** glibc detected *** /home/goon/Documents/344/Lab 1/prog2: double free or corruption (out): 0x00007fffffffe020 ***
This crash happens after executing line 21.

The memory address at the end of the message is the same address as the first **char, which properly prints "ls" in the function and GDB. I'm really at a loss.

That's because argv[x] doesn't point to malloced memory (except for x = 0). It's pointing to the inside of final, because you're allocating memory on line 55, but overwriting the pointer with the pointer returned by strtok, instead of copying the data out. Also, the free on line 61 doesn't do anything.

Adbot
ADBOT LOVES YOU

Vanadium
Jan 8, 2005


dude I got it entirely wrong

b0lt
Apr 29, 2005

Vanadium posted:

dude I got it entirely wrong

Well in that case :smug:

:v:

Hot Yellow KoolAid
Aug 17, 2012

b0lt posted:

^ :argh:


That's because argv[x] doesn't point to malloced memory (except for x = 0). It's pointing to the inside of final, because you're allocating memory on line 55, but overwriting the pointer with the pointer returned by strtok, instead of copying the data out. Also, the free on line 61 doesn't do anything.

So, if use strcpy(final[tracker], temp) instead of the statement on line 56 would it copy over the string without overwriting the malloced memory?
CHRONO EDIT: this gets rid of the error and exits the program normally, but I still need to investigate farther

The only other solution I can think of is directly manipulating argv in the makeargs method? I've tried a bunch of different pointer manipulations, but nothing has worked so far.

Edit2: Yeah, that first fix worked, and valgrind detects no leaks.

Hot Yellow KoolAid fucked around with this message at 02:54 on Oct 2, 2012

Paul MaudDib
May 3, 2006

TEAM NVIDIA:
FORUM POLICE
I'm trying to set up a solution in VS2010 that consists of a library, a launcher, and a tester executable for unit testing with GTest. The problem is I'm running into #include hell - I have a header file in the library that includes a struct definition as well as some function prototypes that involve that struct. Both the library and the launcher/test module need to include the header file and thus loadthat struct definition (despite it being #ifndef guarded) giving me a multiply defined structure error.

Unfortunately this is confidential code so I can't release much of it. Here are the conditions I'm operating under:

1. The library is set to build as a .dll
2. C/C++ mode is set to C++ in all projects to get GTest to work
3. Everything is guarded

What is the proper way to structure my headers and function prototypes so that I can get this tested?

e: I made the struct definition extern in that file and then moved the real definition somewhere else.

Paul MaudDib fucked around with this message at 04:43 on Oct 2, 2012

That Turkey Story
Mar 30, 2003

Paul MaudDib posted:

I'm trying to set up a solution in VS2010 that consists of a library, a launcher, and a tester executable for unit testing with GTest. The problem is I'm running into #include hell - I have a header file in the library that includes a struct definition as well as some function prototypes that involve that struct. Both the library and the launcher/test module need to include the header file and thus loadthat struct definition (despite it being #ifndef guarded) giving me a multiply defined structure error.

...


That's a linker error and doesn't have to do with include guards. In C++, you shouldn't be defining functions and globals inside of header files, unless they are inline and/or template definitions. So either move your definitions out of the header files and into a cpp file, or make them inline.

Edit: Actually, given your situation, what's more likely is that your DLL is defining and exporting functions and objects that your host application also defines, and then you are getting multiple definition errors when linking via the associated .lib.

That Turkey Story fucked around with this message at 04:58 on Oct 2, 2012

nielsm
Jun 1, 2009



Hot Yellow KoolAid posted:

So, if use strcpy(final[tracker], temp) instead of the statement on line 56 would it copy over the string without overwriting the malloced memory?
CHRONO EDIT: this gets rid of the error and exits the program normally, but I still need to investigate farther

The only other solution I can think of is directly manipulating argv in the makeargs method? I've tried a bunch of different pointer manipulations, but nothing has worked so far.

Edit2: Yeah, that first fix worked, and valgrind detects no leaks.

strcopy copies string data pointed to, straight assignment copies pointers. Since you want to make an actual duplicate of the (sub)string then you need to use strcopy.

o.m. 94
Nov 23, 2009

So I'm trying to build a linked list in C, please excuse rather naive commenting, code and implementation. I haven't done all the functions yet:

code:
#include <stdlib.h>
#include <stdio.h>

// Linked list node definition.
typedef struct ll_node {
   int val;
   struct ll_node *next;
} ll_node;

// Linked list data type definition.
typedef struct LinkedList {
    ll_node *current;
    const ll_node *head;
} LinkedList;

void ll_create(LinkedList *ll_ptr, int init_size);
void ll_change(LinkedList *ll_ptr, int index, int value);
void ll_print(LinkedList ll_var);
int ll_size(LinkedList ll_var);


void main() 
{
    LinkedList my_list;
    ll_create(&my_list, 10);
    ll_print(my_list);
    ll_change(&my_list, 2, 239);
    ll_print(my_list);
}


/* Initialise a linked list. Accepts a pointer to a LinkedList
 * struct, or just pass the address in for a newly created one.
 */
void ll_create(LinkedList *ll_ptr, int init_size)
{
    int i;
    ll_node *prev = NULL;

    /*  The LinkedList nodes are built in 'reverse', by creating a
        new block of memory for a node, filling it with a value, then
        linking it to the previously created node (which starts at the
        end as a null pointer.) */
    for(i = 1; i <= init_size; i++) {
        ll_ptr->current = (ll_node *) malloc(sizeof(ll_node));
        ll_ptr->current->val = i;
        ll_ptr->current->next = prev;
        prev = ll_ptr->current;
    }

    // Reset the position to the start of the linked list, set the head.
    ll_ptr->head = ll_ptr->current = prev;
}


/* 
 * Change the value of the LinkedList item at index.
 */
void ll_change(LinkedList *ll_ptr, int index, int value) {
    
    int i;
    ll_ptr->current = ll_ptr->head;

    for (i = 0; i < index; ++i) {
        ll_ptr->current = ll_ptr->current->next;
    }

    ll_ptr->current->val = value;
    ll_ptr->current = ll_ptr->head;
}


/*
 * Return number of items in LinkedList
 */
int ll_size(LinkedList ll_var) {
    int i = 0;
    
    for (i = 0; ll_var.current != NULL; i++)
        ll_var.current = ll_var.current->next;
    
    return i;
}


/* 
 * Print out a LinkedList.
 */
void ll_print(LinkedList ll_var) {
    
    // Make sure we're at the start of the list.
    ll_var.current = ll_var.head;

    printf("[");
    while (ll_var.current != NULL) {
        printf("%d, ", ll_var.current->val);
        ll_var.current = ll_var.current->next;
    }
    printf("]");
}
Anyway my main problem is that I get the following warnings from gcc:

code:
C:\Media\Programs\kochan>gcc linked_list.c

linked_list.c: In function 'll_change':
linked_list.c:62:21: warning: assignment discards 'const' qualifier from pointer target type [enabled by default]
linked_list.c:69:21: warning: assignment discards 'const' qualifier from pointer target type [enabled by default]
linked_list.c: In function 'll_print':
linked_list.c:92:20: warning: assignment discards 'const' qualifier from pointer target type [enabled by default]
It get what it's saying, and it's because of const ll_node *head;, which I want to *always* point to the head of the linked list, so I can perform operations in my functions that wish me to traverse the list by ensuring something is pointing at the start.

Ideally, I want to be able to set some constant pointer in the function ll_create() that will endure as a pointer to the first ll_node in the structure once it's been created, but I'm not sure where I've gone wrong. Any other critique or advice for my implementation so far is also welcome!

nielsm
Jun 1, 2009



First something general, remember that the main advantages of linked lists are easy iteration and insertion in the middle of them. Your interface presents it in an array-like fashion, which pretty much removes all the advantages of linked lists and leaves you with just the disadvantages.


Now, I honestly don't know how const works in C, but in C++:

const X foo; declares foo to be an X that cannot change.
X const foo; declares foo to be an X that cannot change. (Exactly the same as above!)
const X *foo; declares foo to be a pointer to an X, and the X cannot change.
X const *foo; declares foo to be a pointer to an X, and the X cannot change. (Exactly the same as above!)
X * const foo; declares foo to be a constant pointer to an X, the pointer cannot change but the X can.
X const * const foo; declares foo to be a constant pointer to a constant X.


Which of those does your declaration fall under? Does it match with the semantics you want?
(And taking my initial paragraph into consideration, does keeping the head of the list constant even match with the common use cases of linked lists?)

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe
Spiral rule is good for figuring these things out:

http://c-faq.com/decl/spiral.anderson.html

awesmoe
Nov 30, 2005

Pillbug
I want to throw a closure. This is easy! However I also want to catch the closure, and invoke it, but I can't see how :( Any suggestions? Is this even possible?

b0lt
Apr 29, 2005

awesmoe posted:

I want to throw a closure. This is easy! However I also want to catch the closure, and invoke it, but I can't see how :( Any suggestions? Is this even possible?

You need to explicitly construct a std::function from the lambda.

code:
#include <cstdio>
#include <functional>

int main(void)
{
    int foo = 1;
    try 
    {
        throw ::std::function< void (void) > ([foo] { printf("foo = %d\n", foo); });
    }
    catch (::std::function< void (void) > function)
    {
        function();
    }
}

raminasi
Jan 25, 2005

a last drink with no ice
Why is explicit construction needed like that?

raminasi fucked around with this message at 21:30 on Oct 2, 2012

b0lt
Apr 29, 2005

GrumpyDoctor posted:

Why is explicit construction needed like that?

Lambdas don't have a namable type so you can't catch them directly, and catch doesn't (and can't) do implicit conversion, so you can't throw them directly.

awesmoe
Nov 30, 2005

Pillbug
Excellent, thanks for that!

Dog Jones
Nov 4, 2005

by FactsAreUseless
I'm messing around with template meta-programming, and to learn it I'm gonna write a vector / matrix math library. I was thinking about the issue of invertibility today. Only matrices which are square should be invertible, so only matrices which have an equal number of columns and rows should have an "invert" function defined. I was thinking about using partial template specialization to do something like this (to put it simply):
code:
template<int col, int row> struct Invertible 
{

};

template<int sqCol> struct Invertible<sqCol, sqCol>
{
public:
	void Invert() { /*invert the matrix*/ }
};

// Matrix class:
template<int col, 
	int row> 
class Matrix : public Invertible<col,row>
{
	// Matrix stuff here
};
Which works. The problem is that "Invertible" doesn't have access to the matrix's class members so I don't know how I'd actually write Invert(). I was thinking that the Matrix class would also make use of a Storage policy that is contingent on the dimensions of the matrix and the integral type of each element. So maybe the policies would just "stack", something like:

code:
// Storage policies:
template<int col, int row, typename type> class ColumnWise
{
public:
	type Elements[col][row];
};
template<int col, int row, typename type> class RowWise
{
public:
	type Elements[row][col];
};

// Invertibility templates (I guess these aren't actually policies, so I don't know what to call them?):
template<int col, int row, 
	typename type, 
	template<int,int,typename> class StorageType> 
class Invertible
	: public StorageType<col,row,type>
{

};
template<int sqCol, 
	typename type, 
	template<int,int,typename> class StorageType> 
struct Invertible<sqCol, sqCol, type, StorageType>
{
public:
	void Invert() { /*invert the matrix*/ }
};

// Matrix class:
template<int col, int row,
	typename type,
	template<int,int,typename> class StorageType> 
class Matrix : public Invertible<col,row,type,StorageType>
{
	// Matrix stuff here
};
I was just hoping someone might have some insight on this topic, and could give me some good advice on how to structure my class hierarchy. Hopefully I'm not totally off base with the examples I provided.

schnarf
Jun 1, 2002
I WIN.
Rather than making Invert a member function, why not make it a regular function?
code:
template <typename T, size_t N>
Matrix<N, N> Invert(Matrix<N, N> mat) {
  // invert mat in-place
  return mat;
}
I think if you really wanted, you could do some enable_if crap to make the member function only exist when row==col, but that would be ugly.

Also, if you're using templates to write a matrix library, it's really worth learning about expression templates. If you're not familiar with them, expression templates are a technique for having the compiler generate some really efficient code for matrix math that doesn't create unnecessary temporary object. Eigen is a really great library that does this.

Senso
Nov 4, 2005

Always working
I'm having a problem trying the most simple Box2D examples:
code:
#include <Box2D/Box2D.h>

int main()
{
	b2Vec2 gravity(0.0f, -10.0f);
	b2World world(gravity);
	return 0;
}
I get a nasty run-time error in VS2010:
Assertion failed: s > 0.0f && "ERROR: Please ensure your polygon is convex and has a CCW winding order", file e:\box2d\collision\shapes\b2polygonshape.cpp, line 164

I was able to build it properly, I can run the whole testbed, I'm including Box2D.lib, etc. None of the examples or tutorials I found actually run, it's quite frustrating (also, a lot of tutorials are for older versions).

EDIT: It's me, I'm the retard. I created a separate project in VS2010 to be able to do small tests without rebuilding everything but when I hit F5 it ran the main project binary...

Senso fucked around with this message at 10:02 on Oct 5, 2012

Hot Yellow KoolAid
Aug 17, 2012
I have to compile some programs in both 32 and 64 bit mode in order to compare stack traces for my OpSys class. I'm not sure how to do this, but I know I need to install some libraries. Right now, I'm running Ubuntu 12.04. How do you do this?

Cat Plus Plus
Apr 8, 2011

:frogc00l:

Hot Yellow KoolAid posted:

I have to compile some programs in both 32 and 64 bit mode in order to compare stack traces for my OpSys class. I'm not sure how to do this, but I know I need to install some libraries. Right now, I'm running Ubuntu 12.04. How do you do this?

Install gcc-multilib. 32-bit code is compiled with -m32, 64-bit with -m64.

Hot Yellow KoolAid
Aug 17, 2012
Do you know the sudo command for installing gcc-multilib?

nielsm
Jun 1, 2009



Hot Yellow KoolAid posted:

Do you know the sudo command for installing gcc-multilib?

apt-get install <packagename>
For installing and removing packages from the commandline on Ubuntu, it's always apt-get.

Dog Jones
Nov 4, 2005

by FactsAreUseless

schnarf posted:

Also, if you're using templates to write a matrix library, it's really worth learning about expression templates. If you're not familiar with them, expression templates are a technique for having the compiler generate some really efficient code for matrix math that doesn't create unnecessary temporary object. Eigen is a really great library that does this.

Is there a good book on expression templates? I've been using "Modern C++ Design" by Andrei Alexandrescu for the TMP stuff so far, I'm not sure if that book gets into expression templates.

schnarf
Jun 1, 2002
I WIN.

Dog Jones posted:

Is there a good book on expression templates? I've been using "Modern C++ Design" by Andrei Alexandrescu for the TMP stuff so far, I'm not sure if that book gets into expression templates.

Try these two links:
http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Expression-template
http://www.angelikalanger.com/Articles/Cuj/ExpressionTemplates/ExpressionTemplates.htm

The basic idea is, rather than operator+(a, b) returning a new matrix, it returns a type that has knows how to add values, and has references to a and b. No computation is done just by writing "a + b". When you try to index into that special type, it actually evaluates the element's value at that point. So, if you write "c = a + b;", once that special type (the expression template) is assigned to c, at that point, the values are computed.

In a complicated matrix expression, say, "a * b + c / d", an expression template ends up being created that knows how to calculate each element of the resulting matrix, and when it's assigned, each element of the result is computed in a pretty efficient, potentially cache-friendlier way.

Diametunim
Oct 26, 2010
I'm hoping someone can help me out with the math portion of things here. I'm working on a program that calculates Sin(x), cos(x) and exp(x). Currently my code to calculate sin(x) looks like

code:
    
/*
	Compare library result and customized result.
*/

#include <stdio.h>
#include <math.h>

int main()
{
	double x, mysin();
	char more;

	do
	{
		printf("\n\t\t\tInput X: ");
		scanf("%lf", &x);
		printf("\n\t\t\tLibrary Result\tMy Result");
		printf("\n\t\tsin(%5.2f)\t%9.2f\t%9.6f", x, sin(x), mysin(x));

		//	Add cos() and exp() comparsions here

		printf("\n\t\t\tDo more(Y/N)?");
		scanf("%s", &more);
	}
	while(more == 'y' || more == 'Y');
}

double mysin(double x)
{
	double sum, power(), fact();
	int i, sign;

	for(i = 0, sum = 0, sign = 1; i < 20; i++, sign = -sign)
	{
		sum = sum + sign * power(x, 2 * i + 1) / fact(2 * i + 1);
	}

	return sum;
}

// Combine these functions

double power(double x, int n)
{
	int i;
	double prod;

	for(i = 0, prod = 1.; i < n; i++)
	{
		prod = prod * x;
	}

	return prod;
}

double fact(int n)
{
	int i;
	double prod;

	for(i = 1, prod = 1.; i <= n; i++)
	{
		prod = prod * i;
	}

	return prod;
}


I need to combine the bottom two functions into one. I've done some research and found that using a Taylor series is probably the way to get this done. The only problem is I'm half retarded with math and I don't fully understand the concept. Anyone have any ideas to get me going in the right direction?

Gazpacho
Jun 18, 2004

by Fluffdaddy
Slippery Tilde
When adding the Taylor series, it's not necessary to recalculate the powers and the factorials starting from 1 in each term because the factors in one term also appear in the next.

There are many approximations that improve on the Taylor series in both speed and accuracy, especially for exp() of large values, so whether it's appropriate for what you're doing will depend on what you're doing.

Gazpacho fucked around with this message at 07:04 on Oct 7, 2012

Volte
Oct 4, 2004

woosh woosh
Taylor series are generally really bad for computing elementary functions. A better method is by finding polynomials that approximate the function (something like Mathematica can compute these) to the desired precision within some small interval (like [0, pi/8] is enough for sin) and then reducing the range of the input so that it falls into that interval, and transforming the output back to the correct value through creative use of identities.

One way to do exp (it's actually easier to calculate exp2 and then scale the input accordingly to do other bases: exp(x) = exp2(x * log2(e))) would be to construct an IEEE number directly, since the exponent is stored directly in the bit pattern. So if the input is x = p + q where p is the integer part and q is the fraction (so 0.0 <= q < 1.0), then you just need to compute exp2(p + q) = exp2(p) * exp2(q), where exp2(p) is constructed directly and and it's much easier to compute exp2(q) when the range is reduced like that. The hard part of doing functions like this is getting as close to last-bit accuracy as possible for the entire range of inputs, as well as correctly handling denormalized numbers, zero, infinity, and NaN. Those things were only hard in my experience in doing this because the focus was always on maximum performance (as in no branches at all) and strict accuracy requirements, so if you aren't too concerned about that, then it should not be very difficult at all.

Dog Jones
Nov 4, 2005

by FactsAreUseless

schnarf posted:

Try these two links:
http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Expression-template
http://www.angelikalanger.com/Articles/Cuj/ExpressionTemplates/ExpressionTemplates.htm

The basic idea is, rather than operator+(a, b) returning a new matrix, it returns a type that has knows how to add values, and has references to a and b. No computation is done just by writing "a + b". When you try to index into that special type, it actually evaluates the element's value at that point. So, if you write "c = a + b;", once that special type (the expression template) is assigned to c, at that point, the values are computed.

In a complicated matrix expression, say, "a * b + c / d", an expression template ends up being created that knows how to calculate each element of the resulting matrix, and when it's assigned, each element of the result is computed in a pretty efficient, potentially cache-friendlier way.

Thanks man, I appreciate your help.

Boz0r
Sep 7, 2006
The Rocketship in action.
I still haven't gotten the hang of pointers yet. I'm trying to do a matrix multiplication in a tree traversal and I've got some annoying problems with it.

I've got this code:
code:
void function (f4x4 *matrix) {
	f4x4 inverseMatrix;
	...
	matrix = f4x4_mul(inverseMatrix, &matrix)
}

f4x4_mul(f4x4 l, f4x4 r)
and I get this error:
code:
incompatible type for argument 2
expected 'f4x4' but argument is of type 'struct f4x4 **'
What should I be writing instead?

nielsm
Jun 1, 2009



The & prefix-operator creates pointers, the * prefix-operator dereferences pointers.

In types, the * symbol indicates a level of pointer indirection.

This means that the & prefix-operator (the address-of operator) turns a value of type foo into a value of type foo*, adding another level of indirection.
Meanwhile, the * prefix-operator (the dereference operator) turns a value of type foo* into one of type foo, removing a level of indirection.


The compiler is telling you that it wants something of type f4x4 but that you gave it something of type f4x4**, so check your operator usage compared to the above.
Also check the type that the f4x4_mul() function returns, it's probably not compatible with the type of the matrix variable, but differs in level of indirection.


Also read this, posted a couple of days ago:

Suspicious Dish posted:

Spiral rule is good for figuring these things out:

http://c-faq.com/decl/spiral.anderson.html
(It's okay if you don't get all of it right now, but being able to read declarations in C is a valuable tool.)

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe
The other rule is that type declarations are meant to indicate use. That is, given an int ***a;, ***a will give you back an int. C++ of course breaks this rule with references (gently caress you), but that's another thing.

Hot Yellow KoolAid
Aug 17, 2012
For an assignment, I have to write a c program that simulates command line input hard coded as a string. Eventually we are supposed to write our own shell program, but for now the program just has to simulate the activity of a single command line ("ls -l | wc -w" in the assignment) using the PIPE, DUP, and FORK system calls (also probably EXECLP). I'm trying to figure out how to do this. The help we were given in class was the following code teaser (not complete):

code:
#include <stdio.h>
int main()
{
int fd[2];
pipe(fd);
if(fork()!= 0){
  close(fd[0]);
  close(1);
  close(2);
  dup(fd[1]);
  close(fd[1]);
  execlp("ls","ls","-l",NULL);
}
//not sure if I copped everything perfectly
return 0;
}// end main
From class notes, I infer the following:
-The first pipe command connects input 8 with output 7 (in gdb debug, printing "fd" yields {7,8})
-The if statement ensures that the following block only happens in the parent process
-The next three close commands close the pipes output, stdout, and stderr respectively
-The dup command connects the input of fd[1] to the lowest available input (should be stdout, or 1)
-closing fd[1] prevents any data from traveling through until it has been re-opened
-The remainder of the command line prompt ("| wc -w") is to be executed in a child process


What I'm not sure about :
-What the 7 and 8 signify in fd[0] and fd[1] after fd has been piped
-why the dup command doesn't change the value of fd[1] to 1
-what execlp does

I'm really struggling with the concept of pipes and forks, and I'm not sure where to even begin with this program. I would greatly appreciate some more general help understanding these concepts. Our instructor has clued us in that mastery of these two system calls is essential to this program and the rest of the class, so I am committed to learning this.

This isn't due for a few days, but I still want to make some progress while I have time to experiment.

b0lt
Apr 29, 2005

Hot Yellow KoolAid posted:

From class notes, I infer the following:
-The first pipe command connects input 8 with output 7 (in gdb debug, printing "fd" yields {7,8})
-The if statement ensures that the following block only happens in the parent process
-The next three close commands close the pipes output, stdout, and stderr respectively

These inferences are correct.

quote:

-The dup command connects the input of fd[1] to the lowest available input (should be stdout, or 1)

This isn't exactly what dup means. dup copies a file descriptor into another one such that they can be used interchangeably. That means that for example, when you write to stdout, it would be the same as if you had written to fd[1]. Incidentally, using dup() is kinda dumb here, because if you want to swap out stdout, it makes much more sense to do dup2(fd[1], stdout). (using 1 and 2 instead of the stdout and stderrSTDOUT_FILENO/STDERR_FILENO macros is pretty silly as well).

quote:

-closing fd[1] prevents any data from traveling through until it has been re-opened
It prevents stuff from travelling across that file descriptor, it doesn't block all traffic across the pipe (writing to stdout would do the same thing as writing to fd[1] if you hadn't closed it).

quote:

What I'm not sure about :
-What the 7 and 8 signify in fd[0] and fd[1] after fd has been piped
They're just arbitrary values, pipe picks the next two available file descriptors and returns them.

quote:

-why the dup command doesn't change the value of fd[1] to 1
dup takes a file descriptor (fd[1]) and copies its state into a new file descriptor (the lowest available one). Because you closed 1, it's the lowest available one, so it gets copied to there. Because stdout/stderr are fixed constants, anything that writes to stdout will be writing to the file descriptor that just got copied in, which is the pipe you just opened.

quote:

-what execlp does

execlp("foo", "bar", "1", "2", "3", NULL) launches the binary foo with ["bar", "1", "2", "3", NULL] as its argv.

quote:

I'm really struggling with the concept of pipes and forks, and I'm not sure where to even begin with this program. I would greatly appreciate some more general help understanding these concepts. Our instructor has clued us in that mastery of these two system calls is essential to this program and the rest of the class, so I am committed to learning this.

This isn't due for a few days, but I still want to make some progress while I have time to experiment.

One useful thing to keep in mind for the future is that everything (except for the return value of fork(), and some things you don't need to worry about) is the same before forking, but changes after the fork do not show up on the other side. For example, you can close one end of a pipe on one side of a fork, and the other end on the other, and get what you expect (one side can only read, one side can only write).

V Oops, I mean STDOUT_FILENO/STDERR_FILENO, of course. :downs:

b0lt fucked around with this message at 06:20 on Oct 9, 2012

pseudorandom name
May 6, 2007

stdout and stderr are FILE*, not file descriptors.

Edison was a dick
Apr 3, 2010

direct current :roboluv: only

b0lt posted:

execlp("foo", "bar", "1", "2", "3", NULL) launches the binary foo with ["bar", "1", "2", "3", NULL] as its argv.

Also, the p in the name means that it will search in your "$PATH" environment variable for the executable "foo". If you used execl instead you would need to specify an absolute path to the executable.
There's also the execv* variants, which instead of taking a NULL terminated list of arguments, takes a NULL terminated array of arguments, which is more useful most of the time.

Hot Yellow KoolAid
Aug 17, 2012
Ok, after visiting my instructor and getting some help, I got my program to work. Here's the code I came up with.

code:
int main() { 
	int fd[2]; 
	pipe(fd); 
	if(fork()!= 0){ 
		close(fd[0]); 
		close(1); 
		close(2); 
		dup(fd[1]); 
		close(fd[1]); 
		execlp("ls","ls","-l",NULL); 
	}
	else{
		close(fd[1]);
		close(0);
		dup(fd[0]);
		execlp("wc", "wc", "-w", NULL);
	} //not sure if I copped everything perfectly 
	return 0;
}
This duplicates the functionality of the "ls -l | wc -w" terminal command perfectly as far as I can tell. What I'm still trying to figure out is why it works. I still have the following questions.

--why is it necessary to close both ends of the pipe before executing the execlp commands? I know that it wouldn't work properly without closing, but I'm still trying to figure out why.

--How should I visualize the "execlp("ls","ls","-l",NULL);" command when both ends of the pipes are closed? The way I see it, either the command is stalled outside of the pipe at the read end (like a kinked hose), or the execlp command is actually generated inside of the pipe and is trapped inside because both ends are closed. Are either of these correct?

--Are the two "close(fd[1])" calls redundant?

--How does the child process (inside the else block) have access to the results of the system call in the parent process? I guess I still don't understand forking. When a child process is forked, does it start executing at the very beginning of the code or in the middle somewhere?

--Why do you close write/read ends of the pipe in the parent/child processes respectively?

Edit: Lastly, valgrinding this indicates that there is an open file descriptor at the exit. I'm not sure where this is coming from.

Hot Yellow KoolAid fucked around with this message at 19:29 on Oct 9, 2012

nielsm
Jun 1, 2009



First thing about forking:
The fork() function returns TWICE: Once in the calling process, and once in the new process. The new process is a complete copy of the original, including the state and point of execution. The only difference between the two processes at the time of return is the return value. The original process returns the PID of the new process, while the new process returns zero.

Therefore, this code:
C++ code:
if (fork()!=0) {
  /* stuff */
} else {
  /* different stuff */
}
means this:
C++ code:
duplicate_this_process();
if (this_is_the_parent_process){
  /* do parent process stuff */
} else {
  /* do child process stuff */
}
Now I don't know much about Unix file descriptors, but here is my guess:
The reason for the closing might be that, since both processes have copies of both endpoints of the pipe, trying to send data through the pipe will block until all endpoints of the pipe have read the data sent. If the sender doesn't close his input end of the pipe, his output will block until he reads it, i.e. a deadlock.

Boz0r
Sep 7, 2006
The Rocketship in action.
I've received some code from my instructor in C, but it seems like he's including some c++ libraries and my compiler is complaining.

code:
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>

#include <string>
#include <fstream>
#include <sstream>
#include <iostream>

#include <cmath>
It works when I just use his makefile, but when I try copying those includes to my own code, the compiler complains about the string, and stream includes.

What's wrong?

Vanadium
Jan 8, 2005

Yeah, those non-.h ones are definitely C++ headers, it shouldn't possibly compile in C. I guess his Makefile is calling the C++ compiler and you are using the C compiler.

Adbot
ADBOT LOVES YOU

Boz0r
Sep 7, 2006
The Rocketship in action.
Yeah, thanks. I think I got confused as the files were both named .C, and in the tiny top of the make file his calls g++ instead of gcc. I missed that.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply