Where did I make that claim?
Printable View
Where did I make that claim?
void *p = NULL;Quote:
Eh, you are the one who claim that: *P = NULL is different from *p = 0 or *p = (void*)0.
void *p = 0;
These two statements have the same effect. I never once claimed they didn't. Have you looked at both the footnote in 7.22.3.2 and the link I gave you earlier?
From what I see, Barney McGrew is not confused about that. The problem is that you want to initialise the pointers to all bits zero using calloc, because you think that somehow is always equivalent to the representation of a null pointer ;)Quote:
Originally Posted by Subsonics
I was looking for a refutation of your suggestion to use calloc, but I see that Barney McGrew has already referred to "the footnote referenced in 7.22.3.2 of the standard". This presumably refers to C11, because in C99 that footnote is number 252 referenced in clause 7.20.3.1.
EDIT:
Okay, instead of just referring to it, let's just cite it:
Quote:
Note that this need not be the same as the representation of floating-point zero or a null pointer constant.
You're wrong.Quote:
Of course you did!
Have you looked at both the footnote in 7.22.3.2 and the link I gave you earlier?
EDIT:
@laserlight:
Oh, I didn't realise that. Good catch.Quote:
This presumably refers to C11, because in C99 that footnote is number 252 referenced in clause 7.20.3.1.
I think it does: as an unsigned integer, that would be the representation. All three signed integer representations allowed by the standard are such that 0 has all bits zero (I don't think negative zero applies here). On the other hand, the representation of a null pointer (or possible null pointer constants) is left to the implementation without such a constraint.Quote:
Originally Posted by Subsonics
See, that's what I don't get. If you assign NULL to a pointer, and NULL is 0 or (void*)0, then the only way the value the pointer would get by being initialized to 'all bits zero' could be different, is if somehow 0 is not 'all bits zero'. Which is why the distinction from a floating point zero also makes sense no?
If NULL is 0, and a null pointer's internal representation is not all bits zero, then the compiler could just translate it as such when it sees that NULL is assigned to or used to initialise a pointer. If the representation of (void*)0 is not all bits zero, then the compiler can translate the result of the cast to be whatever the representation of the null pointer constant should be.Quote:
Originally Posted by Subsonics
Consider (double)0. If the representation of 0.0 is not all bits zero, then (double)0 could well have a representation that is not all bits zero. But how is that possible when 0 is all bits zero?Quote:
Originally Posted by Subsonics
Well that's subtle, especially since the value of NULL is required to be 0. It would be interesting to know of one practical example of this on this side of the seventies, and the rationale for leaving it in the standard.
I was thinking of how IEEE 754 is not a standard requirement and how in theory an integer could also be represented differently but per post #23 that isn't allowed apparently.
Quote:
It would be interesting to know of one practical example of this on this side of the seventies, and the rationale for leaving it in the standard.
Well, like I said, that link I gave you explains this topic thoroughly: Question 5.17
Hi again guys,
Thanks for the interesting discussion. I have a follow up question.
I'm using a modified version of the allocation function in the OP shown below. Sorry in advance for any weird indentations. The post box seems to hate my properly indented code (being pasted from a linux VM) and fixing it requires modifiying every line. Hopefully it's not too difficult to parse.
For the purposes of my question, we're not interested in the branch that calls Database_load. Assume that the function is always being called with "c" being the active case.Code:struct Connection *Database_open(const char *filename, char mode, int numrows, int stringsize)
{
struct Connection *conn = malloc(sizeof(struct Connection));
if(!conn) die("Memory error");
conn->db = malloc(sizeof(struct Database));
conn->db->numrows = numrows;
conn->db->stringsize = stringsize;
if(!conn->db) die("Memory error");
//Allocate memory for a set of Address pointers
conn->db->rows = malloc(sizeof(struct Address)*numrows);
if(!conn->db->rows) die("Memory error in row creation");
//Allocate the memory for each string field of the each Address struct and
//assign.
int i = 0;
for(i = 0; i < numrows; i++){
conn->db->rows[i].name = malloc(sizeof(char)*stringsize);
printf("The pointer to name is %p\n",conn->db->rows[i].name);
if(!conn->db->rows[i].name) die("Memory error in name field creation");
conn->db->rows[i].email = malloc(sizeof(char)*stringsize);
printf("The pointer to email is %p\n",conn->db->rows[i].email);
if(!conn->db->rows[i].email) die("Memory error in email field creation");
conn->db->rows[i].id = i;
conn->db->rows[i].set = 0;
}
if(mode == 'c') {
conn->file = fopen(filename, "w");
} else {
conn->file = fopen(filename, "r+");
if(conn->file) {
Database_load(conn);
}
}
if(!conn->file) die("Failed to open the file");
return conn;
}
Database_open is called from the following main:
I'm always calling this with the "c" argument. Now, for the source of the problem, the Database_write function:Code:int main(int argc, char *argv[])
{
if(argc < 3) die("USAGE: ex17 <dbfile> <action> [action params]");
//Test constants
int numrows = 5;
int stringsize = 5;
char *filename = argv[1];
char action = argv[2][0];
struct Connection *conn = Database_open(filename, action, numrows, stringsize);
int id = 0;
if(argc > 3) id = atoi(argv[3]);
if(id >= numrows) die("There's not that many records.");
switch(action) {
case 'c':
Database_create(conn);
Database_write(conn);
break;
case 'g':
if(argc != 4) die("Need an id to get");
Database_get(conn, id);
break;
case 's':
if(argc != 6) die("Need id, name, email to set");
Database_set(conn, id, argv[4], argv[5]);
Database_write(conn);
break;
case 'd':
if(argc != 4) die("Need id to delete");
Database_delete(conn, id);
Database_write(conn);
break;
case 'l':
Database_list(conn);
break;
default:
die("Invalid action, only: c=create, g=get, s=set, d=del, l=list");
}
Database_close(conn);
return 0;
}
I've replaced the functional code with print statements to see what was going on, because I was getting a segfault and it seemed that each fwrite operation was seeing the "conn->db->rows[i].email/name" pointer as being null.Code:void Database_write(struct Connection *conn)
{
rewind(conn->file);
int rc = fwrite(conn->db, sizeof(struct Database), 1, conn->file);
if(rc != 1) die("Failed to write db to database.\n");
int sc = fwrite(conn->db->rows, sizeof(struct Address)*conn->db->numrows,1,conn->file);
if(sc !=1) die("Failed to write rows to database.\n");
int i =0;
for(i = 0; conn->db->numrows; i++){
printf("Name addr:\t%p\n",conn->db->rows[i].name);
printf("Email addr:\t%p\n",conn->db->rows[i].email);
/*
int rowname = fwrite(conn->db->rows[i].name, (sizeof(char*)*(conn->db->stringsize)), 1, conn->file);
if(rowname != 1) die("Failed to write name row");
int rowemail = fwrite(conn->db->rows[i].email, (sizeof(char*)*(conn->db->stringsize)), 1, conn->file);
if(rowemail != 1) die("Failed to write email row");
*/
}
rc = fflush(conn->file);
if(rc == -1) die("Cannot flush database.");
}
When I run it with functional code active and valgrind I get a segfault and the notification that address 0x0 is not stack'd malloc'd or recently freed.
When I run it with print codes active, it goes into an infinite loop printing "Name addr: (nil)" etc.
Now, the truly confusing thing. In an earlier stage of development, I ran the main code without calling any of the switch stuff (commented out), it just went straight from Database_open to Database_close (shown below).
Database_close had absolutely no trouble freeing the allocated memory, which would imply to me that it wasn't seeing nil pointers. So what does the write function see nil pointers (how is nil different from null).Code:void Database_close(struct Connection *conn)
{
int i = 0;
if(conn) {
if(conn->file) fclose(conn->file);
if(conn->db->rows){
for(i=0;i<conn->db->numrows;i++){
if(conn->db->rows[i].name) free(conn->db->rows[i].name);
if(conn->db->rows[i].email) free(conn->db->rows[i].email);
}
free(conn->db->rows);
}
if(conn->db) free(conn->db);
free(conn);
}
}
Sorry for the big code bomb, does anyone have any insight as to why I'm getting segfault errors?
Look at line 14 in your third code snippet. What condition must be true for the body of the for statement to be performed?
*Bangs head
I can't believe I missed that, funny how we see what we want to see! Unfortunately the function still sees null pointers.