C struct value resetting to NULL - c

I'm working on a school project where I have to store PPM data into structs. I have an issue with an array of strings inside the struct.
typedef struct {
char **comments;
} PPM;
I have 3 functions that uses this struct.
PPM *getPPM() is used to get all the PPM data from file and store it into the struct
void showPPM(PPM * img) to show the image data in terminal
PPM *encode(PPM *img) which is used to change the LSB of the RGB values of the image
The problem is that getPPM works as intended and gets all the comments into the comments array in getPPM. It displays them fine if I do it like this:
PPM *p = getPPM(fin);
showPPM(p);
But if I try to call it with the encode function like this:
PPM *p = getPPM(fin);
PPM *g = encode(p);
showPPM(g);
the debugger shows that as soon as the program enters the encode function, the comments value resets to NULL even though this function doesn't even touch comments. Is the way I am calling these functions wrong or is there something wrong with my code? I will try to provide the minimal code if the problem is not the way the functions are being called, as the code is big and everything is dependent on one another.
I'm very new to C language. I tried understanding the problem for hours but can't find a solution anywhere. Any help would be greatly appreciated.
EDIT: This is as small as I could make it.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//Structures
typedef struct {
int r, g, b;
} pixels;
typedef struct {
char format[3];
char **comments;
int width, height, maxColors, commentCounter;
pixels **pixelValues;
} PPM;
// Functions declarations
PPM *getPPM(FILE * f);
PPM *encode(PPM *im, char *message, unsigned int mSize, unsigned int secret);
void showPPM(PPM * im);
static int *decimalToBinary(const char *message, unsigned int length);
// Main method
int main(int argc, char **argv) {
FILE * fin = fopen(argv[1], "r");
if(fin == NULL) {
perror("Cannot open file");
exit(1);
}
PPM *p = getPPM(fin);
PPM *g = encode(p, "test", 5, 1);
showPPM(g);
return 0;
}
/*
* This function is used to get the image data from a file and populate
* our strutures with it.
*/
PPM *getPPM(FILE * f) {
// Allocate the memory for structure and check if it was successful
PPM *pic = (PPM *) malloc(sizeof(PPM));
if(!pic) {
perror("Unable to allocate memory for structure");
exit(1);
}
char line[100]; // Expecting no more than 100 characters per line.
pic->commentCounter = 0; // This is the counter to keep size if there are more than one comments
int pixelsCounter = 0; // Counter for pixels' array
pic->comments = malloc(sizeof(char *));
pic->pixelValues = malloc(sizeof(PPM));
int lineCounter = 0;
if((pic->comments) == NULL) {
perror("Unable to allocate memory for pixels");
exit(1);
}
while(fgets(line, sizeof(line), f)) {
// Reference: https://stackoverflow.com/questions/2693776/removing-trailing-newline-character-from-fgets-input
size_t length = strlen(line);
if(length > 0 && line[length-1] == '\n') {
line[--length] = '\0';
}
// Assigning the file format
if(line[0] == 'P') {
pic->format[0] = line[0];
pic->format[1] = line[1];
pic->format[2] = '\0';
}
//Populate comments into struct PPM
if(line[0] == '#') {
// Reallocate/allocate the array size each time a new line of comment is found
if(pic->commentCounter != 0) {
pic->comments = realloc(pic->comments, (pic->commentCounter+1) * sizeof(char *));
}
// Allocate the memory for the string
pic->comments[pic->commentCounter] = malloc(100 * sizeof(char));
// Write the at commentCounter position of the array; character by character
int i = 0;
while(line[i] != '\0') {
pic->comments[pic->commentCounter][i] = line[i];
i++;
}
pic->comments[pic->commentCounter][i] = '\0';
pic->commentCounter++;
}
/*
* Loading the max color property of the file which is gonna be 3 letters (Usually 255)
* and checking if we previously got maxColors in our construct or not. If we didn't
* then we load this value into the consturct and the condition will never validate
* throughout the iterations
*/
if(strlen(line) == 3 && pic->maxColors == 0 && line[0] != '#') {
pic->maxColors = atoi(line);
continue;
}
/*
* Check if the length of string > 3, which means it is going to be a
* number, potentially RGB value or a comment. But since width & height
* comes before RGB values, our condition will fail once we have found
* the width/height for the next iteration. That's why this condition
* only checks if it is a comment or a numbered value of length > 3
*/
if((strlen(line) > 3) && (pic->width == 0) && (line[0] != '#')) {
char *width = strtok(line, " ");
char *height = strtok(NULL, " ");
pic->width = atoi(width);
pic->height = atoi(height);
continue;
}
/*
* If the width/height and maxColors have been found, that means every
* other line is either going to be the RGB values or a comment.
*/
if((pic->width != 0) && (pic->maxColors != 0) && (line[0] != '#')) {
// length(line) > 3 means all the RGB values are in same line
if(strlen(line) > 3) {
char *val1 = strtok(line, " ");
char *val2 = strtok(NULL, " ");
char *val3 = strtok(NULL, " ");
// pixelsCounter = 0 means it's the first element.
if(pixelsCounter != 0) {
// Reallocate memory each time a new R G B value line is found
pic->pixelValues = realloc(pic->pixelValues, (pixelsCounter + 1) * sizeof(PPM));
}
pic->pixelValues[pixelsCounter] = malloc(12 * sizeof(pixels));
pic->pixelValues[pixelsCounter]->r = atoi(val1);
pic->pixelValues[pixelsCounter]->g = atoi(val2);
pic->pixelValues[pixelsCounter]->b = atoi(val3);
pixelsCounter++;
} else if(strlen(line) <= 3) {
/*
* If each individual RGB values are in a separete lines, we will
* use a switch case and a line counter to keep track of where the
* values were inserted and when to know when we got RGB values for
* one pixel
*/
if(pixelsCounter != 0 && lineCounter == 0) {
// Reallocate memory each time a new R G B value line is found
pic->pixelValues = realloc(pic->pixelValues, (pixelsCounter + 1) * sizeof(PPM));
}
switch(lineCounter) {
case 0 :
pic->pixelValues[pixelsCounter] = malloc(12 * sizeof(pixels));
pic->pixelValues[pixelsCounter]->r = atoi(line);
lineCounter++;
continue;
case 1 :
pic->pixelValues[pixelsCounter]->g = atoi(line);
lineCounter++;
continue;
case 2 :
pic->pixelValues[pixelsCounter]->b = atoi(line);
lineCounter=0;
pixelsCounter++;
continue;
default:
continue;
}
}
}
}
pic->pixelValues[pixelsCounter] = NULL;
fclose(f);
return pic;
}
void showPPM(PPM * im) {
printf("%s\n",im->format);
int k = 0;
while(k < im->commentCounter) {
printf("%s\n", im->comments[k]);
k++;
}
printf("%d %d\n", im->width, im->height);
printf("%d\n",im->maxColors);
int j = 0;
while(im->pixelValues[j] != NULL) {
printf("%d %d %d\n", im->pixelValues[j]->r, im->pixelValues[j]->g, im->pixelValues[j]->b);
j++;
}
}
PPM *encode(PPM *im, char *message, unsigned int mSize, unsigned int secret) {
int *binaryMessage = decimalToBinary(message, mSize);
int i, j = 0, lineCounter = 0;
for(i = 0; i < 40; i++) {
switch(lineCounter) {
case 0 :
im->pixelValues[j]->r |= binaryMessage[i] << 0;
lineCounter++;
continue;
case 1 :
im->pixelValues[j]->g |= binaryMessage[i] << 0;
lineCounter++;
continue;
case 2 :
im->pixelValues[j]->b |= binaryMessage[i] << 0;
lineCounter=0;
j++;
continue;
default:
continue;
}
}
return im;
}
/*
* Converts a string into binary to be used in encode function. It
* first converts each letter of the string into ascii code. Then
* finds and stores each of the 8 bits of that int (ascii code of
* the letter) sequentially in an array.
*/
static int *decimalToBinary(const char *message, unsigned int length) {
/*
* malloc is used here instead of [] notation to allocate memory,
* because defining the variable with [] will make its scope
* limited to this function only. Since we want to access this
* array later on, we use malloc to assign space in the memory
* for it so we can access it using a pointer later on.
*/
int k=0, i, j;
unsigned int c;
unsigned int *binary = malloc(8 * length);
for(i = 0; i < length; i++) {
c = message[i];
for(j = 7; j >= 0; j--,k++) {
/*
* We check here if the jth bit of the number is 1 or 0
* using the bit operator &. If it is 1, it will return
* 1 because 1 & 1 will be true. Otherwise 0.
*/
if((c >> j) & 1)
binary[k] = 1;
else
binary[k] = 0;
}
}
return binary;
}
PPM file:
P3
# CREATOR: GIMP PNM Filter Version 1.1
# Amazing comment 2
# Yet another amazing comment
400 530
255
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0
0 0 0

in decimalToBinar
unsigned int *binary = malloc(8 * length);
must be
unsigned int *binary = malloc(8 * length * sizeof(int));
new code is :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//Structures
typedef struct {
int r, g, b;
} pixels;
typedef struct {
char format[3];
char **comments;
int width, height, maxColors, commentCounter;
pixels **pixelValues;
} PPM;
// Functions declarations
PPM *getPPM(FILE * f);
PPM *encode(PPM *im, char *message, unsigned int mSize, unsigned int secret);
void showPPM(PPM * im);
static int *decimalToBinary(const char *message, unsigned int length);
// Main method
int main(int argc, char **argv) {
FILE * fin = fopen(argv[1], "r");
if(fin == NULL) {
perror("Cannot open file");
exit(1);
}
PPM *p = getPPM(fin);
PPM *g = encode(p, "test", 5, 1);
showPPM(g);
free(p->comments);
free(p);
return 0;
}
/*
* This function is used to get the image data from a file and populate
* our strutures with it.
*/
PPM *getPPM(FILE * f) {
// Allocate the memory for structure and check if it was successful
PPM *pic = (PPM *) malloc(sizeof(PPM));
if(!pic) {
perror("Unable to allocate memory for structure");
exit(1);
}
char line[100]; // Expecting no more than 100 characters per line.
pic->commentCounter = 0; // This is the counter to keep size if there are more than one comments
int pixelsCounter = 0; // Counter for pixels' array
pic->comments = malloc(sizeof(char *));
pic->pixelValues = malloc(sizeof(PPM));
int lineCounter = 0;
if((pic->comments) == NULL) {
perror("Unable to allocate memory for pixels");
exit(1);
}
pic->width = 0;
pic->height = 0;
pic->maxColors = 0;
while(fgets(line, sizeof(line), f)) {
// Reference: https://stackoverflow.com/questions/2693776/removing-trailing-newline-character-from-fgets-input
size_t length = strlen(line);
if(length > 0 && line[length-1] == '\n') {
line[--length] = '\0';
}
// Assigning the file format
if(line[0] == 'P') {
pic->format[0] = line[0];
pic->format[1] = line[1];
pic->format[2] = '\0';
}
//Populate comments into struct PPM
if(line[0] == '#') {
// Reallocate/allocate the array size each time a new line of comment is found
if(pic->commentCounter != 0) {
pic->comments = realloc(pic->comments, (pic->commentCounter+1) * sizeof(char *));
}
// Allocate the memory for the string
pic->comments[pic->commentCounter] = malloc(100 * sizeof(char));
// Write the at commentCounter position of the array; character by character
int i = 0;
while(line[i] != '\0') {
pic->comments[pic->commentCounter][i] = line[i];
i++;
}
pic->comments[pic->commentCounter][i] = '\0';
pic->commentCounter++;
}
/*
* Loading the max color property of the file which is gonna be 3 letters (Usually 255)
* and checking if we previously got maxColors in our construct or not. If we didn't
* then we load this value into the consturct and the condition will never validate
* throughout the iterations
*/
if(strlen(line) == 3 && pic->maxColors == 0 && line[0] != '#') {
pic->maxColors = atoi(line);
continue;
}
/*
* Check if the length of string > 3, which means it is going to be a
* number, potentially RGB value or a comment. But since width & height
* comes before RGB values, our condition will fail once we have found
* the width/height for the next iteration. That's why this condition
* only checks if it is a comment or a numbered value of length > 3
*/
if((strlen(line) > 3) && (pic->width == 0) && (line[0] != '#')) {
char *width = strtok(line, " ");
char *height = strtok(NULL, " ");
pic->width = atoi(width);
pic->height = atoi(height);
continue;
}
/*
* If the width/height and maxColors have been found, that means every
* other line is either going to be the RGB values or a comment.
*/
if((pic->width != 0) && (pic->maxColors != 0) && (line[0] != '#')) {
// length(line) > 3 means all the RGB values are in same line
if(strlen(line) > 3) {
char *val1 = strtok(line, " ");
char *val2 = strtok(NULL, " ");
char *val3 = strtok(NULL, " ");
// pixelsCounter = 0 means it's the first element.
if(pixelsCounter != 0) {
// Reallocate memory each time a new R G B value line is found
pic->pixelValues = realloc(pic->pixelValues, (pixelsCounter + 1) * sizeof(PPM));
}
pic->pixelValues[pixelsCounter] = malloc(12 * sizeof(pixels));
pic->pixelValues[pixelsCounter]->r = atoi(val1);
pic->pixelValues[pixelsCounter]->g = atoi(val2);
pic->pixelValues[pixelsCounter]->b = atoi(val3);
pixelsCounter++;
} else if(strlen(line) <= 3) {
/*
* If each individual RGB values are in a separete lines, we will
* use a switch case and a line counter to keep track of where the
* values were inserted and when to know when we got RGB values for
* one pixel
*/
if(pixelsCounter != 0 && lineCounter == 0) {
// Reallocate memory each time a new R G B value line is found
pic->pixelValues = realloc(pic->pixelValues, (pixelsCounter + 1) * sizeof(PPM));
}
switch(lineCounter) {
case 0 :
pic->pixelValues[pixelsCounter] = malloc(12 * sizeof(pixels));
pic->pixelValues[pixelsCounter]->r = atoi(line);
lineCounter++;
continue;
case 1 :
pic->pixelValues[pixelsCounter]->g = atoi(line);
lineCounter++;
continue;
case 2 :
pic->pixelValues[pixelsCounter]->b = atoi(line);
lineCounter=0;
pixelsCounter++;
continue;
default:
continue;
}
}
}
}
pic->pixelValues[pixelsCounter] = NULL;
fclose(f);
return pic;
}
void showPPM(PPM * im) {
printf("%s\n",im->format);
int k = 0;
while(k < im->commentCounter) {
printf("%s\n", im->comments[k]);
k++;
}
printf("%d %d\n", im->width, im->height);
printf("%d\n",im->maxColors);
int j = 0;
while(im->pixelValues[j] != NULL) {
printf("%d %d %d\n", im->pixelValues[j]->r, im->pixelValues[j]->g, im->pixelValues[j]->b);
j++;
}
}
PPM *encode(PPM *im, char *message, unsigned int mSize, unsigned int secret) {
int *binaryMessage = decimalToBinary(message, mSize);
int i, j = 0, lineCounter = 0;
for(i = 0; i < 40; i++) {
switch(lineCounter) {
case 0 :
im->pixelValues[j]->r |= binaryMessage[i] << 0;
lineCounter++;
continue;
case 1 :
im->pixelValues[j]->g |= binaryMessage[i] << 0;
lineCounter++;
continue;
case 2 :
im->pixelValues[j]->b |= binaryMessage[i] << 0;
lineCounter=0;
j++;
continue;
default:
continue;
}
}
free(binaryMessage);
return im;
}
/*
* Converts a string into binary to be used in encode function. It
* first converts each letter of the string into ascii code. Then
* finds and stores each of the 8 bits of that int (ascii code of
* the letter) sequentially in an array.
*/
static int *decimalToBinary(const char *message, unsigned int length) {
/*
* malloc is used here instead of [] notation to allocate memory,
* because defining the variable with [] will make its scope
* limited to this function only. Since we want to access this
* array later on, we use malloc to assign space in the memory
* for it so we can access it using a pointer later on.
*/
int k = 0, i, j;
unsigned int c;
unsigned int *binary = malloc(8 * length * sizeof(int));
for(i = 0; i < length; i++) {
c = message[i];
for(j = 7; j >= 0; j--,k++) {
/*
* We check here if the jth bit of the number is 1 or 0
* using the bit operator &. If it is 1, it will return
* 1 because 1 & 1 will be true. Otherwise 0.
*/
if((c >> j) & 1)
binary[k] = 1;
else
binary[k] = 0;
}
}
return binary;
}

Related

get line in the text for each word

The following program prints the word frequency in a file. I am trying to save for each word in the text file, which line/lines appeared and how many times in total in the whole file. It counts how many times it appeared but I can't get which lines of the txt file.
There is a problem with int lines[]. The ouput of the program gives
segmentation fault
#define MAXWORDS 10000
#define MAXSTRING 100
/* structure holding word frequency information */
typedef struct _word {
char s[MAXSTRING]; /* the word */
int count; /* number of times word occurs */
int lines[1000];
} word;
void insert_word (word *words, int *n, char *s, int no) {
int i;
/* linear search for the word */
for (i=0; i<*n; i++) if (strcmp (s, words[i].s) == 0) {
/* found it? increment and return. */
words[i].count++;
words[i].lines[words[i].count]=no;
printf("%d", no);
return;
}
/* error conditions... */
if (strlen (s) >= MAXSTRING) {
fprintf (stderr, "word too long!\n");
exit (1);
}
if (*n >= MAXWORDS) {
fprintf (stderr, "too many words!\n");
exit (1);
}
/* copy the word into the structure at the first available slot,
* i.e., *n
*/
strcpy (words[*n].s, s);
/* this word has occured once up to now, so count = 1 */
words[*n].count = 1;
words[*n].lines[words[*n].count]=no;
/* one more word */
(*n)++;
}
...........
int main () {
word words[MAXWORDS];
char s[1000];
int i, n, m;
n = 0;
FILE* file = fopen("test.txt", "r");
/* read all the words in the file... */
int no=1;
while (fgets(s, sizeof(s), file)) {
scanf ("%s", s);
insert_word (words, &n, s,no);
no=no+1;
}
}
fclose(file);
qsort((void *) words, n, sizeof (word),
(int (*) (const void *, const void *)) wordcmp);
if (n < 20)
m = n;
else
m = 20;
for (i=0; i<m; i++)
printf ("%s\t[%d] {%d} \n", words[i].s, words[i].count, words[i].lines);
}
Here's a solution with dynamic memory allocation:
typedef struct _word {
char *s; /* the word */
int count; /* number of times word occurs */
int *line_numbers; // Array of line numbers
int num_line_numbers; // Size of the array of line numbers
} word;
// Creating a struct to hold the data. I find it's easier
typedef struct {
word *words; // The array of word structs
int num_words; // The size of the array
} word_list;
void insert_word (word_list *words, char *s, int line_number)
{
/* linear search for the word */
for (int i = 0; i < words->num_words; i++) {
if (strcmp (s, words->words[i].s) == 0) {
/* found it? increment and return. */
words->words[i].count++;
// See if it already appeared in this line
if (words->words[i].line_numbers[words->words[i].num_line_numbers - 1] == line_number) {
return;
}
// New line number. Increase the line number array by one
int *tmp = realloc(words->words[i].line_numbers, sizeof(int) * (words->words[i].num_line_numbers + 1));
if (NULL == tmp) exit(0);
words->words[i].line_numbers = tmp;
// Add the line number to the array
words->words[i].line_numbers[words->words[i].num_line_numbers] = line_number;
words->words[i].num_line_numbers += 1;
return;
}
}
/* error conditions... */
....
// Increase the size of the word array by one.
word *tmp = realloc(words->words, sizeof(word) * (words->num_words + 1));
if (tmp == NULL) exit(0);
words->words = tmp;
/* copy the word into the structure at the first available slot,
* i.e., *n
*/
words->words[words->num_words].s = malloc(strlen(s) + 1);
strcpy(words->words[words->num_words].s, s);
/* this word has occurred once up to now, so count = 1 */
words->words[words->num_words].count = 1;
words->words[words->num_words].line_numbers = malloc(sizeof(int));
words->words[words->num_words].line_numbers[0] = line_number;
words->words[words->num_words].num_line_numbers = 1;
words->num_words += 1;
}
bool remove_word(word_list *words, const char *word_to_delete)
{
for (int i = 0; i < words->num_words; i++) {
if (0 == strcmp(words->words[i].s, word_to_delete)) {
// TODO: handle special case where there is only 1 word in list
// Calc number of words after found word
int number_of_words_to_right = words->num_words - i - 1;
// Free mem
free(words->words[i].s);
free(words->words[i].line_numbers);
// Copy remaining words
memcpy(&words->words[i], &words->words[i + 1], sizeof(word) * number_of_words_to_right);
// Resize the array (technically not required)
word *tmp = realloc(words->words, sizeof(word) * --words->num_words);
if (NULL == tmp) exit(0);
words->words = tmp;
return true;
}
}
return false;
}
And in main()
word_list *words = malloc(sizeof(word_list));
if (NULL == words) exit(0);
memset(words, 0, sizeof(word_list));
....
/* read all the words in the file... */
char s[1000];
int line_number = 1;
while (fgets(s, sizeof(s), file)) {
char *word = strtok(s, " ");
while (word != NULL) {
size_t len = strlen(word);
if (len > 0 && word[len - 1] == '\n') word[--len] = 0;
insert_word(words, word, line_number);
word = strtok(NULL, " ");
}
line_number += 1;
}
fclose(file);
for (int i = 0; i < words->num_words; i++) {
printf("%s\t\t[%d] {", words->words[i].s, words->words[i].count);
for (int j = 0; j < words->words[i].num_line_numbers; j++) {
if (j != 0) printf(",");
printf("%d", words->words[i].line_numbers[j]);
}
printf("}\n");
}
// It's good practice to always free mem. It's super not important
// in this app since the OS will do it when you exit
for (int i = 0; i < words->num_words; i++) {
free(words->words[i].s);
free(words->words[i].line_numbers);
}
free(words->words);
free(words);

multiple line inputs in C

I have to do the following things for my project
eg given an input such as
9 3 2 5
6 3 4 6 1
9 5 0 4 3 1
I will need to do the following things
i)divide the input in separate sets according to each line such as
set1={9,3,2,5)
set2={6,3,4,6,1}
set3={9,5,0,4,3,1}
ii)I will also need the individual elements in each set(such as 9,3,2,5 in set 1) as integers for further processing
notes:I am not allowed to give the input in a separate file so I tried entering as
"9 3 2 5\n6 3 4 6 1\n9 5 0 4 3 1"as pressing the enter after each line won't do as I will be required to give the full input in one go
Also I am required to use ONLY C
Any ideas to implement the above will be appreciated
Thank you for your help.
You can use fgets() to read the lines, and then strtok() to parse each line, this is a sample program, i've used the first element of the integer array as the array count, so you don't need to store it in a separate variable, I did that because I assume you can have different length arrays.
int freeArray(int **array, int setCount)
{
if (array == NULL)
return 0;
while (setCount > 0)
free(array[--setCount]);
free(array);
return -1;
}
void printArray(int *const *const array, int setCount)
{
int i;
for (i = 0 ; i < setCount ; ++i)
{
const int *pointer;
int j;
pointer = array[i];
if (pointer == NULL)
continue;
for (j = 1 ; j <= pointer[0] ; j++)
printf("%d ", pointer[j]);
printf("\n");
}
}
int *parseLine(char *line, int setCount)
{
char *pointer;
int count;
char *token;
int *array;
while ((*line != '\0') && (isspace(*line) != 0))
line++;
if (*line == '\0')
return NULL;
array = NULL;
pointer = line;
count = 0;
while ((token = strtok(pointer, " ")) != NULL)
{
char *endptr;
void *tmp;
pointer = NULL;
tmp = realloc(array, (1 + ++count) * sizeof(int));
if (tmp == NULL)
{
free(array);
return NULL;
}
array = tmp;
array[0] = count;
array[count] = strtol(token, &endptr, 10);
if ((*endptr != '\0') && ((*endptr != '\n')))
fprintf(stderr, "error: the %dth %s: value of the %dth line, is not an integer\n",
count, token, setCount);
}
return array;
}
int main(int argc, char **argv)
{
char line[256];
int **array;
int setCount;
line[0] = '\0';
array = NULL;
setCount = 0;
while (line[0] != '\n')
{
void *tmp;
if (fgets(line, sizeof(line), stdin) == NULL)
return -1;
tmp = realloc(array, (1 + setCount) * sizeof(int *));
if (tmp == NULL)
return freeArray(array, setCount);
array = tmp;
array[setCount] = parseLine(line, setCount);
if (array[setCount] != NULL)
setCount += 1;
}
printArray(array, setCount);
freeArray(array, setCount);
return 0;
}
at the end I show you how to access the elements of the array of arrays by printing them, and also how to free the malloced memory.
This program will exit when you press enter, but if you type a space before pressing enter, there will be problems, I'll let you think about a solution to that.

Creating array to hold 1000000 numbers

I wrote a code in C that read a text file with numbers into memory and the create an 2d int array to store them.
The file has the following format:
9
9 5 6 2235 45558 6 5544 56565 2
The first number is the size of the array and the second line holds as many numbers as the first line says.
MY problem is that the size of the array can't hold more than ~30.000 numbers. How can I make the following code so I can make the array hold until 1.000.000 numbers? I know that I should use some king of long integer but I couldn't do it.
Heres the code
#include <stdio.h>
#include <stdlib.h>
int is_end(char* input) {
return *input == 0;
}
int is_separator(char* input) {
return *input == '\n' || *input == ' ';
}
char* eat_separators(char* input) {
while (is_separator(input))
++input;
return input;
}
size_t count_lines(char* input) {
size_t rows = 1;
while (!is_end(input)) {
if (is_separator(input)) {
++rows;
input = eat_separators(input);
}
else {
++input;
}
}
return rows;
}
char** get_lines(char* input, size_t number_of_rows) {
char* from = input;
size_t length = 0;
size_t line = 0;
size_t i;
char** lines = (char**)malloc(number_of_rows * sizeof(char*));
do {
if (is_end(input) || is_separator(input)) {
lines[line] = (char*)malloc(length + 1);
for (i = 0; i < length; ++i)
lines[line][i] = *(from + i);
lines[line][length] = 0;
length = 0;
++line;
input = eat_separators(input);
from = input;
}
else {
++length;
++input;
}
} while (!is_end(input));
/*
lines[line] = (char*)malloc(length + 1);
for (i = 0; i < length; ++i)
lines[line][i] = *(from + i);
lines[line][length] = 0;
++line; */
return lines;
}
int main(int argc, char* argv[]) {
char** lines;
size_t size;
size_t number_of_rows;
int count;
int* children;
FILE *input, *output;
char *contents;
int fileSize = 0;
int i;
input = fopen("xxx.in", "r");
long int filepos = 0L;
fseek(input, 0L, SEEK_END);
fileSize = ftell(input);
fseek(input, 0L, SEEK_SET);
contents = (char*)malloc(fileSize + 1);
size = fread(contents, 1, fileSize, input);
contents[size] = 0;
fclose(input);
number_of_rows = count_lines(contents);
lines = get_lines(contents, number_of_rows);
if ((count = atoi(lines[0])) <= 0 || count > 1000000){
return 1;
}
children = (int*)malloc(count * sizeof(int));
for (i = 0; i < count; ++i) {
if ((children[i] = atoi(lines[i + 1])) <= 0 )
return(-1);
}
// a check to see if everything stored in the array
for(i = 0;i<count;i++)
{
printf(" %d : %d\n", i, children[i]);
}
free(children);
free(lines);
// This is the end! Oh my dear friend, the end!
return 0;
}
First Let me explaint the reason of having only 30.000 number that will give reply to your question?
Basically you are trying to convert the character to ASCII values. Let us take the example of character x whos ASCII value is 120. You are changing the character x with 120, the storage capacity of x is 1 byte but the storage capacity of 120 is 3 bytes. So, basically you have to do memory allocation of 3 times higher the actual value computed as 1 byte is expanding into 3 bytes.
In Your code increase the memory allocation 3 times then your problem would be solved.

When open the files and assignment to char ,Incompatible Types error

I'm trying to find sum of large numbers.(100-digit,1500-digit)
There is my sum function:
char *find_sum(char *a, char *b) {
char *res;
int alen, blen, rlen;
int carry;
alen = strlen(a);
blen = strlen(b);
rlen = 1 + ((alen > blen) ? alen : blen);
res = malloc(1 + rlen);
if (res) {
int oldlen = rlen;
res[rlen] = 0;
carry = 0;
while (rlen) {
int tmp;
if (alen && blen) tmp = a[--alen] - '0' + b[--blen] - '0';
else if (alen) tmp = a[--alen] - '0';
else if (blen) tmp = b[--blen] - '0';
else tmp = 0;
tmp += carry;
res[--rlen] = '0' + tmp % 10;
carry = tmp / 10;
}
if (res[0] == '0') memmove(res, res+1, oldlen);
}
return res;
}
If I'm try to like below, code is working:
char a[] = "243432423423423";
char b[] = "74356348775345";
char *c;
c = find_sum(a,b);
printf("%s",c);
But I want to these numbers(a and b) get from a file(by line).For example my data.txt has below lines:
7326473264723672364723864762374236
32473264623748632784632784
432423432423423423
0
3248972389473289473289478923
4897238473247382
732468723647236478238423
0
432748932489327894723894798239
48327489237483278
0
32423423423423
I want to open this file, read each line and sum of all numbers(stopped if reach 0 and write other file sum.txt)
If I try to addition values from files using fgets, I take the incompatible types error.
My testing code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *find_sum(char *a, char *b);
int main(int argc, const char *argv[])
{
FILE *file;
file = fopen("a.txt", "r");
if (file != NULL){
char *buf;
char *buf1;
char *sum;
fgets(buf, 100, file);
fgets(buf1, 100, file);
sum = find_sum(buf, buf1);
printf("%s",sum);
}
fclose(file);
return 0;
}
char *find_sum(char *a, char *b) {
char *res;
int alen, blen, rlen;
int carry;
alen = strlen(a);
blen = strlen(b);
rlen = 1 + ((alen > blen) ? alen : blen);
res = malloc(1 + rlen);
if (res) {
int oldlen = rlen;
res[rlen] = 0;
carry = 0;
while (rlen) {
int tmp;
if (alen && blen) tmp = a[--alen] - '0' + b[--blen] - '0';
else if (alen) tmp = a[--alen] - '0';
else if (blen) tmp = b[--blen] - '0';
else tmp = 0;
tmp += carry;
res[--rlen] = '0' + tmp % 10;
carry = tmp / 10;
}
if (res[0] == '0') memmove(res, res+1, oldlen);
}
return res;
}
I gess you are gettign this error
36 D:\Projects\c_c++\so\find_sum\main.cpp invalid conversion from `void*' to `char*'
at the line
res = malloc(1 + rlen);
malloc returns void* witch yo need to cast to the type for witch you are allocating the memory. to get rid of this error add a type cats this way
res = (char*) malloc(1 + rlen);
your code will compile then.
EDIT
Read numbers from file and write result of addition to another output file
Basically you will need to that in a loop, read two operands and make the addition, since you have to stop adding only after you have found a line containing a "0" or you have reached EOF, you'll have to read the next operand in the next loop and add the sum from previous loop to it then store the result back to the sum. after you have reached "0" or EOF write the file sum to the output file.
an other alternative would be to read all numbers into an array of strings till you reach "0" or EOF in one step, an in the next step you iterate over all numbers red, compute the sum and then write it to the output file.
here is a sample implementation for the first solution
int main(int argc, const char *argv[])
{
char buf[100] = "";
FILE *input_file = fopen("a.txt", "r");
if (input_file) {
FILE *output_file = fopen("r.txt", "w");
if(output_file) {
char *op1 = NULL, *op2 = NULL, *sum = NULL, *p_buf = NULL;
do {
// if we alredy have done an additin, copy (flat) that result to op1
if(sum) {
printf("have sum %s\n", sum);
op1 = sum;
}
// if op1 does not point to a sum from previous addition, then attemp to read it from file
if(! op1) {
// read next operand and escape all "0"
do {
p_buf = fgets(buf, 100, input_file);
remove_new_line_ending(p_buf, buf);
} while(p_buf && 0 == strcmp(p_buf, "0"));
if(p_buf) {
printf("read op1 %s\n", buf);
op1 = strdup(buf);
sum = op1;
}
}
// read next operand
p_buf = fgets(buf, 100, input_file);
remove_new_line_ending(p_buf, buf);
if(p_buf && 0 != strcmp(p_buf, "0")) {
printf("read op2 %s\n", buf);
op2 = strdup(buf);
}
// we have both op1 and op2 then make the addition
if(op1 && op2) {
printf("have op1 and op2 %s\n", "");
sum = find_sum(op1, op2);
} else {
if(sum) {
// if we have only op1 then it is the result from the previous addion and there is no operand left in the file
// then write the result to output file and reset all variables
printf("print sum %s to output file\n\n", sum);
fprintf(output_file, "%s\n0\n", sum);
free(sum);
sum = NULL;
}
}
free(op1);
free(op2);
op1 = NULL;
op2 = NULL;
} while(p_buf);
fclose(output_file);
} else {
perror("r.txt");
}
fclose(input_file);
} else {
perror("a.txt");
}
return 0;
}
void remove_new_line_ending(char* line, char dest[])
{
if(line) {
int len = strlen(line);
int i = 0;
while(i < len && line[i] != '\r' && line[i] != '\n') {
dest[i] = line[i];
i++;
}
dest[i] = '\0';
}
}
Input
0
0
7326473264723672364723864762374236
32473264623748632784632784
432423432423423423
0
0
0
3248972389473289473289478923
4897238473247382
732468723647236478238423
0
0
432748932489327894723894798239
48327489237483278
0
32423423423423
0
0
Output
7326473297196937420895929970430443
0
3249704858201833948240964728
0
432748932489376222213132281517
0
32423423423423
0
You should declare your variables at the beginning of the main function (not inside a conditional), and you must allocate memory to them. The easiest way to do this would be to declare them as
int main(int argc, const char *argv[])
{
char buf[100];
char buf1[100];

Allocation - pointer-to-pointer

I would like to ask for help with allocation .... I got this homework to school...I have to write program which will load one G matrix and second G matrix and will search second G matrix for number of presences of the first G matrix....But, when I try to run my program I got Segmentation fault message... Thanks in advance.
Example how the program is supposed to work....
...
Enter number of lines of wanted g matrix:
3
Enter the wanted g matrix:
121212
212121
121212
G matrix to be searched:
12121212121212
21212121212121
12121212123212
21212121212121
12121212121212
G matrix found 8 times.
...
this is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * get_line(void) // get line
{
char * string;
if((string = (char *)malloc(100 * sizeof(char))) == NULL)
{
printf("Nedostatek pameti.\n"); // not enough memory
exit(1);
}
int i = 0;
while((string[i] = fgetc(stdin)) != '\n')
{
i++;
if((i % 100) == 0)
{
if((string = (char *)realloc(string, 100 * ( i - 1 ) * sizeof(char))) == NULL)
{
printf("Nedostatek pameti.\n"); // not enough memory
exit(1);
}
}
}
return ( string );
}
char ** get_wanted_g_matrix(int pocetradek /*number of lines*/) // get wanted g matrix
{
char ** string;
printf("Zadejte hledanou matici:\n");
int i = 0;
if(( * string = (char ** )malloc(100 * sizeof(char *))) == NULL)
{
printf("Nedostatek pameti.\n"); // not enough memory
exit(1);
}
while(i <= (pocetradek - 1))
{
string[i] = get_line();
if((i > 1) && (*string[i-1] != strlen(*string[i])))
{
printf("Nespravny vstup.\n"); // not enough memory
exit(1);
}
printf("%s", string[i]);
i++;
if((i % 100) == 0)
{
if((* string = (char **)realloc(* string, 100 * ( i - 1 ) * sizeof(char *))) == NULL)
{
printf("Nedostatek pameti.\n"); // not enough memory
exit(1);
}
}
}
return (string);
}
int get_number_of_lines(void) // get number of lines
{
int number_of_lines;
printf("Zadejte pocet radek hledane matice:\n"); // enter the number of lines of wanted g matrix
if(scanf("%d", &number_of_lines) != 1)
{
printf("Nespravny vstup.\n"); // Error
exit(1);
}
return ( number_of_lines );
}
char ** get_searched_g_matrix(void) // get wanted g matrix
{
char ** string;
printf("Matice, ktera bude prohledana:\n"); // G matrix to be searched
int i = 0;
if(( * string = (char ** )malloc(100 * sizeof(char *))) == NULL)
{
printf("Nedostatek pameti.\n"); // not enough memory
exit(1);
}
while(!feof(stdin))
{
string[i] = get_line();
if((i > 1) && (*string[i-1] != strlen(*string[i])))
{
printf("Nespravny vstup.\n"); // error
exit(1);
}
printf("%s", string[i]);
i++;
if((i % 100) == 0)
{
if((* string = (char **)realloc(* string, 100 * ( i - 1 ) * sizeof(char *))) == NULL)
{
printf("Nedostatek pameti.\n"); // not enough memory
exit(1);
}
}
}
if(feof(stdin))
{
return string;
}
}
int search( char ** string1, char ** string2 ) // search
{
int string1width = strlen(*string1[0]);
int string2width = strlen(*string2[0]);
int string2height = strlen(**string2);
int number_of_lines = get_number_of_lines();
unsigned int g = 0, h = 0, i2, j2, l = 0, i = 0, j;
while( i <= (string2height - 2) )
{
j = 0;
while( j <= string2width - 2 )
{
g = 0; h = 0;
if(string2[i][j] == string1[g][h])
{
i2 = i;
while((g <= number_of_lines - 1) && (i2 <= string2height - 2))
{
j2 = j; h = 1;
while(((string2[i2][j2] == string1[g][h]) && (j2 <= string2height - 2)) && (h <= string1width - 2))
{
j2++;
h++;
}
if(h != string1width - 1)
{
break;
}
if(g == number_of_lines - 1)
{
l++;
break;
}
i2++;
g++;
}
}
j++;
}
i++;
}
return ( l );
}
int main(void)
{
char ** string1;
char ** string2;
int number_of_lines = get_number_of_lines();
string1 = get_wanted_g_matrix(number_of_lines);
string2 = get_searched_g_matrix();
if(feof(stdin))
{
printf("Matice nalezena %d krat.\n", search( ** string1, **string2 )); // G matrix found %d times.
}
return 0;
}
In this code:
char ** get_wanted_g_matrix(int pocetradek /*number of lines*/) // get wanted g matrix
{
char ** string;
printf("Zadejte hledanou matici:\n");
int i = 0;
if(( * string = (char ** )malloc(100 * sizeof(char *))) == NULL)
You dereference string, but it is uninitialized, so you're writing to a random location in memory. Change that * string to just string. The same applies here:
if((* string = (char **)realloc(* string, 100 * ( i - 1 ) * sizeof(char *))) == NULL)
..and to the corresponding lines in get_searched_g_matrix() as well.
In this line:
if((i > 1) && (*string[i-1] != strlen(*string[i])))
You're passing a char to strlen(), when you should be passing a char *. I suspect you mean just strlen(string[i]), but that line seems somewhat nonsensical. The same problem is in get_searched_g_matrix() as well, as well as the first three calls to strlen() in search().
Your get_searched_g_matrix() can fall off the end without returning a value - you need to consider what to return if feof(stdin) is not true.
In main(), your call to search() passes char values, but the function expects char **. You probably mean:
printf("Matice nalezena %d krat.\n", search( string1, string2 ));
(The above won't be sufficient to fix your code - you also appear to have some logic problems. But it's a necessary start.)
In future, you should compile your code with a higher level of warnings enabled, then fix the problems that the compiler identifies (if you're using gcc, compile with -Wall).
Just some comments and style hints:
I'd say it's quite large for what it should do (and hard to follow), try simplifying it a bit.
1) Save vertical space, most people nowadays have wide screens, and it's quite annoing when you can't see the corresponding closing bracket.
1.1) It's very good that you check for error conditions, but try using something like
void err(const char* msg){
printf("\n\nFATAL ERROR: %s\n", msg);
exit(1);
};
so that you can do
if (!(x = malloc(sz)))
err("Not enough memory!");
1.2) While it's considered safer to use brackets for a signle statement in if, I'd suggest avoiding them when possible, or at least use fewer newlines. Brackets are for compiler, people preffer tabs.
2) There are several while statements in your search function that should be written as fors.
3) Why would you need two distinct functions to read the matrices? One would be enough.
4) As #caf pointed out, you have also errors in input functions. Test each function before going further. It takes years of experience before you can write the whole program at once.

Resources