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.
Related
My code for dynamically allocating arrays, even though the Input methods for both arrays pattern and text are same text outputs different values, can anyone solve this issue?
#include<stdio.h>
#include<stdlib.h>
int main() {
int length=5;
int * pattern = malloc(length * sizeof(int));
int * text = malloc(length * sizeof(int));
int pattern_size=0;
int text_size=0;
printf("Enter Pattern:");
char c;
while(c != '$' && scanf("%c",&c) != '\n'){
if(pattern_size >= length)
pattern = realloc(pattern, (length += 10) * sizeof(int));
if(c!=',') pattern[pattern_size] = atoi(&c)+pattern[pattern_size]*10;
else if(c==',') {
pattern_size++;
}
}
printf("\nPlease enter the replacement text:");
// get_array(text,&text_size,length);
char d;
while(d != '$' && scanf("%c",&d) != '\n'){
if(text_size >= length)
text = realloc(text, (length += 10) * sizeof(int));
if(d!=',') text[text_size] = atoi(&d)+text[text_size]*10;
else if(d==',') {
text_size++;
}
}
for(int i=0;i<pattern_size; i++){
printf("%d ",pattern[i]);
}
printf("\n");
for(int i=0;i<text_size; i++){
printf("%d ",text[i]);
}
printf("\n");
return 0;
}
Input
Enter Pattern:1,2,3,4,5,6,7,8,9,0,$
Please enter the replacement text:1,2,3,4,5,6,7,8,9,0,$
OUTPUT
1 2 3 4 5 6 7 8 9 0
1 2 3 4 5 6 10417 8 540155953 540287027
You should ever check the return value of malloc and scanf.
Scanf does not return the element scanned. Please check man 3 scanf
On success, these functions return the number of input items
successâ fully matched and assigned; this can be fewer than
provided for, or even zero, in the event of an early matching
failure. The value EOF is returned if the end of input is reached
before either the first successful conversion or a matching
failure occurs. EOF is also returned if a read error occurs, in
which case the error indicator for the stream (see ferror(3)) is
set, and errno is set to indicate the error.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main() {
int length = 1;
int *pattern = calloc(length, sizeof(int));
if (pattern == NULL) {
fprintf(stderr, "Unable to find free memory\n");
exit(EXIT_FAILURE);
}
int* text = calloc(length, sizeof(int));
if (text == NULL) {
fprintf(stderr, "Unable to find free memory\n");
exit(EXIT_FAILURE);
}
int pattern_size = 0;
int text_size = 0;
printf("Enter Pattern:\n");
char c = ' ';
while (c != '$') {
if (scanf("%c", &c) != 1) {
fprintf(stderr, "Error in scanf\n");
exit(EXIT_FAILURE);
}
if (isdigit(c) != 0) {
pattern[pattern_size] = c - 48;
pattern_size++;
pattern = realloc(pattern, (pattern_size + 1) * sizeof(int));
}
}
printf("\nPlease enter the replacement text:\n");
// get_array(text,&text_size,length);
char d = ' ';
while (d != '$') {
if (scanf("%c", &d) != 1) {
fprintf(stderr, "Error in scanf\n");
exit(EXIT_FAILURE);
}
if (isdigit(d) != 0) {
text[text_size] = d - 48;
text_size++;
text = realloc(text, (text_size + 1) * sizeof(int));
}
}
fprintf(stdout, "\nOUTPUT:\n");
for (int i = 0; i < pattern_size; i++)
printf("%d ", pattern[i]);
printf("\n");
for (int i = 0; i < text_size; i++)
printf("%d ", text[i]);
printf("\n");
return 0;
free(pattern);
free(text);
}
Including ctype.h you canuse the library function int isdigit(char c) that take in input a char and tells you if it is a number between 0 and 9.
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;
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I was trying to solve CountAndSay problem at one of the online coding site but I am not able to get why my program is printing NULL. I am sure I am doing some conceptual mistake but not getting it.
Here is my code :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* countAndSay(int A) {
int i,j,k,f,count;
char a;
char *c = (char*)malloc(sizeof(char)*100);
char *temp = (char*)malloc(sizeof(char)*100);
c[0] = 1;c[1] = '\0';
for(k=2; k<=A; k++)
{
for(i=0, j=0; i<strlen(c); i++)
{
a = c[i];
count = 1;
i++;
while(c[i] != '\0')
{
if(c[i]==a)
{
count++;
i++;
}
else if(c[i] != a)
{
i--;
break;
}
else
{
break;
}
}
temp[j] = count;
temp[j+1] = a;
j += 2;
}
*(temp+j) = '\0';
if(k<A)
{
for(j=0; j<strlen(temp); j++)
{
c[j] = temp[j];
}
c[j] = '\0';
}
}
return temp;
}
int main(void) {
// your code goes here
char *c = countAndSay(8);
printf("%s\n",c);
return 0;
}
The idea is not that bad, the main errors are the mix-up of numerical digits and characters as shown in the comments.
Also: if you use dynamic memory, than use dynamic memory. If you only want to use a fixed small amount you should use the stack instead, e.g.: c[100], but that came up in the comments, too. You also need only one piece of memory. Here is a working example based on your code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// ALL CHECKS OMMITTED!
char *countAndSay(int A)
{
int k, count, j;
// "i" gets compared against the output of
// strlen() which is of type size_t
size_t i;
char a;
// Seed needs two bytes of memory
char *c = malloc(2);
// Another pointer, pointing to the same memory later.
// Set to NULL to avoid an extra malloc()
char *temp = NULL;
// a temporary pointer needed for realloc()-ing
char *cp;
// fill c with seed
c[0] = '1';
c[1] = '\0';
if (A == 1) {
return c;
}
// assuming 1-based input, that is: the first
// entry of the sequence is numbered 1 (one)
for (k = 2; k <= A; k++) {
// Memory needed is twice the size of
// the former entry at most.
// (Averages to Conway's constant but that
// number is not usable here, it is only a limit)
cp = realloc(temp, strlen(c) * 2 + 1);
temp = cp;
for (i = 0, j = 0; i < strlen(c); i++) {
//printf("A i = %zu, j = %zu\n",i,j);
a = c[i];
count = 1;
i++;
while (c[i] != '\0') {
if (c[i] == a) {
count++;
i++;
} else {
i--;
break;
}
}
temp[j++] = count + '0';
temp[j++] = a;
//printf("B i = %zu, j = %zu\n",i,j-1)
//printf("B i = %zu, j = %zu\n",i,j);
}
temp[j] = '\0';
if (k < A) {
// Just point "c" to the new sequence in "temp".
// Why does this work and temp doesn't overwrite c later?
// Or does it *not* always work and fails at one point?
// A mystery! Try to find it out! Some hints in the code.
c = temp;
temp = NULL;
}
// intermediate results:
//printf("%s\n\n",c);
}
return temp;
}
int main(int argc, char **argv)
{
// your code goes here
char *c = countAndSay(atoi(argv[1]));
printf("%s\n", c);
free(c);
return 0;
}
To get a way to check for sequences not in the list over at OEIS, I rummaged around in my attic and found this little "gem":
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
char *conway(char *s)
{
char *seq;
char c;
size_t len, count, i = 0;
len = strlen(s);
/*
* Worst case is twice as large as the input, e.g.:
* 1 -> 11
* 21 -> 1211
*/
seq = malloc(len * 2 + 1);
if (seq == NULL) {
return NULL;
}
while (len) {
// counter for occurrences of ...
count = 0;
// ... this character
c = s[0];
// as long as the string "s"
while (*s != '\0' && *s == c) {
// move pointer to next character
s++;
// increment counter
count++;
// decrement the length of the string
len--;
}
// to keep it simple, fail if c > 9
// but that cannot happen with a seed of 1
// which is used here.
// For other seeds it might be necessary to
// use a map with the higher digits as characters.
// If it is not possible to fit it into a
// character, the approach with a C-string is
// obviously not reasonable anymore.
if (count > 9) {
free(seq);
return NULL;
}
// append counter as a character
seq[i++] = (char) (count + '0');
// append character "c" from above
seq[i++] = c;
}
// return a proper C-string
seq[i] = '\0';
return seq;
}
int main(int argc, char **argv)
{
long i, n;
char *seq0, *seq1;
if (argc != 2) {
fprintf(stderr, "Usage: %s n>0\n", argv[0]);
exit(EXIT_FAILURE);
}
// reset errno, just in case
errno = 0;
// get amount from commandline
n = strtol(argv[1], NULL, 0);
if ((errno == ERANGE && (n == LONG_MAX || n == LONG_MIN))
|| (errno != 0 && n == 0)) {
fprintf(stderr, "strtol failed: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
if (n <= 0) {
fprintf(stderr, "Usage: %s n>0\n", argv[0]);
exit(EXIT_FAILURE);
}
// allocate space for seed value "1" plus '\0'
// If the seed is changed the limit in the conway() function
// above might need a change.
seq0 = malloc(2);
if (seq0 == NULL) {
fprintf(stderr, "malloc() failed to allocate a measly 2 bytes!?\n");
exit(EXIT_FAILURE);
}
// put the initial value into the freshly allocated memory
strcpy(seq0, "1");
// print it, nicely formatted
/*
* putc('1', stdout);
* if (n == 1) {
* putc('\n', stdout);
* free(seq0);
* exit(EXIT_SUCCESS);
* } else {
* printf(", ");
* }
*/
if (n == 1) {
puts("1");
free(seq0);
exit(EXIT_SUCCESS);
}
// adjust count
n--;
for (i = 0; i < n; i++) {
// compute conway sequence as a recursion
seq1 = conway(seq0);
if (seq1 == NULL) {
fprintf(stderr, "conway() failed, probably because malloc() failed\n");
exit(EXIT_FAILURE);
}
// make room
free(seq0);
seq0 = NULL;
// print sequence, comma separated
// printf("%s%s", seq1, (i < n - 1) ? "," : "\n");
// or print sequence and length of sequence, line separated
// printf("%zu: %s%s", strlen(seq1), seq1, (i < n-1) ? "\n\n" : "\n");
// print the endresult only
if (i == n - 1) {
printf("%s\n", seq1);
}
// reuse seq0
seq0 = seq1;
// not necessary but deemed good style by some
// although frowned upon by others
seq1 = NULL;
}
// free the last memory
free(seq0);
exit(EXIT_SUCCESS);
}
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.
I know the forum has many questions about heap etc. but nothing helped me this much (except for the understanding of why it doesn't work).
I have a huge quantity of data and of course the heap can't follow. The data I need to store are only integers. Malloc starts returning null quite early.
4 arrays of size: (allocation by malloc)
875715
875715
875715
5105043 cells (but it's a 2D array)
Here are my questions:
1) To know the quantity of memory needed, is it:
875715 * 3 * 4 + 5105043 * 4 = 62454492 ? (because integer is 4)
Does it mean around 62 MB? (Sorry if it seems dumb)
2) How can we know the size of the heap available? Is there a way to increase it?
3) I have 3 arrays of the same size, is there an advantage of merging them into one 2D array?
For example, array[875715][3] instead of 3 different arrays (of course, by using malloc)
I use Window seven, 64 bit, 8GB of RAM.
EDIT: Here is a typical allocation I do for the 1D array and for the beginning of the 2D array (first level):
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#define FILE_NAME "SCC.txt"
#define ARRAY_SIZE 875714
void getGgraph(int mode,int **graph,int *sizeGraph);
int sizeOfArray(int *array);
void getGraphSize(int mode,int *arr);
void runThroughGraph(int node,int **graph,int *exploredNode,int *magicalPath,int *sizeGraph);
void getMagicalPath(int *magicalPath,int **graph,int *sizeGraph);
void main()
{
int i, *magicalPath,*sizeGraph, **graph;
/* ------------- creation of the array sizeGraph ------------------ */ // contain the size of each level to initiate the array
if ((sizeGraph =(int*) malloc((ARRAY_SIZE + 1) * sizeof(sizeGraph[0]))) == NULL) {
printf("malloc of sizeGraph error\n");
return;
}
memset(sizeGraph, 0, (ARRAY_SIZE + 1) * sizeof(sizeGraph[0]));
/* ------------- create reverse G graph, this will be a 2D array ------------------ */
if ((graph =(int**) malloc((ARRAY_SIZE + 1) * sizeof(*graph))) == NULL) {
printf("malloc of graph error\n");
return;
}
getGgraph(1,graph,sizeGraph);
// [..... Some more code .....]
// end of main()
}
void getGgraph(int mode,int **graph,int *sizeGraph) {
char int_string[40];
char stringToAdd[10];
FILE *integerFile = NULL;
int i = 0, j = 0, n = 0,stCurrentInt, tail,head,*temp;
getGraphSize(mode,sizeGraph);
for (i = 0; i < (ARRAY_SIZE + 1); i++) {
if ((graph[i] =(int*) malloc((ARRAY_SIZE + 1) * sizeof(graph[i][0]))) == NULL) {
// THIS IS WHERE IT STOPS (i = 594)
printf("Malloc of graph[%d] error\n",i);
return;
}
}
if ((temp =(int*) malloc((ARRAY_SIZE + 1) * sizeof(temp[0]))) == NULL) {
printf("malloc of temp in getGgraph function error\n");
return;
}
memset(temp, 0, (ARRAY_SIZE + 1) * sizeof(temp[0]));
if ((integerFile = fopen(FILE_NAME, "r")) != NULL) {
while (fgets(int_string,40, integerFile) != NULL) {
n = 0, i = 0, stCurrentInt = 0,head = 0; // initialisation
while (int_string[n] != NULL) {
if (int_string[n] == ' ') {
for (j = stCurrentInt; j < n; j++) {
stringToAdd[j - stCurrentInt] = int_string[j];
}
if (stCurrentInt == 0) // first integer is the index
tail = (int) atoi(stringToAdd);
else {
head = atoi(stringToAdd);
if (mode == 0) {
graph[tail][temp[tail]] = head;
temp[tail]++;
}
else if (mode == 1) {
graph[head][temp[head]] = tail;
temp[head]++;
}
}
for (j = 0; j < 10; j++) { // empty the string for next iteration
stringToAdd[j] = NULL;
}
stCurrentInt = n + 1;
}
n++;
}
}
free(temp);
fclose(integerFile);
}
else {
printf("\n File missing in getGgraph.\n");
return;
}
}
void getGraphSize(int mode,int *arr) {
char int_string[40],stringToAdd[10];
FILE *integerFile = NULL;
int i = 0, j = 0, n = 0,stCurrentInt,tail,head;
if ((integerFile = fopen(FILE_NAME, "r")) != NULL) {
while (fgets(int_string,40, integerFile) != NULL) {
n = 0, i = 0, stCurrentInt = 0,head = 0; // initialisation
while (int_string[n] != NULL) {
if (int_string[n] == ' ') {
for (j = stCurrentInt; j < n; j++) {
stringToAdd[j - stCurrentInt] = int_string[j];
}
if (stCurrentInt == 0) // first integer is the index
tail = (int) atoi(stringToAdd);
else
head = atoi(stringToAdd);
for (j = 0; j < 10; j++) { // empty the string for next iteration
stringToAdd[j] = NULL;
}
stCurrentInt = n + 1;
}
n++;
}
if (mode == 0 && head != 0)
arr[tail]++;
else if (mode == 1 && head != 0)
arr[head]++;
}
}
else {
printf("\n File missing in getGraphSize.\n");
return;
}
}
EDIT2: My program actually works like a charm for smaller inputs.
[..... Some more code .....]: this is after the issue. The failing malloc is inside getGraph, so I don't think the rest is relevant. I free() the arrays later on in the program.
without pulling out a calculator, and without your code, your analysis looks right.
The HEAP will grow as needed, constrained only by OS process limits.. By default, under windows, you get no more that 2Gig. Here's a more specific link.
no significant advantage.
In your case you'd be better served by adjusting your memory allocation algorithms to allocate what you need and no more.