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
Morham
Jun 4, 2007
Logic is one of those things that I always feel like I almost understand, the answer is on the tip of my tongue I just can't spit it out :(

I think I sort of get it though, and I'll continue to mull it over until I know I get it. Thanks for the speedy replies guys! Also regarding the 'y' and 'n' thing, I tried it but it doesn't seem to work. Hence the magic numbers.

Adbot
ADBOT LOVES YOU

schnarf
Jun 1, 2002
I WIN.

Morham posted:

Also regarding the 'y' and 'n' thing, I tried it but it doesn't seem to work. Hence the magic numbers.
Did you use double quotes instead of single quotes?

MutantBlue
Jun 8, 2001

nielsm posted:

Lastly, a good rule to learn is this:
If X and Y are boolean expressions, then !(X&&Y)==(!X||!Y), and conversely !(X||Y)==(!X&&!Y).
(It has a name which I forgot.)
De Morgan's laws

SadBag
Jun 24, 2012

Something has gone very wrong for us to get to the point where Hot Dog is the admiral.
I am attempting to modify a file using fgets and fprintf.
Occasionally when modifying something, junk gets thrown to the end of the file(junk that looks like someone took a snippit of the previous lines), or the line repeats itself.
When junk gets thrown to the end, the string used in fprintf doesn't look like what is at the end. Any guesses?

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
Cosmic rays are corrupting your computer's memory. Or maybe you've found a bug in the standard library.

Or, far more likely, your code is doing it wrong, but we can't figure out how it's wrong or tell you how to fix it because we have no idea what your code is.

(Post your code)

Bonfire Lit
Jul 9, 2008

If you're one of the sinners who caused this please unfriend me now.

My crystal ball is telling me you're overwriting the string's null terminator when you're modifying the line.

SadBag
Jun 24, 2012

Something has gone very wrong for us to get to the point where Hot Dog is the admiral.
It's a school project, so I feel uncomfortable posting. I think I'm on the right track though. I've noticed that the amount of junk at the end corresponds to how much was deleted in the file. ie 20 characters deleted adds 20 characters to the end

Vinterstum
Jul 30, 2003

SadBag posted:

I am attempting to modify a file using fgets and fprintf.
Occasionally when modifying something, junk gets thrown to the end of the file(junk that looks like someone took a snippit of the previous lines), or the line repeats itself.
When junk gets thrown to the end, the string used in fprintf doesn't look like what is at the end. Any guesses?

Are you trying to modify the file while you're reading from it?

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
Is it really adding it to the end, or is the file just staying the same length even though you're removing characters from the middle?

SadBag
Jun 24, 2012

Something has gone very wrong for us to get to the point where Hot Dog is the admiral.

Jabor posted:

Is it really adding it to the end, or is the file just staying the same length even though you're removing characters from the middle?

yeah, I think this is it.

Vinterstum posted:

Are you trying to modify the file while you're reading from it?

yes. I'm writing a self-modifying program.

Vinterstum
Jul 30, 2003

SadBag posted:

yeah, I think this is it.


yes. I'm writing a self-modifying program.

Ok. Just be aware of the current seek position. And this may be obvious, but: How are you removing characters from the middle of the file, exactly? The only way to do that is read in the rest of the file into a buffer, and write out that buffer again where you want to remove a section of it. The OS won't shuffle the rest of the file back and forth automatically, just because you insert/remove something in the middle. You just overwrite what's there.

EDIT: Hard to give any better answers without seeing any code.

Vinterstum fucked around with this message at 16:00 on May 15, 2013

SadBag
Jun 24, 2012

Something has gone very wrong for us to get to the point where Hot Dog is the admiral.
yeah, I began replacing the "" when replacing r++; now I use four spaces and it seems to delete more smoothly, but I still occasionally get an error

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!
The thing nobody has explicitly said yet, that you need to do, is truncate the file to the current seek position when you're done writing. Either that or read the whole file into memory, close it, and re-open it for writing (rather than read-write), since that way you'll start from an empty file.

ftruncate(filedescriptor,length);

Morham
Jun 4, 2007

schnarf posted:

Did you use double quotes instead of single quotes?

Definitely used single quotes. Is it something C can do or is it from C++ ?

astr0man
Feb 21, 2007

hollyeo deuroga
It's supposed to be single quotes, and it works in C. If it didn't compile for you there was something else wrong with your code.

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe
What's the compiler error?

Morham
Jun 4, 2007
It compiles, but when I type y or n it doesn't complete the loop it just keeps going.

Dren
Jan 5, 2001

Pillbug
I would have to see his code but I'm pretty sure the input == 'y' style of check doesn't work because input is a char *.

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe
Then why would the raw number work?

Dren
Jan 5, 2001

Pillbug

Suspicious Dish posted:

Then why would the raw number work?

Excellent point. I thought it was weird that he was doing scanf("%s", &input) rather than scanf("%c", &input). A quick test shows that scanf accepts a char * for the "%s" and "%c" format strings. The man page says that it writes a \0 when used with the "%s" specifier. If he's using "%s" with a char instead of a buffer scanf is probably overwriting something it shouldn't with that null-byte, which may lead to undefined behavior.

In the interest of helping him out, here is a chart of the boolean logic involved:

code:
Would you like to play again? (y/n): j
input == 'y'                 false
input == 'n'                 false
input != 'y'                 true
input != 'n'                 true
input == 'y' || input == 'n' false
input == 'y' && input == 'n' false
input != 'y' || input != 'n' true
input != 'y' && input != 'n' true

Would you like to play again? (y/n): y
input == 'y'                 true
input == 'n'                 false
input != 'y'                 false
input != 'n'                 true
input == 'y' || input == 'n' true
input == 'y' && input == 'n' false
input != 'y' || input != 'n' true
input != 'y' && input != 'n' false

Would you like to play again? (y/n): n
input == 'y'                 false
input == 'n'                 true
input != 'y'                 true
input != 'n'                 false
input == 'y' || input == 'n' true
input == 'y' && input == 'n' false
input != 'y' || input != 'n' true
input != 'y' && input != 'n' false

Byde
Apr 15, 2013

by Lowtax
I have some questions about the code below. I'm creating a situation where two structures are defined with the same name in the header and implementation files, except one has its members as constant variables while the other has its variables as non-constant. This is so the code outside the implementation code won't be able to manipulate and change the variables yet can still access them (as the header version is passed as the implementation version if passed by pointer to the implementation file's functions).

Problem is, I think the code has some hidden issues I'm not seeing on the surface. Would the constant variables in the header file take the same positions, address-wise, as the ones in the source file for every case/compiler, or would they mix up, ruining the overall implementation? Can one have a non-constant pointer point to a structure's constant variable set up this way and change the contents there? There's already a constraint in that both versions of the structure have to be the same size and thus have all variables accessible in some way (otherwise the size differences cause wonky results between the file with the non-constant variables and every other file using the header version).

C code:

// thing.h - the header file

#ifndef THING_H
#define THING_H

typedef struct _thing thing;
struct _thing
{
    const int foo;
    const int* const bar;
};

//Declarations of functions dealing with "thing"

#endif

// thing.cpp - the implementation file

typedef struct _thing thing;
struct _thing
{
    int foo;
    int* bar;
}

//Definitions of functions dealing with "thing"

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

Byde posted:

I have some questions about the code below. I'm creating a situation where two structures are defined with the same name in the header and implementation files, except one has its members as constant variables while the other has its variables as non-constant. This is so the code outside the implementation code won't be able to manipulate and change the variables yet can still access them (as the header version is passed as the implementation version if passed by pointer to the implementation file's functions).

That is an ODR violation, and aside from abstractly making your code invalid, there are several concrete ways that it could cause miscompiles (e.g. it might change how a value of that type wold be passed or returned). It is unlikely to change the layout of the type, though.

You're using C++; why would you not just use access control instead of playing games like this?

shrughes
Oct 11, 2008

(call/cc call/cc)

Byde posted:

[Insanity.]

code:

// thing.h - the header file

#ifndef THING_H
#define THING_H

class thing {
public:
  int foo() const { return foo_; }
  const int *bar() const { return bar_; }

  // Declarations of functions dealing with "thing"

private:
  int foo_;
  int* bar_;
};

#endif  // THING_H
code:

// thing.cpp - the implementation file

#include "thing.h"

// Definitions of functions dealing with "thing"

If you really want the functions to be external, declare them to be friend functions. Or make them static functions in another class and declare the class a friend class. Or make them static functions in the thing class.

Byde
Apr 15, 2013

by Lowtax
Well, I meant it to be for plain C (I added a .cpp when I meant .c), which doesn't have much in the way of access control, and it's really more of an experiment than anything, but thanks anyway.

Suspicious Dish
Sep 24, 2011

2020 is the year of linux on the desktop, bro
Fun Shoe
Use accessor functions in that case, and simply give them an opaque pointer.

yippee cahier
Mar 28, 2005

Ciaphas posted:

Lots and lots (and lots) of what amounts to file format conversions, basically. It's all worked so far since we've only targeted one platform (namely, ours--SunCC/SunOS/SPARC) but with the eventual (like, 2+ years out) move to g++/Linux/Intel I've been checking out possible portability issues left and right, and this one occurred to me suddenly.

From last page, but check out stdint.h

BirdOfPlay
Feb 19, 2012

THUNDERDOME LOSER
I'm working on a personal project that deals with SQL databases and such. I'm writing wrapper classes to handle individual records and the connection to the table/database to a) streamline the 3 main "commands" in SQL: INSERT, UPDATE, and DELETE and b) facilitate multiple SQL libraries all with the same basic interface (PS, what is the generic CS/Software Engineering term I'm looking for here for things like this usage of an abstract base class? Interface seems to be a Java term...). I've started working on the db classes and I've hit a bit of a snag with primary keys: I can't figure out a good way to handle primary key creation. Specifically, the question is should it be a method of my database or record class?

The issue is that to make a new primary key, you need, at the least, all active primary keys of a given table (so there's no duplicates), but, in some cases, you'll need to pull data from a record (either the record in question or a record based on a QUERY of another table).

Described like that, it makes some sense for that database class to handle it and just ask the record for what it needs, if it even needs it. The problem is that the record is the one that would what kind of table we're dealing with and, thus, what needs to be done to generate a new primary key. Any thoughts?

Slash
Apr 7, 2011

Shouldn't you let the database itself handle the primary key creation? Using for example an auto-incremented identity column.

When you create a record the database will automatically create the key for you. You can use DBCC commands in SQL Server to find the current identity value(DBCC CHECKIDENT "tablename") if you for some reason you need the ID before creating the record.

Reference material: http://www.w3schools.com/sql/sql_autoincrement.asp

Slash
Apr 7, 2011

e: quote is not edit.

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
From the issues you're describing, it sounds like you're not really designing your tables correctly.

Your primary key should either be completely synthetic (in which case just use an autoincrement column or whatever), or wholly dependent on the record (and if two records have the same primary key, they're the same record). Having a primary key that is partly synthetic and partly depends on the record is really silly.

If you tell us more about your actual database structure you could probably get some help with unsillifying it.

BirdOfPlay
Feb 19, 2012

THUNDERDOME LOSER
I'll preface all this by saying that the application, as a whole, handles school/college tracking and is akin to something like CourseWeb lite. And I don't write just a little bit, ever, it seems.

StorrowS posted:

Shouldn't you let the database itself handle the primary key creation? Using for example an auto-incremented identity column.

...:v: Maybe? I'm just now learning database stuff and probably skipped over that part.

quote:

When you create a record the database will automatically create the key for you. You can use DBCC commands in SQL Server to find the current identity value(DBCC CHECKIDENT "tablename") if you for some reason you need the ID before creating the record.

Reference material: http://www.w3schools.com/sql/sql_autoincrement.asp

While most of the ID's are strictly internal, there are a couple that are should be unique and are based on real world data. The chief one being a Student's ID#, as it would be bad design to use a separate incrementing ID when the student already has a number that can be used to quickly reference them anywhere else. If I'm adding a new student, I have to make a new student ID out of thin air. I also have to insure that there are no duplicates.

And yes, the light bulb did just go off in that I should pass this off to either the constructor for the StudentRecord class or leave it to central Ops to find a valid ID. As opposed to doing it in my INSERT function...

Jabor posted:

From the issues you're describing, it sounds like you're not really designing your tables correctly.

Your primary key should either be completely synthetic (in which case just use an autoincrement column or whatever), or wholly dependent on the record (and if two records have the same primary key, they're the same record). Having a primary key that is partly synthetic and partly depends on the record is really silly.

Yeah, I realized I was poorly explaining it, especially without a concrete example thrown in. As you can see above for the Student ID#, I would have to crosscheck against the list of active Student ID's during creation to make sure there wasn't any conflicts. Given the example above, does it sound a little less silly?

quote:

If you tell us more about your actual database structure you could probably get some help with unsillifying it.

I'm not opposed to; I even have one of those cool boxy-diagram-thingies doodled up in my notebook with lines going all over the place. (Looks like this image) If it'd help, I could post either a scan or clean digital one.

Basically, I have about 10 distinct types of tables. Of those ten, 6 are in the master database (the school's central records) with 2 being maps or relation tables (e.g. StudetSchedule just has a two field record of a Student ID and a Course ID) and the other four having dedicated ID's. The other four are used to represent a teacher/professor's individual class for grading purposes, meaning there's a database per class/course/teacher (how to bundle this properly is an unknown for right now). For this, there's 1 map and 3 with distinct ID's. And, lastly, several of the ID's are stored in other tables for reference. Easy example, a student's record will just store the ID for whatever their declared major is.

If this does sound silly, well, I'm open to suggestions.

FlapYoJacks
Feb 12, 2009

Morham posted:

It compiles, but when I type y or n it doesn't complete the loop it just keeps going.

[Y][\N]

That's what the program sees when you hit enter. Does y\n == y? Nope.

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
Is your system going to be the canonical record of student information? If so, then there's no problem with using an autoincrementing id for students - the only issue is importing the existing information and setting it to start generating new student ids at the correct point.

If your system is not going to be the canonical record, then it shouldn't be creating new students - it should be retrieving the existing id number from the canonical source. If you do it any other way, you're still going to run into conflicts when you create a new student, and the canonical source creates a different new student, and they have the same id numbers.

Jabor fucked around with this message at 09:43 on May 18, 2013

ether
May 20, 2001

BirdOfPlay posted:

While most of the ID's are strictly internal, there are a couple that are should be unique and are based on real world data. The chief one being a Student's ID#, as it would be bad design to use a separate incrementing ID when the student already has a number that can be used to quickly reference them anywhere else. If I'm adding a new student, I have to make a new student ID out of thin air. I also have to insure that there are no duplicates.

Bad design or not, using real world visible data as keys (which might be subject to change now or in the future) complicates your schema on other ways. StudentID is not at all a fixed number (or a number at all) in the software we created used for tracking close to a million students in the Netherlands. We made the same assumption as well in the past and have had to rework quite a bit to allow changing studentid's. The solution now is an ugly hack because the schema is like that.

I personally wouldn't use visible data as a key ever as rule of thumb.

Morham
Jun 4, 2007
Ok just to put this one to bed, I got it working, thank you all for your help. I am still not 100% sure I get it but it is at least there for me to look at and decipher in my own time.

code:
char again;

do
{
   printf("Would you like to try again? (y/n): ");
   scanf("%s", &again);
}
while (!(again == 'y' || again == 'n'));
Like ratbert90 said the computer would see '[y][\n]' however the character variable 'again' is only capable of holding one character (unlike if I made it a char*), so it takes the 'y' and ignores the '\n'. I am assuming this is the correct interpretation and why this works.

Interestingly if I set it to take a character ('%c') it prints the 'would you like to try again (y/n): ' line twice before stopping to ask for input.

Coding is weird.

nielsm
Jun 1, 2009



When you use the %s specifier with a plain char, like there, you are writing, at least, two bytes into the address of the char. That translates to writing the first byte at the actual variable's address, and a zero at the following address. And if the user enters more than one character, it will write all of them into memory, starting at that address, overwriting whatever is on the stack, blindly. That can break your program in all kinds of ways (and is the kind of coding that causes security vulnerabilities.)

Morham
Jun 4, 2007
Awww but it works :( ok I'll fix it...somehow.

mobby_6kl
Aug 9, 2009

by Fluffdaddy
Try using getchar() instead, perhaps?

Gul Banana
Nov 28, 2003

does scanf not have a %c? just use that if it does.

Adbot
ADBOT LOVES YOU

astr0man
Feb 21, 2007

hollyeo deuroga
So I went back and looked at what you were doing before.

Morham posted:

C++ code:
do
{
}
while (input != 'y'&& input != 'n');

Assuming that input is a char array or a char *, the reason your code doesn't work here is because you aren't comparing only the first character.

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