I want to create a new function that will return me a actual temperature from DS18B20 as a float variable. I need that kind of variable to place a string on LCD.
Already I'm using function to read temperature like that:
int8_t readTemp(struct ds18b20 *d) {
struct ds18b20 *newTemp;
char tempAct[5];
while (d->next != NULL)
{
d = d->next;
int fd = open(d->devPath, O_RDONLY);
if (fd == -1)
{
perror("Couldn't open the w1 device.");
return 1;
}
char buf[256];
ssize_t numRead;
while ((numRead = read(fd, buf, 256)) > 0)
{
newTemp = malloc(sizeof(struct ds18b20));
strncpy(newTemp->tempData, strstr(buf, "t=") + 2, 5);
//float tempC = strtof(d->tempData, NULL);
sprintf(tempAct, "%s C", newTemp->tempData);
//printf("Device: %s - ", d->devID);
//printf("Temp: %.3f C ", tempC / 1000);
//printf("%.3f F\n\n", (tempC / 1000) * 9 / 5 + 32);
}
close(fd);
}
return 1;}
I have problem with sprintf from this line:
sprintf(tempAct, "%s C", newTemp->tempData);
In the main code:
int main(void) {
struct ds18b20 *rootNode;
struct ds18b20 *devNode;
struct ds18b20 *getTemp;
// Load pin configuration. Ignore error if already loaded
system("echo w1 > /sys/devices/bone_capemgr.9/slots>/dev/null");
while (1) {
rootNode = malloc(sizeof(struct ds18b20));
devNode = rootNode;
getTemp = rootNode;
int8_t devCnt = findDevices(devNode);
printf("\n Found %d devices\n\n", devCnt);
int8_t tempAct = readTemp(getTemp);
printf("\n Temp Act: %d \n\n", tempAct);
//readTemp(rootNode);
// Free linked list memory
while (rootNode) {
// Start with current value of root node
devNode = rootNode;
// Save address of next devNode to rootNode before deleting current devNode
rootNode = devNode->next;
// Free current devNode.
free(devNode);
}
free(rootNode);
}
return 0;}
I'm trying to recreate the functions from finddevices:
int8_t devCnt = findDevices(devNode);
printf("\n Found %d devices\n\n", devCnt);
int8_t tempAct = readTemp(getTemp);
printf("\n Temp Act: %d \n\n", tempAct);
But the tempData* isn't imported from readTemp fuction to main code.
The code is littered with issues that are not explicitly part of your question. Just some:
readTemp() does not return temperature. In fact it returns 1 if it fails and 1 if it succeeds. That is probably an error.
readTemp() appears to read all available temperature sensors, passed to it as a linked list of struct ds18b20 not just one. But actually skips the root node and accesses the second and subsequent without checking it is valid. If the root node contains no device (just a pointer to the first device), then you need only pass it pass rootNode->next instead.
It is not clear why it dynamically allocates a new struct ds18b20 or why it fails to later de-allocate. That is a serious memory leak.
At a guess the following is more likely to be close to what you need (without knowing anything about struct ds18b20 or what the expected output of the sensor is - just going by the evidence in the code (and commented out code) you have posted - so some bold assumptions have been made.
int readTemp( struct ds18b20 *d, // List of sensors
float* temperatures, // Pointer to array to receive temperatures
int8_t max_temperatures ) // Max number of temperatures to receive
{
struct ds18b20* sensor = d ;
int count = 0 ;
while( sensor != NULL && count < max_temperatures )
{
int fd = open( sensor->devPath, O_RDONLY ) ;
if( fd >= 0 )
{
if( read( fd, buf, sizeof(buf) ) > 0 )
{
char buf[256];
char* temp_str = strstr(buf, "t=") + 2 ;
sscanf( temp_str, "%f", &temperatures[count] ) ;
temperatures[count] /= 1000 ;
count++ ;
}
close( fd ) ;
sensor = sensor->next ;
}
else
{
perror("Couldn't open the w1 device.");
}
}
return count ;
}
Then in you can call it thus:
int8_t devCount = findDevices( rootNode ) ;
float* temperatures = malloc( devCnt * sizeof(float) ) ;
int8_t tempCount = readTemp( rootNode->next, temperatures, devCount ) ;
for( int i = 0; i < tempCount; i++ )
{
printf( "Temp Act: %f\n", temperatures[i] ) ;
}
free( temperatures ) ;
If you know there is only one device or you only need print the first, then this can be simplified:
int8_t devCount = findDevices( rootNode ) ;
if( devCount > 0 )
{
float temperature = 0f ;
int8_t tempCount = readTemp( rootNode->next, temperature, 1 ) ;
if( tempCount > 0 )
{
printf( "Temp Act: %f\n", temperature ) ;
}
}
Issues in your main() are also varied, including:
The root node is needlessly dynamically allocated
several aliases to the root node are needlessly created
The device list is repeatedly re-enumerated and the device list allocated and free'd on every iteration of a non-terminating loop. Assuming the number of sensors does not change while the code is running, this is unnecessary.
The loop never ends - even in the event of an error.
A better implementation might look something like:
int main(void)
{
// Load pin configuration. Ignore error if already loaded
system("echo w1 > /sys/devices/bone_capemgr.9/slots>/dev/null");
struct ds18b20 rootNode = { 0 } ;
int8_t devCount = findDevices( rootNode ) ;
if( devCount > 0)
{
struct ds18b20* devlist = rootNode->next ;
float* temperatures = malloc( devCount * sizeof(float) ) ;
int8_t tempCount = 0 ;
do
{
tempCount = readTemp( devList, temperatures, devCount ) ;
for( int i = 0; i < tempCount; i++ )
{
printf( "Temp Act: %f\n", temperatures[i] ) ;
}
} while (tempCount > 0 ) ;
// Free resources after a temperature read fails
free( temperatures ) ;
// Free linked list memory
while( devlist != NULL )
{
// Save address of next before deleting current
struct ds18b20* next = devlist->next ;
// Free current devNode.
free( devlist ) ;
// get next
devlist = next ;
}
}
return 0 ;
}
Related
I am working on a program written in C that recursively walks a given directory in order to print out the Nth largest files and their sizes in bytes. I am using two arrays to account for the filesystem entry names and filesystem entry sizes respectively.
EDIT: I have updated my program to implement the suggestions shared in the comment section. My focus now is on correctly implementing a swap operation within my iSort function.
#include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>
#include <string.h>
// number of files to display size information for
const int N = 10;
// a struct used to hold filesystem entry names and corresponding sizes in bytes
struct info {
char name[1024];
int size;
};
/* A simple implementation of insertion sort that will operate upon
an array of info structs, sorting them by their member size in
ascending order */
void iSort(struct info *fs_info[], int size, int info_size)
{
int i, j, key;
for (i = 1; i < size; i++)
{
key = fs_info[i]->size;
j = i - 1;
while (j >= 0 && fs_info[j]->size > key)
{
printf("info_size: %d\n", info_size);
// TODO complete a swap operation
memmove(fs_info[j + 1], fs_info[j], info_size);
j = j - 1;
}
fs_info[j + 1]->size = key;
}
}
void get_size(char *path, struct info fs_info[N], int info_size)
{
static int items_added = 0;
static int max_size = 0;
struct stat st;
if (stat(path, &st) == 0)
{
if (items_added < N) // if array capacity will not be exceeded
{
strcpy(fs_info[items_added].name, path);
fs_info[items_added].size = st.st_size;
if (st.st_size > max_size)
max_size = st.st_size;
items_added++;
}
else
{
// do a comparison to determine where to insert
// sort first
iSort(&fs_info, 10, info_size); // this function call results in a seqfault
}
}
else
{
printf("Error getting stat for entry %s: %d\n", path, stat(path, &st));
}
}
void walk(const char *currDir, struct info fs_info[N], int info_size)
{
DIR *dir = opendir(currDir);
struct dirent *entry;
if (dir == NULL)
{
// directory could not be opened
return;
}
while ((entry = readdir(dir)) != NULL)
{
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
{
// if directory is current dir or parent dir
continue;
}
char path_to_entry[1024];
snprintf(path_to_entry, sizeof(path_to_entry), "%s/%s", currDir, entry->d_name);
// use path_to_entry to call stats on the entry
get_size(path_to_entry, fs_info, info_size);
if (entry->d_type == DT_DIR)
{
// recursively visit subdirectories
walk(path_to_entry, fs_info, info_size);
}
}
closedir(dir);
}
int main(int argc, char *argv[])
{
if (argc != 2)
{
printf("Usage: %s <target directory>\n", argv[0]);
}
const char *target_dir = argv[1];
struct info fs_entries[N];
const int info_size = sizeof(struct info);
for (int i = 0; i < N; i++)
{
strcpy(fs_entries[i].name, "");
fs_entries[i].size = 0;
}
printf("Finding %d largest files in: %s\n", N, target_dir);
walk(target_dir, fs_entries, info_size);
for (int i = 0; i < N; i++)
{
printf("%s : %d\n", fs_entries[i].name, fs_entries[i].size);
}
return 0;
}
Currently, the memmove() invocation in iSot() results in a EXC_BAD_ACCESS error, I am working on improving this function now. Any suggestions in the interim are appreciated. Thanks also to those who commented on this question earlier.
This is not so much an answer as it is an example of how one might code this with a bit less fiddling about with every bit/byte.
I don't run a flavour of UNIX, so this offering is untested and may contain typos and even bugs. I hope not.
#include <stdio.h> // From 'generic' to 'specific'
#include <string.h>
#include <sys/stat.h>
#include <dirent.h>
const int N = 10;
// Global array holding names and sizes
struct {
char name[ MAX_PATH ];
size_t size;
} biggies[ N ], wrk; // and a working buffer.
/* "Global" is bad for large projects.
* In this 'utility' program, global saves a LOT of typing/reading.
* Seek clarity, not conformity,
*
* "wrk" is used to buffer ALL paths encountered.
* Notice that each recursion is an EXTENSION of its parent.
* ONE working buffer to deal with.
*/
void walk() {
size_t len = strlen( wrk.name ); // The path so far...
DIR *dir;
if( ( dir = opendir( wrk.name ) ) == NULL )
return;
wrk.name[ len++ ] = '/'; // append a slash ahead of strcpy() below
struct dirent *entry;
while( ( entry = readdir( dir ) ) != NULL ) {
if( strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0 )
continue;
// Notice how each 'local' name is written to "the right spot" in one buffer
strcpy( wrk.name + len, entry->d_name );
if( entry->d_type == DT_DIR ) // directory, so recursion...
walk();
else {
struct stat st;
if( stat( wrk.name, &st ) != 0 ) {
fprintf( stderr, "Error stat'ing '%s'\n", wrk.name );
exit( EXIT_FAILURE );
}
// Add this info to working buffer.
wrk.size = st.st_size;
// Find where to 'insert' this (if it is larger than descending ordered list
for( int i = 0; i < N && biggies[i].size > wrk.size; i++ ) {} // loop
if( i < N ) {
// Slide smaller ones down (don't go out of bounds)
memmove( biggies[i + 1], biggies[i], (N-i-1) * sizeof biggies[0] );
// Copy this one in place.
memcpy( biggies[i], &wrk, sizeof biggies[0] );
}
}
}
closedir(dir);
}
int main( int argc, char *argv[]) {
char *target_dir = argv[1]; // This is okay, so far...
if( argc != 2 ) {
printf( "Usage: %s <target directory>\n", argv[0] );
puts( "Using current directory..." );
target_dir = ".";
}
strcpy( wrk.name, target_dir );
printf( "Finding %d largest files in: %s\n", N, wrk.name );
walk();
for( size_t i = 0; i < N && biggies[i].size != 0; i++ )
printf( "%s : %d\n", biggies[i].name, biggies[i].size);
return 0;
}
You don't need to pass the address of fs_info to iSort() function. fs_info is a pointer to first element of fs_entries array, which is enough to sort the array if the size of array is known. Also, you don't need to pass the size of element of array to iSort().
iSort() function implementation:
void iSort(struct info *fs_info, int size) {
for (int i = 1; i < size; ++i) {
int key = fs_info[i].size;
struct info x = fs_info[i];
int j = i - 1;
while (j >= 0 && fs_info[j].size > key) {
fs_info[j + 1] = fs_info[j];
j--;
}
fs_info[j + 1] = x;
}
}
Use memmove() in iSort():
void iSort (struct info *fs_info, int size) {
for (int i = 1; i < size; ++i) {
int key = fs_info[i].size;
struct info x = fs_info[i];
int j = i - 1;
while (j >= 0 && fs_info[j].size > key) {
j--;
}
if (j != i - 1) {
memmove (&fs_info[j + 2], &fs_info[j + 1], sizeof(*fs_info) * (i - j - 1));
}
memmove (&fs_info[j + 1], &x, sizeof(*fs_info));
}
}
Call iSort() function like this:
iSort(fs_info, N);
There is a lot of scope of improvement in your code, like, it would be good to have array of pointers to struct info instead of array of struct info, so that, during sort simply swapping the pointers required instead of swapping whole structure. Leaving it up to you to identify the improvements and implement them.
This question already has answers here:
C++ sector aligned read
(2 answers)
SetFilePointer without FILE_FLAG_NO_BUFFERING
(2 answers)
Closed 5 years ago.
First, here are a couple links i looked at...
Read and write hard disk sector directly and efficiently
Read specific sector on hard drive using C language on windows
I'm trying to do almost the same thing. What I'm having trouble with is reading the device multiple times so I can store the read bytes from a DEVICE (USB) to writing them into a FILE.
This is what I am trying to do...
declare variables
initialize variables
SetFilePointer()
ReadFile()
output the read bytes to a file
use ReadFile() to get more bytes
output the read bytes to same file again
repeat 6 and 7 (actually just repeating 4 and 5)
This doesn't seem to be working. I would like to read x amount of bytes and store those values into a file then read more and store those values in the same file as last time. I would like it to repeat the process until it reads to the end of the device. I would like this program to work on any size of device. If I can put it in a loop then I can read and write infinite sized devices.
This is a how to read/write so I would like to do this in reverse as well. Read the file for values then write them to the device.
I'm using a 128MB USB. It contains 131858432 bytes. If any more info is needed then I will post it if I have it.
My code:
#include <windows.h>
#include <stdio.h>
int main(int argc, char ** argv)
{
BYTE sector[0x400] = {0};
DWORD bytesRead;
HANDLE device = NULL;
int numSector = 1;
int maxRead = 1;
FILE *readChar = fopen("G:\\usb_128MB_Dec2.txt", "w+");
device = CreateFile("\\\\.\\L:", // Drive to open
GENERIC_READ|GENERIC_WRITE, // Access mode
FILE_SHARE_READ|FILE_SHARE_WRITE, // Share Mode
NULL, // Security Descriptor
OPEN_EXISTING, // How to create
0, // File attributes
NULL); // Handle to template
if(device == INVALID_HANDLE_VALUE)
{
printf("CreateFile: %u\n", GetLastError());
system("pause");
return 1;
}
// set the file pointer for first time
SetFilePointer(device, numSector, NULL, FILE_BEGIN);
// Edit 1. Comment 2.
if(GetLastError() != NO_ERROR)
{
printf("GetLastError: %d\n", GetLastError());
goto end; // end: is before closing files or handles at end of main()
}
// read device for maxRead number of bytes and store the reading into a file
ReadFile(device, sector, maxRead, &bytesRead, NULL);
fprintf(readChar, "%d\n", sector[0]);
// This part of code does not act like expected
SetFilePointer(device, numSector, NULL, FILE_CURRENT);
if(!ReadFile(device, sector, maxRead, &bytesRead, NULL))
printf("err\n");
else
fprintf(readChar, "%d", sector[0]);
end: // Edit 1. Comment 2.
CloseHandle(device);
fclose(readChar);
system("pause");
return 0;
}
Screen ouput:
GetLastError: 87
File output:
Nothing is in the file.
The file should contain an 8 bit decimal value instead of nothing or a 0.
Edit 1:
87 means INVALID PARAMETER.
Your reads have to be sector aligned so you can't seek to offset 1,
but only 0, sector_size, 2sector_size, ..., nsector_size, Your reads
have also be in multiplies of sector size, and your memory buffer has
to be aligned to sector_size.
Sector size could be retrieved with GetDiskFreeSpace and aligned
memory can be obtained with VirtualAlloc.
Maybe you should check also FSCTL_LOCK_VOLUME and
FSCTL_DISMOUNT_VOLUME.
Here's the other code that works for one time reading of the device
#include <windows.h>
#include <stdio.h>
int main(int argc, char ** argv)
{
BYTE sector[0x200] = {0};
DWORD bytesRead;
HANDLE device = NULL;
int numSector = 1;
int maxRead = 0x200;
long long int i;
FILE *readChar = fopen("G:\\usb_128MB_Dec.txt", "w+");
device = CreateFile("\\\\.\\L:", // Drive to open
GENERIC_READ|GENERIC_WRITE, // Access mode
FILE_SHARE_READ|FILE_SHARE_WRITE, // Share Mode
NULL, // Security Descriptor
OPEN_EXISTING, // How to create
0, // File attributes
NULL); // Handle to template
if(device == INVALID_HANDLE_VALUE)
{
printf("CreateFile: %u\n", GetLastError());
system("pause");
return 1;
}
SetFilePointer(device, numSector, NULL, FILE_BEGIN);
if (!ReadFile(device, sector, maxRead, &bytesRead, NULL))
{
printf("ReadFile: %u\n", GetLastError());
goto end;
}
else
{
printf("Success!\n");
}
if(readChar == NULL)
{
printf("Did not open file. Exit 2.");
goto end;
}
for(i = 0; i < maxRead - 1; i++)
{
fprintf(readChar, "%d\n", sector[i]);
}
fprintf(readChar, "%d", sector[i]); // so the previous loop wont add \n to the last read wanted
end:
CloseHandle(device);
fclose(readChar);
system("pause");
return 0;
}
File contents:
235
88
...
Each byte read is stored in decimal value on a new line.
So it may be better understood what I'm trying to do, here it is in code:
// What I want to do..
// This part works
SetFilePointer(device, numSector, NULL, FILE_BEGIN);
ReadFile(device, sector, maxRead, &bytesRead, NULL);
for(i = 0; i < size_of_device - 0x200; i += 512)
{
for(j = 0; j < maxRead; j++)
{
fprintf(readChar, "%d\n", sector[j]);
}
// stops working
SetFilePointer(device, numSector, NULL, FILE_CURRENT);
ReadFile(device, sector, maxRead, &bytesRead, NULL);
}
for(j = 0; j < maxRead - 1; j++)
{
fprintf(readChar, "%d\n", sector[j]);
}
fprintf(readChar, "%d", sector[j]);
// .. end of what i want to do
Edit 2: Working on reading multiple times now.
#include <windows.h>
#include <stdio.h>
int main(int argc, char ** argv)
{
BYTE sector[0x200] = {0};
DWORD bytesRead;
HANDLE device = NULL;
//int numSector = 512; // original value was 1 not 512 but variable is not needed
int maxRead = 512;
int i, j, k = 0, l; // loop variables
FILE *readChar = fopen("G:\\wii u hdd image\\usb_128MB_Dec3.txt", "w+");
if(readChar == NULL)
{
printf("Error creating file.\n");
goto end;
}
device = CreateFile("\\\\.\\L:", // Drive to open
GENERIC_READ|GENERIC_WRITE, // Access mode
FILE_SHARE_READ|FILE_SHARE_WRITE, // Share Mode
NULL, // Security Descriptor
OPEN_EXISTING, // How to create
0, // File attributes
NULL); // Handle to template
// If device does not contain a handle value
if(device == INVALID_HANDLE_VALUE)
{
printf("Error. GetLastError: %u\n", GetLastError());
goto end;
}
for(i = 0; i < maxRead*503; i++) // maxRead * 503 = 257536
{
// If ReadFile() fails it will exit the program without adding a '\n' to the readChar file.
if(!ReadFile(device, sector, maxRead, &bytesRead, NULL))
{
printf("Error of ReadFile(). GetLastError(): %u\n", GetLastError());
goto end;
}
// If this is the first time through the loop then '\n' won't be added to the readChar file.
if(i != 0)
{
fprintf(readChar, "\n");
system("cls");
printf("%.2f%%\n", (i / 257536));
}
// Runs for 511 times. Then prints the 512th decimal value after the loop.
for(j = 0; j < maxRead - 1; j++)
{
fprintf(readChar, "%d\n", sector[j]);
}
fprintf(readChar, "%d", sector[j]);
}
end:
CloseHandle(device);
fclose(readChar);
system("pause");
return 0;
}
Edit 3:
This question has not been answered in another post.
87 means INVALID PARAMETER.
Your reads have to be sector aligned so you can't seek to offset 1, but only 0, sector_size, 2*sector_size, ..., n*sector_size, Your reads have also be in multiplies of sector size, and your memory buffer has to be aligned to sector_size.
Sector size could be retrieved with GetDiskFreeSpace and aligned memory can be obtained with VirtualAlloc.
Maybe you should check also FSCTL_LOCK_VOLUME and FSCTL_DISMOUNT_VOLUME.
Edit
Because direct reading (or writing) isn't buffered, if you want to operate on smaller sizes then sector size, you have to handle buffering yourself.
This code implements reading single bytes from arbitrary places using one sector buffering scheme. Disclaimer: Needs through testing. Beware of possible bugs.
#include <windows.h>
typedef __int64 int64;
struct MyDevice
{
HANDLE handle;
DWORD sector_size;
int64 current_sector_position;
void* sector_buffer;
};
BOOL OpenMyDevice( struct MyDevice* device, const char* name )
{
device->current_sector_position = -1;
device->handle = INVALID_HANDLE_VALUE;
device->sector_buffer = 0;
{
DWORD bytes_per_sector, unused1, unused2, unused3;
// GetDiskFreeSpace doesn't like "\\.\".
const char* name2 = name;
if ( strncmp( name, "\\\\.\\", 4 ) == 0 )
name2 = name + 4;
// For comaptibility reasons we will get logical sector size here.
// For Vista+ it would be better to use DeviceIoControl with IOCTL_STORAGE_QUERY_PROPERTY.
if ( !GetDiskFreeSpace( name2, &unused1, &bytes_per_sector, &unused2, &unused3 ) )
return FALSE;
device->sector_size = bytes_per_sector;
}
device->sector_buffer = VirtualAlloc( 0, device->sector_size, MEM_COMMIT, PAGE_READWRITE );
if ( !device->sector_buffer )
return FALSE;
device->handle = CreateFile(
name,
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
0,
OPEN_EXISTING,
FILE_FLAG_NO_BUFFERING, // Can be zero, but in most cases it assumed by Windows.
0 );
if ( device->handle == INVALID_HANDLE_VALUE )
{
VirtualFree( device->sector_buffer, 0, MEM_RELEASE );
device->sector_buffer = 0;
return FALSE;
}
return TRUE;
}
// Call only when OpenDevice was successful.
void CloseMyDevice( struct MyDevice* device )
{
CloseHandle( device->handle );
device->handle = INVALID_HANDLE_VALUE;
VirtualFree( device->sector_buffer, 0, MEM_RELEASE );
device->sector_buffer = 0;
}
BOOL LoadMyDeviceSector( struct MyDevice* device, int64 byte_offset )
{
// Calculate sector position.
int64 sector_position = ( byte_offset / device->sector_size ) * device->sector_size;
if ( sector_position == device->current_sector_position )
// No need to load, it is in buffer
return TRUE;
{
LARGE_INTEGER li;
li.QuadPart = sector_position;
if ( SetFilePointerEx( device->handle, li, 0, FILE_BEGIN ) )
{
DWORD read;
if ( ReadFile( device->handle, device->sector_buffer, device->sector_size, &read, 0 ) )
{
if ( read == device->sector_size )
{
device->current_sector_position = sector_position;
return TRUE;
}
// else Hmmm. Maybe this is read beyond EOF?
}
}
}
// Cant guarantee that device->sector_buffer contains valid data.
device->current_sector_position = -1;
return FALSE;
}
BOOL LoadNextMyDeviceSector( struct MyDevice* device )
{
DWORD read;
device->current_sector_position = -1;
if ( ReadFile( device->handle, device->sector_buffer, device->sector_size, &read, 0 ) )
{
if ( read == device->sector_size )
return TRUE;
// else Hmmm. Maybe this is read beyond EOF?
}
return FALSE;
}
BOOL SetMyDevicePos( struct MyDevice* device, int64 sector_aligned_byte_offset )
{
LARGE_INTEGER li;
li.QuadPart = sector_aligned_byte_offset;
device->current_sector_position = -1;
return SetFilePointerEx( device->handle, li, 0, FILE_BEGIN );
}
int GetMyDeviceByte( struct MyDevice* device, int64 offset )
{
if ( LoadMyDeviceSector( device, offset ) )
{
// Calculate position in sector buffer.
int64 offset_in_sector = offset - ( offset / device->sector_size ) * device->sector_size;
return ((unsigned char*)( device->sector_buffer ))[ offset_in_sector ];
}
return -1;
}
BOOL GetMyDeviceBytes( struct MyDevice* device, int64 byte_offset, void* dst_buffer, int64 count )
{
char* dst = (char*) dst_buffer;
int64 sector_position = ( byte_offset / device->sector_size ) * device->sector_size;
int64 start = byte_offset - sector_position; // First loop pass can be unaligned!
while ( count > 0 )
{
if ( LoadMyDeviceSector( device, byte_offset ) )
{
int64 chunk = device->sector_size - start;
if ( chunk > count )
chunk = count;
// chunk <= sector_size so conversion to int isn't harmful.
memcpy( dst, ((char*)(device->sector_buffer)) + start, (int)chunk );
dst += chunk;
byte_offset += chunk;
count -= chunk;
start = 0; // From now loop would be always sector_size aligned.
}
else
return FALSE;
}
return TRUE;
}
int main( int argc, char* argv[] )
{
struct MyDevice device = { INVALID_HANDLE_VALUE };
if ( OpenMyDevice( &device, "\\\\.\\K:" ) )
{
// #1: Get one byte from device.
{
int byte = GetMyDeviceByte( &device, 11111 );
if ( byte >= 0 )
{
}
}
// #2: Get multiple bytes from device.
{
char buff[1000];
if ( GetMyDeviceBytes( &device, 111111, buff, 1000 ) )
{
}
}
// #3: Scan 100 sectors beginning from sector 111 for byte 155.
{
if ( SetMyDevicePos( &device, 111*device.sector_size ) )
{
int i, j;
for ( i = 0 ; i < 100 ; ++i )
{
if ( !LoadNextMyDeviceSector( &device ) )
break;
for ( j = 0 ; j < (int)device.sector_size ; ++j )
{
int byte = ((unsigned char*)( device.sector_buffer ))[ j ];
if ( byte == 155 )
{
// FOUND!
}
}
}
}
}
CloseMyDevice( &device );
}
}
GetMyDeviceByte and GetMyDeviceBytes are rather random seek oriented for small byte tranfers. If someone needs to trasfer large amounts of data in sequential order it is a lot faster to SetMyDevicePos and LoadNextMyDeviceSector like #3 in main.
I would prefer to write this code in C++.
I have a strange thing in my code execution
every thing goes ok except the value of player_count. When i read the data again from file, it still = 0 although name and email are updated correctly ..!!
why player_count still equal 0 ??????
here is the code :
#define MAX_DATA 128
#define STRLEN 101
#define FILENAME "C:\\Users\\ahmed\\Desktop\\C codes\\new_game\\data_base.dat"
typedef struct
{
char name[STRLEN] ;
char email[STRLEN] ;
int score ;
int id ;
int Set ;
} player_t ;
typedef struct
{
player_t player[MAX_DATA] ;
int player_count ;
}DataBase ;
typedef struct
{
DataBase db ;
FILE *filename ;
}Connection ;
void Store_Player_Database( int score )
{
Connection *conn = Creat_Connection(FILENAME );
player_t *player = conn->db.player ;
Read_Database(conn) ;
int player_num = conn->db.player_count ;
printf("Your name : ") ;
get_str(player[player_num].name , STRLEN) ;
printf("Your e-mail : ") ;
get_str(player[player_num].email , STRLEN) ;
player[player_num].Set = 1 ;
player[player_num].score = score ;
conn->db.player_count++ ;
printf("count here = %d\n",conn->db.player_count) ;
Write_Database(conn) ;
}
Connection *Creat_Connection(const char *filename )
{
Connection *conn = calloc(1,sizeof(Connection)) ;
//check_mem(conn) ;
int i = 0;
for( i = 0 ; i< MAX_DATA ; i++)
conn->db.player[i].id = i+1 ;
/// for update or read
conn->filename = fopen(filename , "r+") ;
//check(db->filename , "File open failed !") ;
return conn ;
}
int Read_Database(Connection *conn)
{
int rc ;
if(conn)
{
if(conn->filename)
{
DataBase *db = &conn->db ;
rc=fread(db,sizeof(DataBase),1,conn->filename); // load database from file .
printf("count = %d\n" , db->player_count) ;printf("%s %s \n" , db->player[0].name , db->player[0].email);
/* if (rc != 1)
{
printf("Error load database from file\n") ;
return -1 ;
}*/
}
}
return 1 ;
}
int Write_Database(Connection *conn)
{
int rc ;
if(conn)
{
if(conn->filename)
{
rewind(conn->filename) ;
DataBase *db = &conn->db ;printf("%s %s count = %d \n" , db->player[0].name , db->player[0].email , conn->db.player_count);
rc = fwrite(db,sizeof(DataBase),1,conn->filename) ;
if (rc != 1)
{
printf("Error load database from file\n") ;
return -1 ;
}
fflush(conn->filename) ;
}
}
return 1 ;
}
/*****************************/
int main(void)
{
int score = 5 ;
/* any code here */
Store_Player_Database(score) ;
Store_Player_Database(score +1) ; // at that call i get name and mail correct but player_count still zero ??? why?!
return 0 ;
}
When i try this program in linux it runs correctly
then i find the bug finally .
In windows fread should open in binary mode like that :
conn->filename = fopen(filename , "rb+") ; // use rb+ instead of r+ to open it in binary mode
I'm trying to represent a battle cards game :
typedef struct list_of_cards* p_loc;
typedef struct game game_s;
struct list_of_cards {
char card[4]; // card is represented like 10C or KS
p_loc ncards; // next card
};
struct game {
p_loc loc; // list of card
p_loc lcard; // last card
};
p_loc init_cards(p_loc loc, int n) {
loc = malloc(sizeof(struct list_of_cards));
scanf("%s", loc->card);
fprintf(stderr, "%s\n", loc->card);
if (n == 1)
return loc;
init_cards(loc->ncards, n-1);
}
int main()
{
int n; // the number of cards for player 1
scanf("%d", &n);
game_s player1;// the n cards of player 1
player1.lcard = init_cards(player1.loc, n);
fprintf(stderr, "%s %s\n", player1.loc->card, player1.lcard->card);
}
The first fprintf give me what I want (like AD KC QC) but the second displays
�(�� QC
.
So my question is, why �(�� is player1.loc->card value.
Thanks
The reason why player1.loc->card is some weird string is due to the fact it is uninitialized and the memory contains random characters which are not always printable in ascii.
You need to modify your loc in your init to do so you can pass your loc as a pointer to the first element of your list,but the best way is probably to initialize you whole player struct in one function.
p_loc init_cards(p_loc* loc, int n) {
*loc = malloc(sizeof(struct list_of_cards));
scanf("%s", (*loc)->card);
fprintf(stderr, "%s\n", (*loc)->card);
if (n == 1)
{
(*loc)->ncards = NULL;
return *loc;
}
return init_cards(&((*loc)->ncards), n-1);
}
int main()
{
int n; // the number of cards for player 1
scanf("%d", &n);
game_s player1;// the n cards of player 1
player1.lcard = init_cards(&player1.loc, n);
fprintf(stderr, "%s %s\n", player1.loc->card, player1.lcard->card);
}
You have to return the allocate card and assign it back to the member p_loc of its predecessor.Further you need an output parameter for the last card of the deck:
p_loc init_cards( int n, p_loc *lastCard )
// ^ output parameter
{
if ( n <= 0 ) // terminate recursion
return NULL; // successor of last card is NULL
p_loc loc = malloc(sizeof(struct list_of_cards)); // allocate new card
if ( loc != NULL )
{
scanf("%s", loc->card);
fprintf(stderr, "%s\n", loc->card);
*lastCard = loc; // new card is last card
loc->ncards = init_cards( n-1 ); // next card is successor of act card
}
return loc; // return new card
}
int main()
{
int n; // the number of cards for player 1
scanf("%d", &n);
game_s player1;// the n cards of player 1
player1.lcard = NULL;
player1.loc = init_cards( n, &player1.lcard );
fprintf(stderr, "%s %s\n", player1.loc->card, player1.lcard->card);
}
But you can easily do that without recursion:
p_loc init_cards( int n, p_loc *lastCard )
{
*lastCard = NULL;
p_loc head;
p_loc *act = &head; // init pointer to first card
for ( int i = 0; i < n; i ++ )
{
*act = malloc( sizeof(struct list_of_cards) ); // allocate next card right to target
if ( *act == NULL )
break;
scanf( "%s", (*act)->card );
fprintf( stderr, "%s\n", (*act)->card );
*lastCard = *act; // last card is act card
act = &((*act)->ncards); // set pointer to member ncards of last card
}
*act = NULL; // successor of last card is NULL
return head; // return first card
}
I created a function in C called 'remover' that is used to remove a struct of the array 'lista'. This function resizes 'lista'. The problem is that I tried to print the elements of 'lista' but it prints strange things.
When I don't free 'lista_aux' the program runs normally. Why does it happen?
typedef struct localidade{
char nome[31];
float local[3];
}Localidade;
Localidade** remover(Localidade** lista, char end_remover[], int posicao){
int i, j;
int pos_remover;
char nome_aux[31];
Localidade** lista_aux;
lista_aux = (Localidade**) malloc((posicao) * sizeof(Localidade*));
if( lista_aux == NULL){
printf("Erro na alocacao de memoria!\n");
exit(-1);
}
for( i = 0; i < posicao; i++){
lista_aux[i] = (Localidade*) malloc(sizeof(Localidade));
if( lista_aux[i] == NULL){
printf("Erro na alocacao de memoria!\n");
exit(-1);
}
}
for( i = 0; end_remover[i]; i++ ){
end_remover[i] = toupper( end_remover[i] );
}
for( i = 1; i < posicao; i++){
strcpy( nome_aux, lista[i]->nome);
for( j = 0; nome_aux[j]; j++){
nome_aux[j] = toupper( nome_aux[j] );
}
if( !(strcmp( end_remover, nome_aux)) ){
pos_remover = i;
break;
}
else if( i == posicao ){
printf("Endereco nao cadastrado.\n");
}
}
for( i = 0; i < posicao; i++){
if( i < pos_remover ){
lista_aux[i] = lista[i];
}
else{
lista_aux[i] = lista[i + 1];
}
//printf("***%s\n", lista_aux[i]->nome);
}
lista = (Localidade**) realloc( lista, (posicao)*sizeof(Localidade*));
lista = lista_aux;
//printf("*****%s\n", lista[1]->nome);
/*for( i = 0; i < posicao; i++ ){
printf("***%s\n", lista[i]->nome);
}
for( i = 0; i < posicao; i++ ){
printf("*****%s\n", lista_aux[i]->nome);
}*/
/*for( i = 0; i < posicao; i++){
free( lista_aux[i] );
}
free( lista_aux );*/
return lista;
}
If you free lista_aux, your code will be returning an invalid (freed) pointer to the caller, because of this line:
lista = lista_aux;
Your code has other issues (depending on how you call it, you may have a memory leak, for starters) and I'd suggest you review your algorithm for removing an entry from "lista". One suggestion would be to have a known size for the list (or a NULL-terminated list), and using memmove() instead of manually copying things around.
Your problem (well, one of them) appears to lie here:
lista = (Localidade**) realloc( lista, (posicao)*sizeof(Localidade*));
lista = lista_aux;
This does not copy everything at lista_aux to lista, it just changes the lista pointer to point to the lista_aux data (overwriting the memory you just reallocated).
If you then free that data, your pointer is left pointing at freed memory.
You don't need to copy the memory if you've created a brand new array, you should just free the original and return the copy you made:
free (lista);
lista = lista_aux;
There's a better way to do what you're attempting by doing it in-place. It's a simpler form which simply uses a source and destination index to remove unwanted elements.
Normally, source and destination will be identical so that the array doesn't change but, when a removable item is found, the source is incremented without the destination (after freeing the data for the unwanted element of course).
I've also changed it so it gives you back the new size as well. Here's a complete program, test suite and all:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct localidade {
char nome[31];
float local[3];
} Localidade;
static void dump ( int sz, Localidade **lista) {
int i;
printf ("Size = %d\n", sz);
for (i = 0; i < sz; i++)
printf (" [%s]\n", lista[i]->nome);
}
Localidade **remover (
Localidade **lista,
char end_remover[],
int posicao,
int *new_posicao)
{
int sidx, didx;
// Maintain separate source and destination indexes.
sidx = didx = 0;
while (sidx < posicao) {
// If need to remove, just increment source after freeing.
if (stricmp (end_remover, lista[sidx]->nome) == 0) {
free (lista[sidx]);
lista[sidx++] = NULL;
continue;
}
// Otherwise transfer and increment both indexes.
lista[didx++] = lista[sidx++];
}
*new_posicao = didx;
if (sidx != didx)
lista = realloc (lista, (*new_posicao) * sizeof(Localidade*));
return lista;
}
int main (void) {
int sz;
Localidade **x = malloc (3 * sizeof(Localidade*));
x[0] = malloc (sizeof(Localidade));
x[1] = malloc (sizeof(Localidade));
x[2] = malloc (sizeof(Localidade));
sz = 3;
strcpy (x[0]->nome, "PaxDiablo");
strcpy (x[1]->nome, "Adriano");
strcpy (x[2]->nome, "Kate Bush");
dump (sz, x);
x = remover (x, "AdRiAnO", sz, &sz);
dump (sz, x);
return 0;
}
which outputs, as expected:
Size = 3
[PaxDiablo]
[Adriano]
[Kate Bush]
Size = 2
[PaxDiablo]
[Kate Bush]