having trouble acquiring Int from "gets(*buffer)" - c

So my tutor asked me to acquire an integer for a data struct , but 2 of the int parts im supposed to get , is via gets , im thinking he meant me to use gets(temp) // temp stand for char temp[50] and then perform x=strlen(temp);
here is my work so far :
#include<stdio.h>
#include<conio.h>
#include<string.h>
#define N 20
struct one
{
int ak;
char pin[N];
};
struct two
{
int data,mat[N];
struct one melos,item;
};
int main(void)
{
bool x=true;
int i;
char temp[N];
struct one person;
struct two memb;
/*GETTING VARS*/
gets(person.pin);
gets(memb.item.pin);
gets(memb.melos.pin);
person.ak=(int)gets(temp);
memb.data=(int)gets(temp);
for(i=0;i<N;i++)
scanf("%d",&memb.mat[i]);
scanf("%d",&memb.melos.ak);
scanf("%d",&memb.item.ak);
putchar('\n');
/*CHECKING VARS*/
puts("Posting vars in Data Struct ""one"" \n");
printf("%d\n",person.ak);
puts(person.pin);
puts("Posting vars in Data Struct ""two"" \n");
printf("%d\n",memb.data);
putchar('\n');
for(i=0;i<N;i++)
printf("%d\t",memb.mat[i]);
printf("\n%d\n",memb.melos.ak);
puts(memb.melos.pin);
printf("%d\n",memb.item.ak);
puts(memb.item.pin);
puts("**********************\n---POST_END---");
return 1;
}

The return value of gets() is the pointer to the buffer passed if successful, and NULL if failed. It won't mean the integer read.
Also note that you shouldn't use gets(), which has unavoidable risk of buffer overrun.
You will have to convert the string read to integer.
Try this:
#include<stdio.h>
#include<stdlib.h> /* for using atoi() */
#include<string.h>
#define N 20
/* read one line while checking the size read */
char* safer_gets(char* outbuf, size_t max){
size_t idx = 0;
int input;
if(max == 0) return NULL;
while(idx + 1 < max && (input = getchar()) != EOF && input != '\n'){
outbuf[idx++] = input;
}
if (idx == 0 && input == EOF) return NULL;
outbuf[idx] = '\0';
return outbuf;
}
/* read one line and convert it to integer */
int get_int(void) {
char temp[N];
safer_gets(temp, sizeof(temp));
return atoi(temp);
}
struct one
{
int ak;
char pin[N];
};
struct two
{
int data,mat[N];
struct one melos,item;
};
int main(void)
{
int i;
struct one person;
struct two memb;
/*GETTING VARS*/
safer_gets(person.pin, sizeof(person.pin));
safer_gets(memb.item.pin, sizeof(memb.item.pin));
safer_gets(memb.melos.pin, sizeof(memb.melos.pin));
person.ak=get_int();
memb.data=get_int();
/* latter part omitted */
}

Avoid gets - I'm surprised your class mentions it because it's been removed from all of the recent C language specifications and now deprecated in C++11.
But if you must...
http://www.cplusplus.com/reference/cstdio/gets/
long int getIntegerWithGetS() {
char* end;
char* buffer = calloc( 1024, sizeof(char) ); // 1024 bytes should be enough
long int result;
bool got_result_yet = false;
while( !got_result_yet ) {
gets( buffer ); // DANGER WILL ROBINSON
result = strtol( buffer, &end, 10 );
if( result == 0 ) {
if( end != buffer ) {
result = 0;
got_result_yet = true;
}
} else {
if( result != LONG_MAX && result != LONG_MIN && errno != ERANGE ) got_result_yet = true;
}
}
free(buffer);
return result;
}
Note how I call my code in a loop so we will persist until we get valid input from the user. I start off calling gets (to fill the buffer), then using strtol to convert the human-readable text in buffer to an actual computer int value - note that strtol is more powerful than atoi and uses long int instead of int as its declared type. Then the code checks for the strtol error conditions (in case a user types in "0" when the function returns 0 on failure anyway).
I don't return immediately, because the buffer must be free'd before execution leaves the scope, otherwise that buffer will remain unallocated and so leaked.

Related

Having problems passing in data to a function

Writing a program in C and I am trying to pass two variables into the function kstrextend. Name which is a word or set of characters that is stored in the value kstring and a which is a numeric value, but name is not getting passed into the function at all as far as I can tell and I cannot figure out why. Is something not getting stored correctly? Because the function works just fine I just cannot get name passed in correctly.
Declaration of kstring and name:
kstring name;
char kstring[50];
Typedef:
typedef struct
{
char *data;
size_t length;
} kstring;
Function:
void kstrextend(kstring *strp, size_t nbytes)
{
char *nwData;
int lnth=strp->length;
if(lnth < nbytes)
{
// new array allocate with large size and copy data to new array
nwData = (char *)realloc(strp->data, nbytes);
// call abort in case of error
if(nwData == NULL)
{
abort();
}
//Making strp->data point to the new array
strp->data = nwData;
//Setting strp->length to the new size.
strp->length = nbytes;
for(int i = 0; i <= lnth; i++)
{
printf("\n %s",strp->data);
}
// filled with '\0' in remaining space of new array
for (int lp = lnth; lp < nbytes; lp++)
{
strp->data[lp] = '\0';
printf("\n %s", strp->data[lp]);
}
}
}
Portion of main:
size_t a;
char * k = kstring;
printf("\n Enter number: ");
scanf("%d", &a);
name.data = (char*)calloc(sizeof(k), 1);
strcpy(input, k);
name.length= kstring_length;
kstrextend(&name,a);
First of all, you have misleading variable name kstring. Use something else like kstring_init and assign it a value. I assume you want to initialize the name variable of type kstring with something and then change its length. So this is what it is all about. Then define a constant of type char * and initialize length and data of your kstring with it. Then use realloc to extend the memory of the pointer with the input value a, not with the size of k. That does not make sense. Since the size of k is the size of the pointer, which is constant.
In your function: don't use int if you pass size_t. Use the same datatype where you do the same things.
In your loop from 0 to lnth, you output the same string lnth+1 times, which does not make sense. You probably want to output the characters of the string. So use %c and use an index into the character array and don't set <= lnth but < lnth as upper limit. Take care with data types if signed and unsigned!
Design hint: If you have a if block, that wraps all your code... invert the condition and just exit so that the code is after the if block.
Take care when you work with size_t and int, since int is signed and size_t is not, which can give problems in if statements.
Don't use abort but rather exit. You don't want your program to abort abnormally and core-dump.
A working version of your program is:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef struct
{
char *data;
size_t length;
} kstring;
kstring name;
char *kstring_init = "blabla";
void kstrextend(kstring *strp, size_t nbytes)
{
char *nwData;
size_t lnth = strp->length;
if ((int) lnth >= (int) nbytes) {
printf("Error, size already larger than requested size.\n");
exit(-1);
}
// new array allocate with large size and copy data to new array
nwData = realloc(strp->data, sizeof(char) * (int) nbytes);
if(nwData == NULL)
{
printf("Error, realloc returned NULL\n");
exit(-1);
}
//Making strp->data point to the new array
strp->data = nwData;
//Setting strp->length to the new size.
strp->length = nbytes;
for(int i = 0; i < lnth; i++)
{
printf("\n %c", strp->data[i]);
}
// filled with '\0' in remaining space of new array
for (int lp = lnth; lp < (int) nbytes; lp++)
{
strp->data[lp] = '\0';
printf("\n %c", strp->data[lp]);
}
}
int main(void)
{
size_t a;
printf("\n Enter number: ");
scanf("%d", &a);
name.length = strlen(kstring_init) + 1;
printf("Length of string is: %d\n", name.length);
name.data = (char*)malloc(sizeof(char) * name.length);
strcpy(name.data, kstring_init);
printf("Old string: %s\n", name.data);
printf("You want to reallocate %d bytes\n", a);
kstrextend(&name, a);
return 0;
}

How to fix? Triggers exception when trying to free dynamic allocated memory

This is my first time posting question, and I did try to find solution, but, even if I did found it I didn't recognize it.
So, as the title says, the problem is in this triggered exception "Exception thrown at 0x0F26372D (ucrtbased.dll) in lab10.exe: 0xC0000005: Access violation reading location 0xCCCCCCC4.
If there is a handler for this exception, the program may be safely continued.", which happens when I step into line -> free(word).
This did happen to me a few times when I was learning malloc, but I overlooked it - thinking there was some other problem. But now I see that I'am doing something wrong.
The point of the program is - writing the struct "word". I need to input sentence and "cut" it into words, and then every word put in struct together with size of letters in the word and ordinal number of the word.
#include <stdio.h>
#include <string.h>
struct word {
char text_word[50];
unsigned sizee; //number of letters of the word
unsigned number; //ordinal number of the word
};
void cutting_sentence(struct word *p, char *sen) { //sen is sentence
int size_sen, i, j;
size_sen = strlen(sen) + 1; //size of sentence
p = (struct word*)malloc(size_sen * sizeof(struct word));
if (p == NULL) {
printf("\nNot enaugh memory!");
return 0;
}
strcpy(p[0].text_word, strtok(sen, " ,.!?"));
p[0].sizee = strlen(p[0].text_word);
p[0].number = 1;
printf("word:%s \t size:%u \t ordinal number of the word:%u\n",
p[0].text_word, p[0].sizee, p[0].number);
for (i = p[0].sizee - 1, j = 1;i < size_sen;++i) {
if (*(sen + i) == ' ' || *(sen + i) == '.' || *(sen + i) == ','
|| *(sen + i) == '?' || *(sen + i) == '!') {
strcpy(p[j].text_word, strtok(NULL, " ,.!?"));
p[j].sizee = strlen(p[j].text_word);
p[j].number = j + 1;
printf("word:%s \t size:%u \t ordinal number of the
word:%u\n", p[j].text_word, p[j].sizee, p[j].number);
j++;
}
}
}
int main() {
char sentence[1024];
struct word *word;
printf("Sentence: ");
gets(sentence);
cutting_sentence(&word, sentence);
free(word); //here is exception triggered
return 0;
}
You're changing the local value of the pointer argument passed, you need to change the memory at its target for the caller to discover the location of the allocated memory. Since you didn't do that, you're trying to free the local variable word which is stored on the stack of main().
First thing to fix is not to have a variable identical to the name of a type, that's just evil.
Then change the function prototype to pass a double pointer:
void cutting_sentence(struct word **p, char *sen);
And remember that where you were using p you now need to use *p or first assign a local (word *) with the address value contained there.
void cutting_sentence(struct word **p, char *sen) { //sen is sentence
int size_sen, i, j;
size_sen = strlen(sen) + 1; //size of sentence
*p = (struct word*)malloc(size_sen * sizeof(struct word));
if (*p == NULL) {
printf("\nNot enaugh memory!");
return; //void cannot return a value
}
and so on changing every usage of p to *p.
and then
int main() {
char sentence[1024];
struct word *words;
printf("Sentence: ");
gets(sentence);
cutting_sentence(&words, sentence);
if (words != NULL)
free(words); //now valid
return 0;
}
There are a few more issues than those previously discussed.
[As already pointed out] your first argument should be struct word **. But, a simpler way is to eliminate it and change the return type to struct word *. This allows the code within the function to be simpler (i.e. no double dereferencing of a pointer)
Although allocating as many word structs as there are characters in the input string will work, that is somewhat unusual.
A better way [more idiomatic, at least] to do this is to use realloc inside the loop.
In either case, the array size can be trimmed to only use what it needs via a final realloc.
I think that your loop that scans sen looking for delimiters is overly complex. Simply using strtok in the loop will give the same effect with less complexity.
Also, you're not conveying back a count of the number of word. One way is to add an extra element to the array that has a size of zero (e.g. an end-of-list marker)
Here's is a refactored version that should help:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct word {
char text_word[50];
unsigned sizee; // number of letters of the word
unsigned number; // ordinal number of the word
};
struct word *
cutting_sentence(char *sen)
{ // sen is sentence
int curcnt = 0;
int maxcnt = 0;
char *token;
struct word *word;
struct word *words;
while (1) {
token = strtok(sen," ,.!?\n");
if (token == NULL)
break;
sen = NULL;
if (curcnt >= maxcnt) {
maxcnt += 100;
words = realloc(words,sizeof(struct word) * (maxcnt + 1));
}
word = &words[curcnt];
strcpy(word->text_word,token);
word->number = curcnt;
word->sizee = strlen(token);
++curcnt;
}
words = realloc(words,sizeof(struct word) * (curcnt + 1));
// set end-of-list
word = &words[curcnt];
word->sizee = 0;
return words;
}
int
main()
{
char sentence[1024];
struct word *words;
struct word *word;
printf("Sentence: ");
fflush(stdout);
fgets(sentence,sizeof(sentence),stdin);
words = cutting_sentence(sentence);
for (word = words; word->sizee != 0; ++word)
printf("main: number=%u sizee=%u text_word='%s'\n",
word->number,word->sizee,word->text_word);
free(words);
return 0;
}
the following proposed code:
eliminates redundant code
properly checks for errors
properly outputs error message (and the text reason the system thinks an error occurred to stderr
performs the desired functionality
properly initializes the struct word pointer
properly updates the struct word pointer
changed int sizee to size_t sizee because the function: strlen() returns a size_t, not an int
changed int i to unsigned i because the declaration of the struct field number is declared as unsigned
documents why each header file is included
allocates an instance of the struct word for every character in the sentence This is 'overkill'. The most possible amount of words would be if every word was only a single character. So, immediately, the size of the allocated memory could be cut in half. A loop, counting the word separators would result in the correct amount of allocated memory. You could easily add that feature.
Note the way that the function: strtok() is used. I.E. initial call before loop, then following calls at end of loop
And now the proposed code:
#include <stdio.h> // printf(), fgets(), NULL
#include <stdlib.h> // exit(), EXIT_FAILURE, malloc(), free()
#include <string.h> // strlen(), strtok()
struct word
{
char text_word[50];
size_t sizee; //number of letters of the word
unsigned number; //ordinal number of the word
};
// notice the `**p` so can access the pointer in `main()` so it can be updated
void cutting_sentence(struct word **p, char *sen)
{ //sen is sentence
size_t size_sen = strlen(sen); //size of sentence
struct word *wordptr = *p;
wordptr = malloc(size_sen * sizeof(struct word));
if ( !wordptr )
{
perror("malloc failed");
exit( EXIT_FAILURE );
}
unsigned i = 0;
char * token = strtok(sen, " ,.!?");
while( token )
{
strcpy( wordptr[i].text_word, token );
wordptr[i].sizee = strlen( token );
wordptr[i].number = i;
printf("word:%s\t Length:%lu]tordinal number of the word:%u\n",
wordptr[i].text_word,
wordptr[i].sizee,
wordptr[i].number);
token = strtok( NULL, " ,.!?");
i++;
}
}
int main( void )
{
char sentence[1024];
struct word *wordArray = NULL;
printf("Sentence: ");
if( !fgets(sentence, sizeof( sentence ), stdin ) )
{
perror( "fgets failed" );
exit( EXIT_FAILURE );
}
// remove trailing new line
sentence[ strcspn( sentence, "\n") ] = '\0';
cutting_sentence(&wordArray, sentence);
free( wordArray ); //here is exception triggered
return 0;
}
A typical run of the code results in:
Sentence: hello my friend
word:hello Length:5 ordinal number of the word:0
word:my Length:2 ordinal number of the word:1
word:friend Length:6 ordinal number of the word:2
Notice that 'short' words result in an uneven output. You might want to correct that.

How to access struct in an array of structs

In a school assignment, I have to sort elements of struct that are located in binary file. I think I have managed to sort it, but I have a problem with printing the result. I don't know how to access elements of struct because data must be read from file, so I only have address of the first struct in a array. (I think it should stay in array so that I can use qsort.)
This is the main code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "readfile.h"
typedef struct {
char name[32];
double value;
} record;
int nuvu(record* a, record* b){
if(a->name < b->name) return -1;
if(a->name > b->name) return 1;
if(a->value < b->value) return -1;
if(a->value > b->value) return 1;
}
int main()
{
long N;
unsigned char* p = readfile( "d.bin", &N );
char* s;
scanf("%s",&s);
int k= N/sizeof(record);
qsort(p,k,sizeof(record),(int(*)(const void*, const void *))nuvu);
printf???
free(p);
return 0;
}
Additional:
readfile.c
#include "readfile.h"
unsigned char* readfile( char* filename, long* pN )
{
FILE* f= fopen(filename,"rb");
if(f==0){
*pN=-1;
return 0;
}
fseek(f,0,SEEK_END);
*pN=ftell(f);
fseek(f,0,SEEK_SET);
char*p=malloc(*pN);
if(p==0){
*pN=-2;
fclose(f);
return 0;
}
size_t r = fread(p,1,*pN,f);
if(r!=*pN){
*pN=-3;
fclose(f);
free(p);
return 0;
}
fclose(f);
return p;
}
readfile.h
#ifndef __READFILE_H
#define __READFILE_H
#include <stdio.h>
#include <stdlib.h>
unsigned char* readfile(char* filename, long* pN);
#endif /* __READFILE_H */
The biggest confusion you seem to have is "How do I read my array of structs back in?"
unsigned char* p = readfile( "d.bin", &N );
Is no way to begin. The concept of reading records from a binary file into an array of struct, is to read sizeof (struct record) bytes from the file into storage for type struct record. (this will ignore for now the lack of serialization of the data, padding and portability issues, and the fact we are using a typedef).
Knowing the file size, and knowing the sizeof (struct record) allows you to (1) validate the number of records you will read from the file, e.g. (nbytes / sizeof (struct record)) and (2) determine whether there are any stray bytes leftover that will not be part of the read (e.g. if (nbytes / sizeof (struct record) != 0)) which if present you should at least warn about.
Depending on the number of records you have to read and whether there is an upper bound for that number will determine whether you can use a fixed size array (or VLA) or whether you need to dynamically allocate (and reallocate) to address an unknown number of records or to prevent StackOverflow.. Regardless how you handle creating storage for your records -- It is up to you to make sure you do not write beyond the bounds of the storage you create.
Below, for example purposes we will simply work with an array of 100 records. The dividing line between what will fit on the stack and when you need to dynamically allocate will be compiler dependent, but any time you start thinking about tens of thousands of records, you need to consult your compiler documentation and start thinking about dynamic allocation.
fread provides a simple method to read binary records from a file and validate that you actually read the number of records you intended to read. For example, given a declaration of an array of 100 records in rec, you could do something like the following:
enum { MAXC = 32, MAXS = 100 }; /* if you need constants, define them */
...
record rec[MAXS] = {{ .name = "" }}; /* array of 100 records */
...
nrec = nbytes / sizeof *rec; /* number of records based on file size */
/* read / validate nrec records from file */
if (fread (rec, sizeof *rec, nrec, fp) != nrec) {
perror (fn);
return 1;
}
With your records successfully read from your file, using qsort to sort the records (either by name or by value) requires you to understand that the const void * pointers to be compared in your comparison function will be pointer to rec, so you must provide an appropriate cast within your comparison function to access and compare the values. For example to perform a string comparison on name, you can do something similar to the following:
/** record string comparison on name */
int reccmpname (const void *a, const void *b)
{
const record *ra = a,
*rb = b;
return strcmp (ra->name, rb->name);
}
Other than that, the remainder of what your code lack is validation of each step in the process. Always, always, validate the return of any function you use and handle any errors you encounter. A minimal example, without splitting the code up between separate source files could be something like the following. Splitting up into separate source files is left to you.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum { MAXC = 32, MAXS = 100 }; /* if you need constants, define them */
typedef struct {
char name[MAXC];
double value;
} record;
/** record string comparison on name */
int reccmpname (const void *a, const void *b)
{
const record *ra = a,
*rb = b;
return strcmp (ra->name, rb->name);
}
int main (int argc, char **argv) {
record rec[MAXS] = {{ .name = "" }}; /* array of 100 records */
size_t nrec = 0; /* number of records from file */
long nbytes = 0; /* number of bytes in file */
char *fn = argc > 1 ? argv[1] : "dat/records.bin";
FILE *fp = fopen (fn, "rb");
if (!fp) { /* validate file open for reading */
fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
return 1;
}
if (fseek (fp, 0, SEEK_END) == -1) { /* validate seek to end */
perror ("fseek");
return 1;
}
nbytes = ftell (fp); /* number of bytes in file */
if (nbytes == -1) {
perror ("ftell");
return 1;
}
if (fseek (fp, 0, SEEK_SET) == -1) { /* validate seek to start */
perror ("fseek");
return 1;
}
if (nbytes % sizeof *rec != 0) /* does file contain even no. or records? */
fprintf (stderr, "warning: file size not multiple of record size.\n");
nrec = nbytes / sizeof *rec; /* number of records based on file size */
/* read / validate nrec records from file */
if (fread (rec, sizeof *rec, nrec, fp) != nrec) {
perror (fn);
return 1;
}
fclose (fp); /* close file */
printf ("\n=== unsorted records ===\n\n"); /* output unsorted */
for (size_t i = 0; i < nrec; i++)
printf ("%-32s %g\n", rec[i].name, rec[i].value);
qsort (rec, nrec, sizeof *rec, reccmpname); /* qsort records */
printf ("\n=== sorted records ===\n\n"); /* output sorted */
for (size_t i = 0; i < nrec; i++)
printf ("%-32s %g\n", rec[i].name, rec[i].value);
return 0;
}
note: The data file used simply contained 100 struct records with dictionary words as name and random values as value shuffled before being written to the file.
Example Use/Output
$ ./bin/struct_rd_name_val_recs
=== unsorted records ===
Abscess 4.15871e+08
Abject 3.5743e+08
Abo 6.87659e+08
Aboard 2.02028e+09
Abase 3.34319e+08
...
=== sorted records ===
A 3.66907e+08
Aaa 5.59224e+07
Aaas 1.45617e+09
Aardvark 1.72828e+09
Aarhus 1.95723e+09
Let me know if you have any questions.
Use the standard procedure for qsort, don't change its signature. Use strcmp as noted in comments. You have to figure out the logic of how the structure is to be sorted. The example below sorts by record::name, if name is the same, it tests value, in that order:
int nuvu(const void * a_, const void * b_)
{
const record* a = a_;
const record* b = b_;
if(strcmp(a->name, b->name) == 0)
return a->value > b->value;
return strcmp(a->name, b->name);
}
Data is read as bytes in to p, it must be converted to "array of records" record* arr = (record*)p;. The number of items in the array should be filesize/sizeof(record) if everything went according to plan
int main(void)
{
long filesize = 0;
unsigned char* p = readfile("d.bin", &filesize);
if(!p)
return 0;
int count = filesize / sizeof(record);
record* arr = (record*)p;
qsort(arr, count, sizeof(record), nuvu);
for(int i = 0; i < count; i++)
printf("%s %f\n", arr[i].name, arr[i].value);
free(p);
return 0;
}
You can use the [] operator with a pointer:
struct my_struct {
int i, j;
};
struct my_struct * ptr = malloc(sizeof(struct my_struct) * 10);
for(int n = 0; 10 > n; ++ n)
{
ptr[n].i = n;
ptr[n].j = n*2;
}
free(ptr);

Pointer to string not incrementing (C programming)

I have two string shown below:
char code *text_to_compare = "TesT";
char code *dictionary = "TesTT,Tes,Tes,TesT.";
In a part of the program I used the following code where it increments the pointers for both strings to point to the next characters.
ch_A = text_to_compare[i++];
ch_B = dictionary[j++];
Why is pointer j being incremented but pointer i is remaining as it was?
Thanks in advance.
EDIT: Below is the full code. The aim of this project is to compare a string with a list of words. Integer i is not incrementing only after the program enters the else statement.
#include <string.h>
char code *text_to_compare = "TesT";
char code *dictionary = "TesTT,Tes,Tes,TesT.";
int bring_characters(char pdata *, char pdata *, char ch_A, char ch_B, char i,
char j);
void main(void) {
unsigned char ch_A;
unsigned char ch_B;
unsigned char i = 0;
unsigned char j = 0;
char pdata N1;
char pdata N2;
int result;
ch_A = text_to_compare[i]; // take a caharacter from the text
ch_B = dictionary[j];
result = bring_characters(&N1, &N2, ch_A, ch_B, i, j);
if (result == 0) {
while (1)
;
}
else {
while (1)
;
}
while (1)
;
}
int bring_characters(char pdata *N1, char pdata *N2, char ch_A, char ch_B,
char i, char j) {
do {
if (ch_A == ch_B) {
ch_A = text_to_compare[i++]; // take a caharacter from the text
ch_B = dictionary[j++];
if ((ch_A == '\0') && ((ch_B == ',') || (ch_B == '.'))) {
while (1)
; // load idata-------------------------------------------------------------------------------------------------
}
}
else {
i = 0; // refresh pointer
ch_A = text_to_compare[i]; // take a caharacter from the text
ch_B = dictionary[j++];
}
} while (ch_B != '.');
return (0);
}
Whew, there's a lot going on here! Now that you've added the full code it looks like in your attempt to move on to the next word you have prevented yourself from moving on.. you'll need to do some major revisions to get this guy working.
The first thing you need to do is figure out how you would do this on paper, then step by step try to reproduce that in your code.
Here's a function to kickstart you:
int find_next_match(char toFind, int startingPosition, char* mainString){
int counter = startingPosition;
char buf = mainString[counter];
while(buf != NULL){
if (buf == toFind){
return counter;
}
counter++;
buf = mainString[counter];
}
return -1; //error
}
You can use something like this to find the next instance of the first character in your string, then you can implement a loop to determine if that is a match.
Good luck, you can do it!

Storing values of an array in one variable

I am trying to use md5 code to calculate checksums of file. Now the given function prints out the (previously calculated) checksum on screen, but I want to store it in a variable, to be able to compare it later on.
I guess the main problem is that I want to store the content of an array in one variable.
How can I manage that?
Probably this is a very stupid question, but maybe somone can help.
Below is the function to print out the value. I want to modify it to store the result in one variable.
static void MDPrint (MD5_CTX* mdContext)
{
int i;
for (i = 0; i < 16; i++)
{
printf ("%02x", mdContext->digest[i]);
} // end of for
} // end of function
For reasons of completeness the used struct:
/* typedef a 32 bit type */
typedef unsigned long int UINT4;
/* Data structure for MD5 (Message Digest) computation */
typedef struct {
UINT4 i[2]; /* number of _bits_ handled mod 2^64 */
UINT4 buf[4]; /* scratch buffer */
unsigned char in[64]; /* input buffer */
unsigned char digest[16]; /* actual digest after MD5Final call */
} MD5_CTX;
and the used function to calculate the checksum:
static int MDFile (char* filename)
{
FILE *inFile = fopen (filename, "rb");
MD5_CTX mdContext;
int bytes;
unsigned char data[1024];
if (inFile == NULL) {
printf ("%s can't be opened.\n", filename);
return -1;
} // end of if
MD5Init (&mdContext);
while ((bytes = fread (data, 1, 1024, inFile)) != 0)
MD5Update (&mdContext, data, bytes);
MD5Final (&mdContext);
MDPrint (&mdContext);
printf (" %s\n", filename);
fclose (inFile);
return 0;
}
Declare an array and memcpy the result.
Example:
unsigned char old_md5_dig[16]; // <-- binary format
...
MD5_CTX mdContext;
MD5Init(&mdContext);
MD5Update(&mdContext, data, bytes);
MD5Final(&mdContext);
memcpy(old_md5_dig, mdContext.digest, 16); // <--
Edit: to compare the previous with the new md5 hash you can use memcmp,
if (memcmp(old_md5_dig, mdContext.digest, 16)) {
// different hashes
}
Just pass a char buffer and its size to this function:
static void MDGen (mdContext, buf, size)
MD5_CTX *mdContext;
char *buf;
size_t size;
{
int i;
int minSize = 33; // 16 pairs of hex digits plus terminator
if ((buf != NULL) && (size >= minSize))
{
memset(buf, 0, size);
for (i = 0; i < 16; i++)
{
snprintf(buf + (i*2), size - (i*2), "%02x", mdContext->digest[i]);
}
}
}
You can define a variable:
char **md5sums;
You will then need to modify MDPrint to instead return a malloced null-terminated string with the 32 hex digits. You can basically reuse your existing loop, but with sprintf instead.
Then have main add each md5sum (a char*) to md5sums. You will need to use realloc to allocate memory for md5sums because you don't know the number of elements up front.
It should be:
static char* MDString (mdContext)
MD5_CTX *mdContext;
{
int i;
char *digest = malloc(sizeof(char) * 33);
if(digest == NULL)
{
return NULL;
}
for (i = 0; i < 16; i++)
{
sprintf(digest + (i * 2), "%02x", mdContext->digest[i]);
}
return digest;
}
Also, you should modify your code by editing your question. And why are you using K&R syntax?
EDIT: I fixed some incorrect counts.
Since you want to duplicate, store, compare, free and probably more the MD5 digest, just create a md5_t type and write appropriate functions to manipulate it, ie :
typedef char md5_t[16];
md5_t *md5_new( MD5_CTX *pMD5Context )
{
md5_t *pMD5 = malloc( sizeof( md5_t ) );
memcpy( pMD5, pMD5Context->digest, 16 );
return pMD5 ;
}
int md5_cmp( md5_t *pMD5A, md5_t *pMD5B )
{
return memcmp( pMD5A, pMD5B, 16 );
}
void md5_print( md5_t *pMD5 )
{
...
}
void md5_free( md5_t *pMD5 )
{
free( pMD5 );
}
And so on ... Next, create a type for your MD5 array and simple functions to manipulate it :
typedef struct md5array_t {
unsigned int uSize ;
md5_t **ppMD5 ;
}
md5array_t *md5array_new()
{
md5array_t *pArray = malloc( sizeof( md5array_t );
pArray->uSize = 0 ;
pArray->ppMD5 = NULL ;
}
md5array_t *md5array_add( md5array_t *pArray, md5_t *pMD5 )
{
pArray->uSize ++ ;
pArray = realloc( pArray, pArray->uSize + sizeof( md5_t * ) );
pArray->ppMD5[ pArray->uSize-1 ] = pMD5 ;
}
md5_t *md5array_get( md5array_t *pArray, unsigned int uIndex )
{
return pArray->ppMD5[ uIndex ];
}
void md5array_free( md5array_t *pArray }
{
/* I let you find what to write here.
Be sure to read AND understand the previous
functions. */
}
To resume : create a type and the functions you need to manipulate it as soon as you want to do more than one operation with a datum. You don't need to create a real, generic type with full-blown functions representing as many operations you can imagine on that type : just code what you need. For example, in the md5array_t, you can add a md5_t * but you cannot delete it (unless you write the function void md5array_del( md5array_t *pArray *, int iIndex ).
P.S. : my C code is here to "illustrate" my point of view, not to be useable by just copying/pasting it as is ...
Store it as a string and then use strcmp() to compare.
Just leave in an array!
You don't have you store it in variable; because it is ALREADY in a variable..
Just create global variable, store MD5 hash in it and compare to it later.
What you need is MD5IsEqual function, which takes 2 arrays like this.
int MD5IsEqual(unsigned char *x, unsigned char* y)
{
int i;
for(i=0; i<16;i++)
if(x[i] != y[i])
return 0;
return 1;
}
Why not make the function
MD5File(char * filename, unsigned char *digest){
/* as before */
memcpy(digest, mdContext->digest, 16);
return;
}
so that outside the function you have access to the digest (after printing it) ?
The digest is just an array of 16 unsigned char...
You know where the sum is stored by the way you print it: through ->digest[i]. Which is defined like
unsigned char digest[16];
So you basically just need to copy these 16 unsigned char in another array of unsigned char (at least 16 unsigned char long). The function memcpy can do it. If you need comparing two sums, you can use memcmp (the comparing size will be 16*sizeof(unsigned char) which is 16, being sizeof(unsigned char) 1.

Resources