How to reset allocated memory and resources in c? - c

My program consists of a Menu, where you can select 1 of 2 options.
The second is just to exit the program. The first, however, is where you can find a specific sequence of bits that you choose, in a separate ".txt" file with 100.000 lines.
It does what I want the first time, and then returns to the Menu.
The problem is when the user goes for a second (or more) search. The program prints on screen random information.
It seems like I didn't do a "reset" of the resources, memory or values on the first search.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct{
char ID[8];
char content[2048];
int distance;
} DATA;
void search(){
FILE *f;
DADO *z=NULL;
long int tot=0;
int a;
int c;
int i;
int j=1;
int k=0;
char e;
char b[2048];
printf("\n");
f=fopen("DANGER_DB_LARGE.txt", "r");
printf("\n");
printf("How many results do you wish?\n");
scanf("%d",&a);
printf("Introduce the sequence:\n");
scanf("%s",b);
c=strlen(b);
printf("\n");
z=(DATA*)realloc(z,(++tot)*sizeof(DATA));
while(e!=EOF){
e=fgetc(f);
if(k<8){
z[tot-1].ID[k]=e;
}
else if(k==8 && e=='\t'){
continue;
}
else if(k>=9 && e!='\n'){
z[tot-1].content[k-9]=e;
}
else if(e=='\n'){
k=(-1);
z=(DATA*)realloc(z,(++tot)*sizeof(DATA));
}
k++;
}
for(i=1; i<=tot; i++){
distance(z,i,c,b);
}
free(z);
fclose(f);
}
I proceed to store the ID and content of every single one of those 100.000 lines of text. I end the function by doing free(z), but when I search again the program just prints random stuff.

Use of uninitialised variables without an intervening assignment is undefined behaviour. It may work on the first Wednesday of every month, on the first time through the loop, only when the boss is looking, ...
int e; // originally was char
//...
while (e != EOF) { // uninitialised, no intervening assignment

Realloc returns void by the way
void *realloc(void *ptr, size_t size)
plus it takes a pointer as input so its pass by reference.
update: This function returns a pointer to the newly allocated memory, or NULL if the request fails.
my bad.

Related

C function returning different values while calling from main function

I have written a program which read values from a the file. The data in the file is in following format.
100 Full Name SomeDetails.
234 Full Name SomeDetails
Following is the program which i wrote.
#include <stdio.h>
#include <stdlib.h>
#include<string.h>
#define MAX 10
struct student
{
int rollno;
char name[20];
char course[25];
};
int main()
{
FILE *fptr;
fptr=fopen("records.txt","r");
struct student s[10];
int i=0,tstudent=0;
char che;
char line[100];
//SECTION : 1.1 -> READING NUMBER OF LINES
while(!feof(fptr))
{
che=fgetc(fptr);
if(che=='\n')
{
tstudent++;
}
}
printf("Total Lines in File = %d\n",tstudent);
fclose(fptr);
//SECTION : 1.2 -> READING RECORDS FROM FILE
fptr=fopen("records.txt","r");
char newString[20][20];
int ii,j,ctr;
j=0;
ctr=0;
for(i=0; i<tstudent; i++)
{
fgets(line,100,fptr);
printf("Value of Line %d = %s",i,line);
for(ii=0; ii<=(strlen(line)); ii++)
{
// if tab or NULL found, assign NULL into newString[ctr]
if(line[ii]=='\t'||line[ii]=='\0')
{
newString[ctr][j]='\0';
ctr++; //for next word
j=0; //for next word, init index to 0
}
else
{
newString[ctr][j]=line[ii];
j++;
}
}
}
for(ii=0; ii < ctr; ii++)
{
printf("\n%s",newString[ii]);
}
printf("Value of ctr = %d",ctr);
fclose(fptr);
}
Above code is working fine, BUT all the code is in main function, but i want to make a separate function which can be called from main file and return me every data of file in two dimensional or one dimensional array as return value.
Any help/suggestions would be appreciated.
I tried following CODE as a separate function.. NOT WORKING.
#include <stdio.h>
#include <stdlib.h>
#include<string.h>
char readfile(int tstudent,FILE* filename)
{
//FUNCTION TO READ RECORDS FROM FILE.
FILE *fptr;
int i,k;
char line[100];
char newString[20][20];
int j=0,ctr=0;
fptr=fopen("records.txt","r");
for(i=0; i<tstudent; i++)
{
fgets(line,100,fptr);
printf("Value of Line %d = %s",i,line);
for(k=0; k<=(strlen(line)); k++)
{
// if tab or NULL found, assign NULL into newString[ctr]
if(line[k]=='\t'||line[k]=='\0')
{
newString[ctr][j]='\0';
ctr++; //for next word
j=0; //for next word, init index to 0
}
else
{
newString[ctr][j]=line[k];
j++;
}
}
}
return newString;
}
I defined a new variable char results[] in main function.. and tried to called the function as follows
results[]=readfile(tstudent,fptr)
but when trying to read results.. its showing garbage
char readfile(int tstudent,FILE* filename)
...
char newString[20][20];
...
return newString;
That can't be a good thing, right? You define readFile to return one single character (not a pointer, just one byte) and then return an array instead. We should not be surprised the compiler complained.
If you "fix" that be redefining the return type, you still have a problem because newString is an automatic local variable. The storage (memory) it defines is undefined outside the function.
The easiest way for a function to populate a structure (or array) in C is for the caller to pass it as a function parameter. So you wind up with something more like:
int readfile( FILE* input, char newString[][20], int tstudent )
where newString is defined the same way as you have it, but by the caller, not in readfile. Cf. the stdio functions like fgets; most of them require the caller to define the buffer they read into.
I'll just point out a few more mistakes.
Whenever you call a function -- especially an I/O function -- check for errors. You may want to read tstudent records, but how many are there? If you ask for 5 and find only 1, what then? Your read loop must test for end-of-file, and readfile must return the number of records read, else the caller will never know. Compare with how fread(3) works. Those Unix guys knew a thing or two about how to define a function!
Now your function looks something like this:
int readfile( FILE* input, char newString[][20], int tstudent ) {
char line[100], *s;
int i=0;
for( ; i < tstudent && (s = fgets(line, sizeof(line), input)) != NULL; i++ ) {
/* do stuff with line */
}
/* check for EOF/error if s is NULL, and report */
return i;
}

Formatted input array int

I need to be able to enter array of ints and hold it in a set inside a struct, however for some reason it won't read the numbers into the array:
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#define MAX 100
typedef struct set {
int arr[MAX];
} set;
set SETA;
int read_set(set,...);
void print_set(set);
int main(){
int x;
x=read_set(SETA,2,3,4,-1);
printf("%d numbers were read\n",x);
print_set(SETA);
return 0;
}
void print_set(set s){
int *iptr;
iptr=s.arr;
while(*iptr++){
printf("%d ",*iptr);
}
}
int read_set(set s,...){
va_list ap;
int i=0;
int c=0;
va_start(ap,s);
while( *ap != -1){
s.arr[i++]=va_arg(ap,int);
printf("%d was entered\n",s.arr[i]);
c++;
}
va_end(ap);
return c;
}
the output I get is:
0 was entered
0 was entered
0 was entered
3 numbers were read
and needless to say that print_set prints nothing.
In
while( *ap != -1){
s.arr[i++]=va_arg(ap,int);
printf("%d was entered\n",s.arr[i]);
c++;
}
you increment i when you record the value.
When you try to print s.arr[i] you are one ahead of where you stored the value.
Increment after the print?
while( *ap != -1){
s.arr[i]=va_arg(ap,int);
printf("%d was entered\n",s.arr[i]);
i++;
c++;
}
You function int read_set(set s,...) takes a copy of a set s and puts stuff in it.
By the time you get back to the calling function in main, the set that you copied in is unchanged.
You need to send pointers to variables to change them:
int read_set(set *ps,...)
and the calling code would then need to send the address x = read_set(&SETA, 2, 3, 4, -1); so you can change what's in the set.
An alternative is to return the filled structure.
Two other things to think about.
First, you could declare your set inside main - it has no reason to be global.
And you don't need to captilaise it.
int main() {
set setA; //style/design point. Also don't shout.
//... etc
}
Also, look at your print function.
It uses while (*iptr++), so is checking of 0s or some kind of NULL to stop looping. I can't see any zeros so this needs a re-think. And, do you want to have a set that won't display anything beyond a 0?

What syntax am i missing out on regarding char arrays and pointers to them

I was doing some testing for a program of mine and was wondering why the program was crashing when entering my function. Don't mind the logic of the program, since i was still in the phase of making sure i understood how to use my tools at hand.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Constants */
#define HEX_CAPITAL_LETTERS_BEGIN 65
#define HEX_CAPITAL_LETTERS_END 90
#define HEX_NUMBERS_BEGIN 48
#define HEX_NUMBERS_END 57
#define EXIT_SUCCES 0
/* Prototypes */
void codeToField(char *charArray, int i, int hexFloor, int hexCeil, char *outputArray);
/* Main Function */
int main(void) {
char *code, warehouse, product, qualifiers;
int i = 0;
printf("Enter a MMOC product code: ");
scanf("%s", &code);
codeToField(code, i, HEX_CAPITAL_LETTERS_BEGIN, HEX_CAPITAL_LETTERS_END, &warehouse);
codeToField(code, i , HEX_NUMBERS_BEGIN, HEX_NUMBERS_END, &product);
strcpy(&qualifiers, code + i);
printf("\n\nWarehouse: %s\nProduct: %s\nQualifiers: %s\n", &warehouse, &product, &qualifiers);
return EXIT_SUCCES;
}
void codeToField(char *charArray, int i, int hexFloor, int hexCeil, char *outputArray) {
int j = 0;
while (charArray[i] >= hexFloor && charArray[i] <= hexCeil) {
outputArray[j] = charArray[i];
i++;
j++;
}
}
Thanks in advance.
First, this does not do what you want:
char *code, warehouse, product, qualifiers;
The only pointer is code, the other are just a single char. You're printing them as strings with printf, and you use warehouse and product as outputArray in your function. They need to be pointers (or arrays) too:
char *code, *warehouse, *product, *qualifiers;
Then you need memory. The pointers are still uninitialized, so any reading from them is undefined behavior.
You can either allocate memory with automatic storage duration (on the stack) or dynamically (on the heap).
Stack:
char codestr[100];
code = codestr;
but then, you could also just have declared code as
char code[100];
to avoid to have two variables.
If you want to allocate the memory dynamically, you would use malloc:
code = malloc(100);
Don't forget to free the memory again:
free(code);
warehouse, product, qualifiers all need memory too. Some of the array sizes could be deduced form the defined constants.
char *code, warehouse, product, qualifiers;
int i = 0;
printf("Enter a MMOC product code: ");
scanf("%s", &code);
Here, code is an uninitialized pointer to memory so once you do the scanf call, your program is hosed.
I think you want something more like
char code[100];
printf ("Enter a MMOC product code: ");
scanf ("%s", code);
The reason is because code has no memory allocated to it. It is an uninitialized pointer. Try this instead:
// ...
char myString[16], *code, warehouse, product, qualifiers;
code = &myString[0];
int i = 0;
printf("Enter a MMOC product code: ");
scanf("%15s", code);
// ...

Why break gets me out of 2 loops at once and how to fix it [duplicate]

This question already has answers here:
How to find the size of an array (from a pointer pointing to the first element array)?
(17 answers)
Closed 6 years ago.
Ok, so the idea of the task I have (I am the student) is to allow user to insert a string of words in this form: num1_num2_num3..._numN. The code should create an array X, give it memory dynamically and then I should fill X with numbers from string user inserted. Simple as that. Well, in the function stringuniz() I thought I had it all figured out but it simply wont work. It gets the first number well but it then stops and I think its because of the break. Break behaves (if I am right) like it breaks the entire code and not just the loop. Do you guys have an idea why is this happening?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void stringuniz(char *);
int *x;
int main(){
char s[50];
int i;
puts("Unesite string brojeva u formatu br1_br2_...brN: ");
gets(s);
stringuniz(s);
for(i=0;i<(sizeof(x)/sizeof(int));i++)
printf("%d",x[i]);
}
void stringuniz(char *s){
int duz,c=0,i,j,k=0,m=0;
char b[10];
duz=strlen(s);
for(i=0;i<duz;i++)
if(s[i]=='_')
c++;
x=(int*)malloc((c+1)*sizeof(int));
if(x==NULL) exit(1);
for(i=0;i<c+1;i++){
for(j=m;j<duz;j++){
if(s[j]!='_'){
b[k++]=s[j];
m++;
}
else{
b[k]='\0';
x[i]=atoi(b);
k=0;
m++;
break;
}
}
}
}
This
(sizeof(x)/sizeof(int)
won't give you the size of the array. sizeof(x) is the bytesize of int* (likely 4 or 8).
You'll need to remember the size as implied by the number of _ in the string.
Also you have some off-by-one errors in there and for future reference, you might want to choose more descriptive variable names for code you decide to post publicly.
The code worked for me once I changed it to:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void stringuniz(char *);
int *x;
int x_size = 0;
int main(){
char s[50];
int i;
puts("Unesite string brojeva u formatu br1_br2_...brN: ");
fgets(s,50,stdin);
stringuniz(s);
for(i=0;i<x_size;i++)
printf("%d\n",x[i]);
}
void stringuniz(char *s){
int duz,c=0,i,j,k=0,m=0;
char b[10];
duz=strlen(s);
for(i=0;i<duz;i++)
if(s[i]=='_')
c++;
x=malloc((c+1)*sizeof(int));
x_size = c+1;
if(x==NULL) exit(1);
for(i=0;i<=c+1;i++){
for(j=m;j<=duz;j++){
if(s[j]!='_' && s[j]!='\0'){
b[k++]=s[j];
m++;
}
else {
b[k]='\0';
x[i]=atoi(b);
k=0;
m++;
break;
}
}
}
}
void stringuniz(char *);
int *x;
int main(){
[...]
}
void stringuniz(char *s){
[...]
}
I don't know why many ppl teach it this way, but there is absolute no use in having main somewhere in the middle of a source file, and putting it at the end also allows you to get rid of the forward declarations. So, I would write it this way:
int *x;
void stringuniz(char *s){
[...]
}
int main(){
[...]
}
Then you should start using the space character more.
stringuniz(s);
for(i=0;i<(sizeof(x)/sizeof(int));i++)
printf("%d",x[i]);
In a comment, alain already pointed out, that sizeof(x) will return the size of a pointer. So, you need a different way to figure out the size of the array. One way is to add a variable size_t x_len; besides int * x;. Also, you should use curley brackets even for one line statements, believe me, not only makes it the code more readable, it also prevents introducing bugs on later changes.
for (i = 0; i < x_len; i++) {
printf("%d", x[i]);
}
.
void stringuniz(char *s){
int duz,c=0,i,j,k=0,m=0;
char b[10];
b will hold the word the user enters. If his word is longer then 9 characters, you get a buffer overflow here.
duz=strlen(s);
for(i=0;i<duz;i++)
if(s[i]=='_')
c++;
You are counting the number of words here. So, please use more descriptive names like num_words instead of c. BTW: This is the x_len mentioned above.
x=(int*)malloc((c+1)*sizeof(int));
No need to cast return value of malloc. Actually it might hide bugs. Also, I would use sizeof(*x) instead of sizeof(int), because if you change the type of x, in your statement, you also would have to change the malloc call. In my statement, the malloc call doesn't need to be touched in any way.
x = malloc((c+1) * sizeof(*x));
if(x==NULL) exit(1);
for(i=0;i<c+1;i++){
for(j=m;j<duz;j++){
if(s[j]!='_'){
b[k++]=s[j];
You are constantly overwriting b with the next word being read. Since you're not using it anyway, you can just skip this line.
m++;
}
else{
b[k]='\0';
x[i]=atoi(b);
k=0;
m++;
break;
And this break; only breaks out of the innermost for (j-loop.
}
}
}
}

Trying to write a function that get names from the user

I tried to write a function, that get a number of candidates betwen 10 to 60,000,
and gets a name for each candidate...
This is what I wrote:
/********** Headers **********/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
/********** Consts **********/
const number_candidates;
/********** Functions **********/
void get_candidates(char *arr[256][256])
{
int counter = 1, i = 0, j =0;
int temp = 0;
printf ("Please enter the number of candidates: \n");
scanf ("%d", &temp);
while (temp < 10 && temp > 60000)
{
printf ("Please enter the number of candidates: \n");
scanf ("%d", temp);
}
const number_candidates = temp;
while (counter < number_candidates + 1)
{
printf ("Please enter the %d name: \n", counter);
fgets (arr, 256, stdin);
counter++;
}
}
int main(int argc, char *argv[])
{
int i = 0;
char can_names[256][256];
get_candidates(&can_names);
system("PAUSE");
return 0;
}
There is an error in getting the names into the arr...
You should avoid using arguments like this one: char *arr[256][256] ... what's the point of it? You should think about what your function will do. You want it to load names of candidates right? So you could define struct candidate with an attribute name within it:
typedef struct candidate{
char name[256];
} Candidate;
Another thing: why are you passing an address of your array to this function? You just want your array to be filled with data, you won't work with an array itself, thus it's enough to pass an array, not an address of it.
Then prototype of your function could be changed to void get_candidates(Candidate* candidates) which is much easier to read. And look how simple can usage of this function become:
Candidate candidates[256];
get_candidates(candidates);
And last thing: before you write function like that, try something simpler first (to find out what's happening there).
Here's an example:
#include <stdio.h>
typedef struct candidate{
char name[256];
} Candidate;
void get_candidates(Candidate* candidates){
scanf("%255s", candidates[4].name);
}
int main(int argc, char *argv[]){
Candidate candidates[256];
get_candidates(candidates);
printf("%s\n", candidates[4].name);
return 0;
}
In case you don't know the count of candidates before calling get_candidates, then it's better to change the prototype of this function to Candidate* get_candidates() so that it's clear that this function creates an array:
// caller is responsible for calling free on return value
Candidate* get_candidates(){
Candidate* candidates;
int count = 50; // here you found out the count
candidates = malloc(count*sizeof(Candidate));
fgets(candidates[4].name, 255, stdin);
return candidates;
}
int main(int argc, char *argv[]){
Candidate* candidates = get_candidates();
printf("%s\n", candidates[4].name);
free(candidates);
return 0;
}
You should call:
counter = 0;...fgets (arr[counter], 256, stdin);
You need walk one step for each loop.
Have a look at the documentation for scanf which indicates that variables need to be passed as a pointer as you did the first time you call scanf. Then have a look at your second call to scanf...
You're currently only assigning names to the first string in your array over and over again. Look at that while loop and in particular, how you're passing in the 'arr' variable. Have a look here for some inspiration.
To print out all of the names you need to loop over the array. You can find some examples of printing a list of strings here and here.
A few things are wrong:
First, you need space for 60000 names, yet you only allocate enough for 256. OK, we change
char can_names[256][256];
to
char can_names[60000][256];
and get... a segmentation fault, probably. That's because the array is using too much stack space. Change it to
static char can_names[60000][256];
so it's not on the stack.
Second, there's no need to take the address of the array - it's already passed as a pointer. Your function call changes to
get_candidates(can_names);
and the function signature is
void get_candidates(char arr[60000][256])
Third, you need a loop to read the entries one at a time. A for loop is easier to read:
for (counter = 0; counter < number_candidates; counter++)
{
printf ("Please enter the %d name: \n", counter);
fgets (arr[counter], 256, stdin);
}
Fourth, the condition
while (temp < 10 && temp > 60000)
should be
while (temp < 10 || temp > 60000)
(how can a number be both less than 10 and greater than 60000?) Once this is fixed, you can remove the initial read of temp since the loop will run at least once. Note that if you type a letter instead of a number now, the program will go into an infinite loop (it will repeatedly read the letter). Fixing this is left as an exercise.
Fifth, you don't need any headers except stdio.h. Also, the i and j variables are unused.
Edit: missed the scanf error. scanf takes addresses as parameters. it makes sense too: scanf needs somewhere to store a value, it doesn't care about the current value. So the call to scanf should be:
scanf ("%d", &temp);
Don't know if this would help but have a look at the code below.
It works dynamically ie. it allocated memory for desired no of candidates rather than assuming 60,000 of them.
/*
* Write a function, that get a number of candidates betwen 10 to 60,000, and gets a name for each candidate
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 256
int main(int argc, char*argv[]){
int i,n;
char **s;
printf("Enter the total number of candidates\n");
scanf("%d",&n);
//error condition
if(n<10 || n>60000){
printf("Sorry number of candidates should be between 10 to 60,000\n");
return -1;
}
//allocate memory
s = malloc(sizeof(char*)*n);
//get the data
for(i=0;i<n;i++){
s[i] = calloc(MAX,sizeof(char));
printf("Enter the candidate number %d's name:\n",i+1);
//fgets(s[i],MAX,stdin);
scanf("%s",s[i]);
}
//Display the data
printf("\nDetails of all the Candidates\n\n");
for(i=0;i<n;i++){
printf("Candidate number %d's name:%s\n",i+1,s[i]);
}
//Free the memory
for(i=0;i<n;i++){
free(s[i]);
}
free(s);
return 0;
}
I had a problem with fgets it was skipping the first candidate info. Any help would be appreciated.. I tried flush(stdin) but did not solve the issue.

Resources