I'm have a bit of a problem with C and XML.
Basically, the code I'm using is:
#include <stdio.h>
#include <curl/curl.h>
#include <libxml/tree.h>
#include <string.h>
#include <stdlib.h>
#define WEBPAGE_URL "http://gdata.youtube.com/feeds/api/videos/mKxLmdBzS10"
typedef struct {
char *contents;
int size;
} data;
/*Curl uses this function to write the contents of a webpage to a file/stdout*/
size_t write_data( void *ptr, size_t size, size_t nmeb, void *stream)
{
data *curl_output = (data *)stream;
int curl_output_size = size * nmeb;
curl_output->contents = (char *) realloc(curl_output->contents, curl_output->size + curl_output_size + 1);
if (curl_output->contents) {
memcpy(curl_output->contents, ptr, curl_output_size); /*Copying the contents*/
curl_output->size += curl_output_size;
curl_output->contents[curl_output->size] = 0;
return curl_output->size;
}
}
int main()
{
data webpage;
webpage.contents = malloc(1);
webpage.size = 1;
CURL *handle = curl_easy_init();
curl_easy_setopt(handle,CURLOPT_URL,WEBPAGE_URL); /*Using the http protocol*/
curl_easy_setopt(handle,CURLOPT_WRITEFUNCTION, write_data); /*Setting up the function meant to copy data*/
curl_easy_setopt(handle,CURLOPT_WRITEDATA, &webpage); /*The data pointer to copy the data*/
curl_easy_perform(handle);
curl_easy_cleanup(handle);
printf("Contents: %s",webpage.contents);
int i;
}
I'm mean't to be getting this XML back: http://gdata.youtube.com/feeds/api/videos/mKxLmdBzS10.
But currently, I only get arbitrary amounts back, sometimes a third sometimes a half and other times just a quater.
Anybody know what I'm doing wrong?
The problem is in your write_data function.
This line copies the new data to the start of your array, rather than the current end.
memcpy(curl_output->contents, ptr, curl_output_size); /*Copying the contents*/
You need to offset your pointer:
memcpy(curl_output->contents + curl_output->size, ptr, curl_output_size); /* Copying the contents */
Additionally, your return value is bad -- it should be return(curl_output_size); to indicate success, via the number of bytes actually processed on the call -- and below the bracket, return(0); to show an error.
You might also find it clarifies things if instead of having curl_output->size and curl_output_size you pick more distinct names...perhaps curl_output->len?
Related
I am attempting to write a program which will store credential information in an array of structures and then print that information out into a file (this is for learning purposes only, don't worry). To do this, I create an array of structures and then raster through that array to assign the pertinent information to each field. This proceeds without issue. I then attempt to raster through the array again to write each structure's fields to a file whereupon the program crashes after the first write (ie only one structure's worth of content is successfully written to the output file).
I created the following simplified / stripped down variant of my program which reproduces the error. I believe the problem lies within the set_hash_entry function as the error only manifested after that function was re-introduced into my stripped down code in place of a hard coded test value.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "openssl/sha.h"
#include <time.h>
#include <math.h>
struct password_struct {
char password[17];
char hash[65];
float entropy;
};
struct password_struct* allocate_heap_memory(int num_passwords);
void orchestrate_value_setting(int num_passwords, struct password_struct* user_password_structs);
void orchestrate_file_output(int num_passwords, struct password_struct* user_password_structs);
void write_results_to_disk(char file_name[], struct password_struct* user_password_structs);
void set_hash_entry(struct password_struct* user_password_structs);
int main(void) {
int num_passwords = 2;
struct password_struct* user_password_structs = allocate_heap_memory(num_passwords);
struct password_struct* allocated_memory_start_ptr = user_password_structs;
orchestrate_value_setting(num_passwords, user_password_structs);
user_password_structs = allocated_memory_start_ptr; // Resetting pointer to allow cycling back through all structures for appending data to output file
orchestrate_file_output(num_passwords, user_password_structs);
free(allocated_memory_start_ptr);
}
struct password_struct* allocate_heap_memory(int num_passwords) {
struct password_struct* user_password_structs = malloc(num_passwords * sizeof(struct password_struct));
if (!user_password_structs) {
printf("Malloc failed, exiting\n");
exit(0);
}
return user_password_structs;
}
void set_hash_entry(struct password_struct* user_password_structs){
int pass_entry_length = strlen(user_password_structs->password);
SHA256_CTX context;
unsigned char generated_hash[65]; //sha256 standard digest length + 1;
SHA256_Init(&context);
SHA256_Update(&context, (unsigned char *)user_password_structs->password, pass_entry_length);
SHA256_Final(generated_hash, &context);
char* hash_ptr = &user_password_structs->hash[0];
int i;
for (i=0; i < (64); i++) {
snprintf(&hash_ptr[i*2], (64), "%02x", generated_hash[i]); // Need to convert from hex to char representation
}
user_password_structs->hash[64] = '\0';
printf("%s\n", user_password_structs->hash);
}
void orchestrate_value_setting(int num_passwords, struct password_struct* user_password_structs) {
char pw1[10] = "test";
char pw2[10] = "test2";
float entropy1 = 5.0;
float entropy2 = 10.0;
strcpy(user_password_structs->password, pw1);
set_hash_entry(user_password_structs);
user_password_structs->entropy = entropy1;
user_password_structs++;
strcpy(user_password_structs->password, pw2);
set_hash_entry(user_password_structs);
user_password_structs->entropy = entropy2;
user_password_structs++;
}
void orchestrate_file_output(int num_passwords, struct password_struct* user_password_structs) {
printf("Writing data to disk...\n");
char file_name[20] = "name";
int i;
for (i = 0; i < num_passwords; i++) {
write_results_to_disk(file_name, user_password_structs);
user_password_structs++;
}
}
void write_results_to_disk(char file_name[], struct password_struct* user_password_structs) {
FILE *file_pointer = fopen(file_name, "a");
if (file_pointer == NULL) {
printf("Error: Failed to open file\n");
exit(1);
}
fprintf(file_pointer, "%s:%s:%f\n", user_password_structs->password, user_password_structs->hash, user_password_structs->entropy);
fclose(file_pointer);
}
After running this program, the following output is produced:
9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08
60303ae22b998861bce3b28f33eec1be758a213c86c93c076dbe9f558c11c752
Writing data to disk...
*** Error in `./diagnostic': free(): invalid next size (normal): 0x0804b0c0 ***
Aborted (core dumped)
I naively assumed this was an overflow issue related to my
snprintf(&hash_ptr[i*2], (64), "%02x", generated_hash[i]);
operation, but increasing the size of the hash buffer in the struct does not seem to help. Any help would be greatly appreciated!
I compiled as follows: gcc -o diagnostic -g diagnostic.c -lcrypto -lm
char hash[65];
Okay, hash has room for 65 characters.
char* hash_ptr = &user_password_structs->hash[0];
So, hash_ptr points to hash, so it points to room for 65 characters.
for (i=0; i < (64); i++) {
snprintf(&hash_ptr[i*2], (64), "%02x", generated_hash[i]); // Need to convert from hex to char representation
}
When i is 60, i*2 is 120. So you're trying to write to the 120th position of a buffer with room for 65 characters.
Change that (64) to 32 in the loop or change hash[65] to a bigger buffer.
Using valgrind found this immediately. You should learn to use some too that detects buffer overflows, use after free, double frees, and similar problems.
There is a function that asks the user which text file to open, opens it and then passes the array of structures that was passed into the function along with the file pointer to another function that reads in data from file into the structure. The array structure for testing purposes only has the value char name[25];. I can assign one line at a time from the file to the same structure index all I want but when I try an increment it I get a segmentation fault no matter what approach I've taken.
The structure has been type defined as well.
The code is:
void oSesame(char usrTxt[], int len, FILE * pFile, Country * p)
{
pFile = fopen(usrTxt, "rw");
if(pFile != NULL)
{
readIn(pFile, &p);
}
else
{
printf("Error opening %s , check your spelling and try again.\n", usrTxt);
}
}
void readIn(FILE * pfile, Country ** p)
{
int count = 0;
int i = 0;
for(i = 0; i<3; i++)
{
fgets((*p[i]).cntName, MAX_COUNTRY_LENGTH, pfile);
}
fclose(pfile);
}
The header file:
//Header.h
#define COUNTRY_MAX 10
#define MAX_COUNTRY_LENGTH 25
#define MAX_CAPITAL_LENGTH 25
typedef struct country
{
char cntName[MAX_COUNTRY_LENGTH];
char capName[MAX_CAPITAL_LENGTH];
double population;
}Country;
int ask(char * usrTxt);
void oSesame(char usrTxt[], int len, FILE * pFile, Country * p);
void readIn(FILE * pFile, Country ** p);
The main code:
#include <stdio.h> //for testing within main
#include <string.h> //for testing within main
#include "headers.h"
int main()
{
int len;
FILE * fileP;
char UI[25];
Country c[10];
Country * ptr;
ptr = c;
len = ask(UI);
oSesame(UI, len, fileP, ptr);
return 0;
}
You are passing Country** for some reason and then handling it as *p[index]. This is wrong. You could use (*p)[index] but the correct way is not to take a reference to the Country* in the first place.
The way you're doing it means you have a pointer to pointer to Country. When you index that you are moving to next pointer to pointer, which is not the same as moving to the next pointer. Undefined behaviour happens.
/* This Program generates a file with a pseudo-random number of st_record_t structures. The file is passed by command line arguments. The program must by executed, in UNIX, this way: ./file_gen -path <path> */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include "types.h"
#define MSG_INVALID_INPUT "Your input was not valid"
#define CMD_FLAG_PATH_POSITION 1
#define CMD_ARG_PATH_POSITION 2
#define CMD_FLAG_PATH "-path"
#define SDM_MAX 10000.0
status_t validate_arguments (int argc, char * argv []);
int main (int argc, char * argv [])
{
FILE * fi;
size_t i;
st_record_t aux_struct, aux2_struct;
int size;
if ((validate_arguments(argc, argv))!= OK)
{
fprintf(stderr, "%s\n", MSG_INVALID_INPUT);
return EXIT_FAILURE;
}
if((fi = fopen(argv[CMD_ARG_PATH_POSITION], "wb")) == NULL)
return EXIT_FAILURE;
srand(time(NULL));
for (i=0; i<(size=100); i++)
{
aux_struct.SDM = (((float)rand()/(float)(RAND_MAX)) * SDM_MAX); /*pseudo-random real number between 0 and SDM_MAX*/
(aux_struct.ID) = i;
(aux_struct.coordinates)->latitude.deg = rand()%180;
(aux_struct.coordinates)->latitude.min = rand()%60;
(aux_struct.coordinates)->latitude.sec = rand()%60;
(aux_struct.coordinates)->longitude.deg = rand()%180;
(aux_struct.coordinates)->longitude.min = rand()%60;
(aux_struct.coordinates)->longitude.sec = rand()%60;
if((fwrite (&aux_struct, sizeof(st_record_t), 1, fi))!=1)
return ERROR_WRITING_FILE;
}
if(fclose(fi) == EOF)
return EXIT_FAILURE
return EXIT_SUCCESS;
}
The problem is with the (aux_struct.coordinates)->latitude.deg = rand()%180 lines. If instead of using a random number I select one, this won't happen
The st_record_t struct is defined this way:
typedef struct {
unsigned char deg, min, sec;
}angle_t;
typedef struct {
angle_t latitude, longitude;
}st_coord_t;
typedef struct {
float SDM;
size_t ID;
st_coord_t * coordinates;
}st_record_t;
The segmentation fault has nothing to do with random number, it's because you never allocate memory for aux_struct.coordinates.
To fix the problem, use something like:
aux_struct.coordinates = malloc(sizeof(st_coord_t));
Remember to free the memory when it's not used any more.
In addition to the issue of the missing initialization of the "coordinates" member, it should be pointed out that the fwrite() will not do what you want. It will just write the contents of the st_record_t. The value of the pointer "coordinates" has no meaning outside the process that is doing the writing and the data in the st_coord_t structure it points to will not get written at all.
You might want to look at something like hdf5 to write complex binary data structures to file in a portable way.
You have
typedef struct {
float SDM;
size_t ID;
st_coord_t * coordinates;
}st_record_t;
As you can see,coordinates is a pointer of type st_coord_t. You need to allocate memory for it using malloc:
aux_struct.coordinates=malloc(sizeof(st_coord_t));
And you need to free the allocated memory after its use using:
free(aux_struct.coordinates);
Note that you must allocate memory for coordinates in aux2_struct if you want to use it and later free it after its use.
I'm fully prepared to be told that I'm doing something stupid/wrong; this is what I expect.
I'm getting a feel for structures and coming a cropper when it comes to accessing the fields from the pointers. Code to follow.
matrix.h:
#ifndef MATRIX_H_INCLUDED
#define MATRIX_H_INCLUDED
#include <stdlib.h>
typedef struct
{
size_t size;
int* vector;
} vector_t;
#endif // MATRIX_H_INCLUDED
main.c:
#include <stdio.h>
#include <stdlib.h>
#include "matrix.h"
vector_t* vector_new(size_t size)
{
int vector[size];
vector_t v;
v.size = size;
v.vector = vector;
return &v;
}
int main(int argc, char* argv[])
{
vector_t* vec = vector_new(3);
printf("v has size %d.\n", vec->size);
printf("v has size %d.\n", vec->size);
return EXIT_SUCCESS;
}
So this is a very simple program where I create a vector structure of size 3, return the pointer to the structure and then print its size. This, on the first print instance is 3 which then changes to 2686668 on the next print. What is going on?
Thanks in advance.
You are returning a pointer to a local variable v from vector_new. This does not have a slightest chance to work. By the time vector_new returns to main, all local variables are destroyed and your pointer points to nowhere. Moreover, the memory v.vector points to is also a local array vector. It is also destroyed when vector_new returns.
This is why you see garbage printed by your printf.
Your code has to be completely redesigned with regard to memory management. The actual array has to be allocated dynamically, using malloc. The vector_t object itself might be allocated dynamically or might be declared as a local variable in main and passed to vector_new for initialization. (Which approach you want to follow is up to you).
For example, if we decide to do everything using dynamic allocation, then it might look as follows
vector_t* vector_new(size_t size)
{
vector_t* v = malloc(sizeof *v);
v->size = size;
v->vector = malloc(v->size * sizeof *v->vector);
return v;
}
(and don't forget to check that malloc succeeded).
However, everything that we allocated dynamically we have to deallocate later using free. So, you will have to write a vector_free function for that purpose.
Complete re-write of answer to address your question, and to provide alternate approach:
The code as written in OP will not compile: &v is an illegal return value.
If I modify your code as such:
#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
typedef struct
{
size_t size;
int* vector;
} vector_t;
vector_t* vector_new(size_t size)
{
int vector[size];
vector_t v, *pV;
pV = &v;
pV->size = size;
pV->vector = vector;
return pV;
}
int main(int argc, char* argv[])
{
vector_t* vec = vector_new(3);
printf("v has size %d.\n", vec->size);
printf("v has size %d.\n", vec->size);
getchar();
return EXIT_SUCCESS;
}
It builds and runs, but returns unintended values for vec->size in main() due to the local scope of that variable in the function vector_new.
Recommend creating globally visible instance of your struct, and redefine vector_new() to int initVector(void):
#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
#define SIZE 10
typedef struct
{
size_t size;
int* vector;
} vector_t;
vector_t v, *pV;//globally visible instance of struct
int initVector(void)
{
int i;
pV->size = SIZE;
pV->vector = calloc(SIZE, sizeof(int));
if(!pV->vector) return -1;
for(i=0;i<SIZE;i++)
{
pV->vector[i] = i;
}
return 0;
}
int main(int argc, char* argv[])
{
int i;
pV = &v; //initialize instance of struct
if(initVector() == 0)
{
printf("pV->size has size %d.\n", pV->size);
for(i=0;i<SIZE;i++) printf("pV->vector[%d] == %d.\n", i, pV->vector[i]);
}
getchar(); //to pause execution
return EXIT_SUCCESS;
}
Yields these results:
You still need to write a freeVector function to undo all the allocated memory.
I have the following code in a header file:
#ifndef BUFFER_H
#define BUFFER_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct c_buff
{
void *buffer; // data buffer
void *buffer_end; // end of data buffer
size_t capacity; // maximum number of items in the buffer
size_t count; // number of items in the buffer
size_t sz; // size of each item in the buffer
void *head; // pointer to head
void *tail; // pointer to tail
};
void cb_init(c_buff *cb, size_t capacity, size_t sz)
{
cb->buffer = malloc(capacity * sz);
if(cb->buffer == NULL) {
// handle error
}
cb->buffer_end = (char *)cb->buffer + capacity * sz;
cb->capacity = capacity;
cb->count = 0;
cb->sz = sz;
cb->head = cb->buffer;
cb->tail = cb->buffer;
}
#endif
And the following c file
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdio.h>
#include <common.h>
#include <usart.h>
#include <buffer.h>
struct c_buff usart_buffer;
struct c_buff *usart_buffer_ptr;
cb_init(usart_buffer_ptr, USART_BUFFER_SIZE, sizeof(char));
void initUSART(void) {
SETBIT(UCSR0A, UDRE0);
//SETBIT(UCSR0A, U2X0);
SETBIT(UCSR0C, UCSZ01);
SETBIT(UCSR0C, UCSZ00);
UBRR0 = 25;
SETBIT(UCSR0B, RXCIE0);
SETBIT(UCSR0B, TXCIE0);
SETBIT(UCSR0B, RXEN0);
SETBIT(UCSR0B, TXEN0);
}
ISR(USART_RX_vect) {
char data;
data = UDR0;
UDR0 = data;
}
ISR(USART_TX_vect) {
}
When I try to compile this I get an error that points to this line:
cb_init(usart_buffer_ptr, USART_BUFFER_SIZE, sizeof(char));
And it just says "error: expected ')' before numeric constant".
Google tells me it's some kind of preprocessor error. But I don't see how that could be the case.
I'm new to C so I apologize if it is something totally obvious.
You can't have a naked function call at the top level.
cb_init(usart_buffer_ptr, USART_BUFFER_SIZE, sizeof(char));
is a naked function call. Move that inside main().
You can't run function in global scope. It has to be done in main:
int main(int argc, char *argv[] {
cb_init(usart_buffer_ptr, USART_BUFFER_SIZE, sizeof(char));
}
The problem is that you're attempting to execute a method at the file level.
cb_init(usart_buffer_ptr, USART_BUFFER_SIZE, sizeof(char));
The C language only allows declarations / definitions at this level not actual executed statements. This call needs to be moved into a function definition.