In my code I opened file (succesful) and I am trying to get the numbers to array, but it does not working (control output is bad). Compiler did not show me any error.
link on txt file: https://textuploader.com/1amip
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
FILE *fr_koty;
int **array = NULL;
int x = 1; /* Pocet radku */
int y = 1; /* Pocet sloupcu */
char line[1024];
char *assistant_line;
int number; /* Promena pro cislo*/
char *tab;
if((fr_koty = fopen("koty.txt", "r")) == NULL) {
printf("Soubor se nepodarilo otevrit!");
return 0;
}
while(fgets(line, 1023, fr_koty) != NULL) {
array = (int **) realloc(array, x * sizeof(int *));
array[x] = NULL;
assistant_line = line;
while(sscanf(assistant_line, "%d", &number) == 1) {
array[x] = (int *) realloc(array[x], y * sizeof(int));
array[x][y] = number;
printf("%d ", array[x][y]);
if((tab = strchr(assistant_line, '\t')) != NULL) {
assistant_line = tab + 1;
y++;
}
else {
break;
}
}
putchar('\n');
x++;
}
}
Output of numbers is random. I think the reason is bad working with memory, but I can not see the problem.
You're initializing x and y to 1, which is ok for the realloc, but as C arrays are 0 based, you need to use x-1 and y-1 to access the array elements.
Or you init them to 0 and use (x+1) and (y+1) in the realloc call. I would prefer this way.
Now I see it too. Thank you!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
FILE *fr_koty;
int **array = NULL;
int x = 1; /* Pocet radku */
int y; /* Pocet sloupcu */
char line[1024];
char *assistant_line;
int number; /* Promena pro cislo*/
char *tab;
if((fr_koty = fopen("koty.txt", "r")) == NULL) {
printf("Soubor se nepodarilo otevrit!");
return 0;
}
while(fgets(line, 1023, fr_koty) != NULL) {
y = 1;
array = (int **) realloc(array, x * sizeof(int *));
array[x-1] = NULL;
assistant_line = line;
while(sscanf(assistant_line, "%d", &number) == 1) {
array[x-1] = (int *) realloc(array[x-1], y * sizeof(int));
array[x-1][y-1] = number;
printf("%d ", array[x-1][y-1]);
if((tab = strchr(assistant_line, '\t')) != NULL) {
assistant_line = tab + 1;
y++;
}
else {
break;
}
}
putchar('\n');
x++;
}
}
Related
I attempt to malloc char** to store string, and free this, but I got this error. I can't understand why. The steps are as follows:
1:
char **pid_array = (char **)malloc(sizeof(char *) * MAX_LEN);
2:
pid_array[0] = (char *)malloc(sizeof(char) * SINGLE_LEN * MAX_LEN);
3:
free(pid_array); free(pid_array[0]);
The detailed code follows:
#include <assert.h>
#include <ctype.h>
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define MAX_LEN 1000
#define SINGLE_LEN 10
int isPid(char *str) {
int len = strlen(str);
for (int i = 0; i < len; i++) {
if (isdigit(str[i]) == 0) {
return 1;
}
}
return 0;
}
void getFileName(char *dir_path, char *pid_array[], int *len) {
DIR *dir = opendir(dir_path);
if (dir == NULL) {
fprintf(stderr, "path open failed!\n");
exit(EXIT_FAILURE);
}
chdir(dir_path);
struct dirent *ent;
int i = 0;
while ((ent = readdir(dir)) != NULL) {
if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) {
continue;
}
int size = strlen(ent->d_name);
if (isPid(ent->d_name) == 0) {
pid_array[i++] = ent->d_name;
}
}
*len = i;
closedir(dir);
}
int main(int argc, char *argv[]) {
int pflag, nflag, vflag;
pflag = 0;
nflag = 0;
vflag = 0;
int opt;
while ((opt = getopt(argc, argv, "pvn")) != -1) {
switch (opt) {
case 'p':
pflag = 1;
break;
case 'v':
vflag = 1;
break;
case 'n':
nflag = 1;
break;
}
}
printf("pflag=%d; nflag=%d; vflag=%d; optind=%d\n", pflag, nflag, vflag, optind);
char **pid_array = (char **)malloc(sizeof(char *) * MAX_LEN);
pid_array[0] = (char *)malloc(sizeof(char) * SINGLE_LEN * MAX_LEN);
for(int i=0; i < MAX_LEN; i++){
pid_array[i]=pid_array[i-1]+SINGLE_LEN;
}
/*
for (int i = 0; i < MAX_LEN; i++) {
pid_array[i] = (char *)malloc(sizeof(char) * SINGLE_LEN);
assert(pid_array[i] != NULL);
}
*/
for (int i = 0; i < MAX_LEN; i++) {
free(pid_array[i]);
}
int *pid_array_len = (int *)malloc(sizeof(int));
getFileName("/proc", pid_array, pid_array_len);
for (int i = 0; i < *pid_array_len; i++) {
printf("%d\n", atoi(pid_array[i]));
}
free(pid_array);
free(pid_array[0]);
free(pid_array_len);
return 0;
}
The error is follow:
error
The steps as noted are not correct.
if pid_array is char** then
*pid_array is char*
**pid_array is char
And you need to construct them as such. And free them in the reverse order. If you intend to have a vector of pointers at pid_array then your case is very very common: every C program gets one for free. The main prototype can be declared as
int main(int argc, char**argv);
The system knows how many char* to pass to the program, but in your case maybe the simplest (safest) way is to use encapsulation and build a block like this
typedef struct
{
size_t argc;
char** argv;
} Block;
I will let an example below.
a way to free the block properly
If you insist in using just the pointer you can easily adapt this. Anyway a possible implementation is
Block* delete (Block* blk)
{
if (blk == NULL) return NULL;
fprintf(
stderr, "Deleting block of %llu strings\n",
blk->argc);
for (int i = 0; i < blk->argc; i += 1)
free(blk->argv[i]);
free(blk->argv);
free(blk);
fprintf(stderr, "Deleted...\n");
return NULL;
}
The reason to return a pointer is to create a simple way to assure the pointer is invalidated as in
my_block = delete (my_block);
In the example
A block is created
is filled with strings of random size
the strings are printed
the block is deleted
main for the example
int main(void)
{
srand(220630);
const int size = MAX_LEN;
Block* my_block = build(size);
fill(my_block);
show(my_block, "a vector of numbered strings");
my_block = delete (my_block);
return 0;
}
the output
a vector of numbered strings
25 strings:
1 "#000#k"
2 "#001#swfsxji"
3 "#002#cn"
4 "#003#akmxhksqgb"
5 "#004#dqnegzryobmhucldx"
6 "#005#iiuqddvuvukkrs"
7 "#006#jxvlsolocgnvgjcrwh"
8 "#007#zylbzumyhmeswxuno"
9 "#008#ex"
10 "#009#ixinxqyxqydnswb"
11 "#010#ylxelydzqgs"
12 "#011#absdfpdjvgwhxcmzekr"
13 "#012#sceqzvmjskkrmszpth"
14 "#013#n"
15 "#014#rsmkrqhssjniqgphjp"
16 "#015#dgojvpflydevwudvv"
17 "#016#qbmaolgrskkqghhkgb"
18 "#017#uzsunopqpdawg"
19 "#018#rvdeaiooylywf"
20 "#019#zfejmgqxu"
21 "#020#fjubcmllylxqahvbfh"
22 "#021#zwanyivra"
23 "#022#vooropiugmuya"
24 "#023#js"
25 "#024#qzecia"
Deleting block of 25 strings
Deleted...
The complete C code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_LEN 25
typedef struct
{
size_t argc;
char** argv;
} Block;
Block* build(size_t ttl);
Block* delete (Block* blk);
int fill(Block* bl);
int show(Block* blk, const char* title);
int main(void)
{
srand(220630);
const int size = MAX_LEN;
Block* my_block = build(size);
fill(my_block);
show(my_block, "a vector of numbered strings");
my_block = delete (my_block);
return 0;
}
Block* build(size_t ttl)
{
if (ttl == 0) return NULL;
Block* blk = (Block*)malloc(sizeof(Block));
if (blk == NULL) return NULL;
blk->argc = (ttl > MAX_LEN) ? MAX_LEN : ttl;
blk->argv = (char**)malloc(ttl * sizeof(char*));
if (blk->argv == NULL) return NULL;
for (int i = 0; i < ttl; i += 1)
*(blk->argv + i) = NULL;
return blk;
}
int fill(Block* bl)
{
const char prefix[] = "#nnn#"; // common prefix
char buffer[30] = {0};
char data[20] = {0};
for (int i = 0; i < bl->argc; i += 1)
{
int rest = 1 + rand() % 19;
for (int j = 0; j < rest; j += 1)
data[j] = 'a' + rand() % 26; // a single letter
data[rest] = 0; // terminates string
int res = sprintf(buffer, "#%03d#%s", i, data);
bl->argv[i] = (char*)malloc(strlen(buffer) + 1);
strcpy(bl->argv[i], buffer);
}
return 0;
}
int show(Block* blk, const char* title)
{
if (title != NULL) printf("%s\n", title);
printf("%llu strings:\n", blk->argc);
for (int i = 0; i < MAX_LEN; i += 1)
printf("%d\t \"%s\"\n", 1 + i, *(blk->argv + i));
printf("\n");
return 0;
}
Block* delete (Block* blk)
{
if (blk == NULL) return NULL;
fprintf(
stderr, "Deleting block of %llu strings\n",
blk->argc);
for (int i = 0; i < blk->argc; i += 1)
free(blk->argv[i]);
free(blk->argv);
free(blk);
fprintf(stderr, "Deleted...\n");
return NULL;
}
// https://stackoverflow.com/questions/72809939/
// how-do-i-use-free-properly-to-free-memory-when
// -using-malloc-for-char
I'm trying to count chars from input, and I noticed that while(getchar()!=EOF) produces an extra count, Is it because it counts the null-terminated from input?
This is my code:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define LINE 5
#define MEM_SIZE 10
char *getInput(int *counter);
void printInput(char *input);
int main() {
char *mainInput;
int counter = 0;
printf("Please enter your input:\n");
mainInput = getInput(&counter);
if (mainInput == NULL) {
return 1;
}
printf("\n\n\nOutput:\n%s\n", mainInput);
printf("number of chars: %d\n", counter);
printInput(mainInput);
free(mainInput);
return 0;
}
char *getInput(int *counter) {
char *p = (char *)malloc(MEM_SIZE * sizeof(char));
char *q = p; /* backup pointer, if realloc fails to allocate, function will return last address values stored */
int c;
int temp_counter = 0;
long current = 0, last = MEM_SIZE - 1;
while ((c = getchar()) != EOF) {
if (current >= last) {
q = p;
p = (char *)realloc(q, last + (MEM_SIZE * sizeof(char)));
if (p == NULL) {
printf("Memory allocation failed, printing only stored values \n");
return q;
}
last += MEM_SIZE;
}
p[current] = c;
temp_counter++;
printf("number of chars: %d\n", temp_counter);
++current;
}
p[current] = '\0';
(*counter) = temp_counter - 1;
return p;
}
void printInput(char *input) {
int i, j = 0;
while (input[j] != '\0') {
for (i = 0; i < LINE; i++) {
if (input[j] == '\0')
break;
putchar(input[j]);
++j;
}
if (input[j] != '\0')
putchar('\n');
}
}
I have the following inputs:
23 34 43 56 45
100 73
I want to input these two strings in different arrays integer arrays using pointer since the input size is apriori unknown.
I have written the following code, but I cannot get the integers into any of the two arrays.
#include <stdio.h>
#include <stdlib.h>
#define lent(x) (sizeof(x) / sizeof(x[0]))
#define Malloc(n, type) (type *)malloc((unsigned)((n) * sizeof(type)))
#define Realloc(ptr, n, type) (type *)realloc(ptr, (n) * sizeof(type))
void getInt_Stream(int *ptr)
{
int i = 0;
ptr = Malloc(i+1, int);
char c;
scanf("%c", &c);
while ((c != EOF) && (c != '\n'))
{
if (c >= '0' && c <= '9')
{
ptr[i] = ptr[i] * 10 + (c - '0');
}
else if (c == ' ')
{
i++;
ptr = Realloc(ptr, i+1,int);
ptr[i] = 0;
}
scanf("%c", &c);
}
}
int main()
{
int *arr1, *arr2;
getInt_Stream(arr1);
getInt_Stream(arr2);
int n1 = lent(arr1);
for (int i = 0; i < n1; i++)
{
printf(" arr1[%d] =%d\n", i, *(arr1+i));
}
return 0;
}
Also, I am getting some errors and warnings when I compile the program using
gcc prog.c -o prog -Wall -Wextra.
Please help with some hints. Thanks in advance.
Would you please try the following:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
* get integer values from the file stream
* return the pointer to the array of integers
* the size of the array is stored in *n
*/
int *
getInt_Stream(FILE *fp, int *n)
{
char str[BUFSIZ]; // line buffer of the input stream
char *tk; // pointer to each token
char delim[] = " "; // delimiter of the tokens
int *arr = NULL; // array of intergers
int count = 0; // token counter
if (NULL == (fgets(str, BUFSIZ, fp))) {
// read a line and assign str
perror("fgets");
exit(1);
}
for (tk = strtok(str, delim); tk != NULL; tk = strtok(NULL, delim)) {
// get token one by one
if (NULL == (arr = realloc(arr, (count + 1) * sizeof(int)))) {
// allocate memory for the array
perror("realloc");
exit(1);
}
arr[count] = (int)strtol(tk, (char **)NULL, 10);
// assign the array element to int
count++;
}
*n = count; // number of the elements
return arr; // pointer to the array
}
int
main(int argc, char *argv[])
{
int *arr1, *arr2;
int n1, n2;
char *filename = argv[1];
FILE *fp;
int i;
if (argc != 2) {
fprintf(stderr, "usage: %s file.txt\n", argv[0]);
exit(1);
}
if (NULL == (fp = fopen(filename, "r"))) {
perror(filename);
exit(1);
}
arr1 = getInt_Stream(fp, &n1);
for (i = 0; i < n1; i++) {
printf("arr1[%d] = %d\n", i, arr1[i]);
}
arr2 = getInt_Stream(fp, &n2);
for (i = 0; i < n2; i++) {
printf("arr2[%d] = %d\n", i, arr2[i]);
}
free(arr1);
free(arr2);
fclose(fp);
return 0;
}
Output for the provided file:
$ ./a.out file.txt
arr1[0] = 23
arr1[1] = 34
arr1[2] = 43
arr1[3] = 56
arr1[4] = 45
arr2[0] = 100
arr2[1] = 73
so I have this file:
Jane
18
5.3
John
23
5.8
and I need to create a program to store this two persons details on a array of structs.
I have done this:
#include <stdio.h>
typedef struct
{
char name[100];
int age;
float height;
} PERSON;
main()
{
PERSON *X = NULL;
FILE *f;
char ch;
int lines = 1;
f = fopen("filename.txt", "r");
while ((ch = fgetc(f)) !=EOF)
{
if (ch == '\n')
lines++;
}
rewind(f);
X = (PERSON*) malloc ((lines/3) * sizeof(PERSON));
StoreInArray(X, f, lines);
}
StoreInArray(PERSON *X, FILE *f, int lines)
{
int i = 0;
for (i=0; i < lines/3; i++)
{
fscanf(f, "%s%d%f", (*(X+i)).name[100], &(*(X+i)).age, &(*(X+i)).height);
}
//for testing//
for (i=0; i < lines/3; i++)
printf("%s\n%d \n%f\n",X[i].name[100], X[i].age, X[i].height);
}
But all it prints is:
(null)
0
0.000000
If you could help me figure out what is wrong I'd be very appreciated!
Thank you in advance.
I'd compile with -Wall -O2 to catch warnings, which would have pointed out an error.
In your fscanf and printf, you don't want name[100] but name. You want to point to the name array, but name[100] is a single char [fetching past the end of the array (i.e.) undefined behavior], and would be flagged by the compiler.
Here's a version of your code with the bugs annotated/corrected:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char name[100];
int age;
float height;
} PERSON;
void StoreInArray(PERSON * X, FILE * f, int lines);
int
main()
{
PERSON *X = NULL;
FILE *f;
char ch;
int lines = 1;
f = fopen("filename.txt", "r");
while ((ch = fgetc(f)) != EOF) {
if (ch == '\n')
lines++;
}
rewind(f);
X = (PERSON *) malloc((lines / 3) * sizeof(PERSON));
StoreInArray(X, f, lines);
return 0;
}
void
StoreInArray(PERSON * X, FILE * f, int lines)
{
int i = 0;
for (i = 0; i < lines / 3; i++) {
#if 0
fscanf(f, "%s%d%f", (*(X + i)).name[100], &(*(X + i)).age, &(*(X + i)).height);
#else
fscanf(f, "%s%d%f", (*(X + i)).name, &(*(X + i)).age, &(*(X + i)).height);
#endif
}
//for testing//
for (i = 0; i < lines / 3; i++) {
#if 0
printf("%s\n%d \n%f\n", X[i].name[100], X[i].age, X[i].height);
#else
printf("%s\n%d \n%f\n", X[i].name, X[i].age, X[i].height);
#endif
}
}
Note that using *(X + i)).name is cumbersome, so here's a simplified and more readable version that uses an extra pointer variable:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char name[100];
int age;
float height;
} PERSON;
void StoreInArray(PERSON * X, FILE * f, int lines);
int
main()
{
PERSON *X = NULL;
FILE *f;
char ch;
int lines = 1;
f = fopen("filename.txt", "r");
while ((ch = fgetc(f)) != EOF) {
if (ch == '\n')
lines++;
}
rewind(f);
X = (PERSON *) malloc((lines / 3) * sizeof(PERSON));
StoreInArray(X, f, lines);
return 0;
}
void
StoreInArray(PERSON * X, FILE * f, int lines)
{
int i = 0;
PERSON *p;
p = X;
for (i = 0; i < lines / 3; i++, p++)
fscanf(f, "%s%d%f", p->name, &p->age, &p->height);
//for testing//
p = X;
for (i = 0; i < lines / 3; i++, p++)
printf("%s\n%d \n%f\n", p->name, p->age, p->height);
}
It isn't really necessary to preread the file to get a line count. It is possible to grow your array dynamically, as lines are read in, using realloc:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char name[100];
int age;
float height;
} PERSON;
int
main()
{
PERSON *X = NULL;
FILE *f;
int i;
PERSON *p;
int count = 0;
f = fopen("filename.txt", "r");
while (1) {
X = realloc(X,sizeof(PERSON) * (count + 1));
p = &X[count];
if (fscanf(f, "%s%d%f", p->name, &p->age, &p->height) == EOF)
break;
++count;
}
fclose(f);
// trim the array
X = realloc(X,sizeof(PERSON) * count);
p = X;
for (i = 0; i < count; i++, p++)
printf("%s\n%d \n%f\n", p->name, p->age, p->height);
return 0;
}
Here's a further refinement that reduces the number of realloc calls needed:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char name[100];
int age;
float height;
} PERSON;
int
main()
{
PERSON *X = NULL;
FILE *f;
int i;
PERSON *p;
size_t count = 0;
size_t alloc = 0;
f = fopen("filename.txt", "r");
while (1) {
if (count >= alloc) {
alloc += 100;
X = realloc(X,sizeof(PERSON) * alloc);
}
p = &X[count];
if (fscanf(f, "%s%d%f", p->name, &p->age, &p->height) == EOF)
break;
++count;
}
fclose(f);
// trim the array to what was actually used
X = realloc(X,sizeof(PERSON) * count);
p = X;
for (i = 0; i < count; i++, p++)
printf("%s\n%d \n%f\n", p->name, p->age, p->height);
return 0;
}
I want to compare 2 files for identical lines: mytab2411.txt(15,017,210 bytes in size) and shadow.txt (569 bytes in size) but when I compiled this code and ran the program, I get a segmentation fault. I know that it's because the "mytab2411.txt" file exceeds the size of "char buf" but how do I go about solving this problem without overflowing the buffer?
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
int cmp(const void * s1, const void * s2)
{
return strcasecmp(*(char **)s1, *(char **)s2);
}
int cmp_half(const char * s1, const char * s2)
{
int i;
for (i = 0; i < 3; i++)
{
int res = strncasecmp((char *)s1+i*3, (char *)s2+i*3, 2);
if (res != 0) return res;
}
return 0;
}
char * line[1024];
int n = 0;
int search(const char * s)
{
int first, last, middle;
first = 0;
last = n - 1;
middle = (first+last)/2;
while( first <= last )
{
int res = cmp_half(s, line[middle]);
if (res == 0) return middle;
if (res > 0)
first = middle + 1;
else
last = middle - 1;
middle = (first + last)/2;
}
return -1;
}
int main()
{
FILE * f1, * f2;
char * s;
char buf[1024*1024], text[1024];
f1 = fopen("shadow.txt", "rt");
f2 = fopen("mytab2411.txt", "rt");
s = buf;
while (fgets(s, 1024, f2) != NULL)
{
line[n] = s;
s = s+strlen(s)+1;
n++;
}
qsort(line, n, sizeof(char *), cmp);
while (fgets(text, 1024, f1) != NULL)
{
text[strlen(text)-1] = 0;
int idx = search(text);
if (idx >= 0)
{
printf("%s matched %s\n", text, line[idx]);
}
else
{
printf("%s not matched\n", text);
}
}
return 0;
}
Your method assumes that each line in the file is 1024 bytes long. In practice the lines can be up to 1024 bytes, but most lines are much shorter. Use strdup or malloc to allocate memory for each line based on line's length.
Store the lines in dynamically allocated arrays. This is about 15 MB of data and it should not be a problem unless there are resource limitations.
int main(void)
{
char buf[1024];
char **arr1 = NULL;
char **arr2 = NULL;
int size1 = 0;
int size2 = 0;
FILE * f1, *f2;
f1 = fopen("shadow.txt", "r");
f2 = fopen("mytab2411.txt", "r");
while(fgets(buf, 1024, f1))
{
size1++;
arr1 = realloc(arr1, sizeof(char*) * size1);
arr1[size1 - 1] = strdup(buf);
}
while(fgets(buf, 1024, f2))
{
size2++;
arr2 = realloc(arr2, sizeof(char*) * size2);
arr2[size2 - 1] = strdup(buf);
}
for(int i = 0; i < size1; i++)
for(int j = 0; j < size2; j++)
{
if(strcmp(arr1[i], arr2[j]) == 0)
printf("match %s\n", arr1[i]);
}
return 0;
}