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
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 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;
}
I am reading text from an input file in. I have to separate text from scores ie
John Doe 100 95 67 85
jane doe 67 78 99
and then average the numbers. I can separate by the spaces using strtok but how can i tell when i have an integer? i need to split the reading of names and of integers into 2 functions. My code to read it works but i need to stop at the end of each name. I attempted to use numbers converted to strings and using strcmp however it did not work.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void read_reverse_write(FILE * ptr_file, FILE * op);
void write_and_avarage(int * fp, char * op);
//int checker(char *token);
int main(int argc, char** argv) {
FILE *fp;
FILE *op;
//opens quiz and checks and checks to make sure it did
fp = fopen("quiz.txt", "r");
if (fp == NULL) {
printf("Error opening file");
return (-1);
}
//opens op and checks that it did
op = fopen("output.txt", "w");
if (op == NULL) {
printf("Error opening file");
return (-1);
}
// runs read reverse write
read_reverse_write(fp, op);
fclose(fp);
fclose(op);
return (EXIT_SUCCESS);
}
void read_reverse_write(FILE * ptr_file, FILE * op) {
char buf[1000];
char *token;
const char delim[2] = " ";
fgets(buf, 1000, ptr_file);
token = strtok(buf, delim);
while (token != 100) {
fprintf(op, "%s ", token);
token = strtok(NULL, delim);
}
}
/*void write_and_avarage(int * fp, char * op) {
}
int checker(char *token) {
char *arr[102];
char ph[4];
for (int p = 0; p < 100; p++) {
if (p < 10) {
snprintf(ph, 1, "%d", p);
arr[p] = ph;
} else if (p < 99) {
snprintf(ph, 2, "%d", p);
arr[p] = ph;
} else if (p = 100) {
snprintf(ph, 3, "%d", p);
arr[p] = ph;
}
}
for (int z = 0; z < 100; z++) {
if (strcmp(token, arr[z]) == 1) {
return 1;
} else {
z++;
}
return 0;
}
}
*/
You can use the following code to check the whether the string is a number or not.
#include <stdio.h>
#include <string.h>
#define MAX_NUM 9
#define MIN_NUM 0
#define ZERO 0
#define MAX_SIZE 1024
int checkDigit(int num, int len)
{
int divisor = 1, checkVal = 0;
if(len <= 2)
divisor = 10;
else if(len > 2)
{
len = len - 1;
while(len != ZERO)
{
divisor = divisor * 10;
len = len - 1;
}
}
checkVal = num/divisor;
if(checkVal > MIN_NUM && checkVal <= MAX_NUM)
return 1;
else
return 0;
}
void main()
{
char array[MAX_SIZE] = "JOHN DOE 120 DOE HELLO 2323 90909";
char *split_token = NULL;
int status = 2, len = 0, sum = 0, total_digits = 0;
float average = 0;
split_token = strtok(array, " ");
while( split_token != NULL )
{
len = strlen(split_token);
status = checkDigit(atoi(split_token), len);
if (1 == status)
{
sum = sum + atoi(split_token);
total_digits = total_digits + 1;
}
split_token = strtok(NULL, " ");
}
average = (float)sum/total_digits;
printf("Average is : %f\n", average);
}
This code will check whether your string is a number or not and finally calculate the average of all the numbers in the given string.
If you need to read from a file, multiple sets of inputs, use fscanf() and use the complete code logic repeatedly for each line of input.
Hope it helps! Do ask if you need the complete code or any clarification for the code.
I'm trying to extract all numbers from a string add 56 89 29. There is something wrong with my code which I'm not able to figure out. The output looks like this:
Current no: 56
Current no: 89
Current no: 9
Current no: 29
Current no: 9
Current no: 9
Current no: 0
Current no: 0
where as, I would expect this:
Current no: 56
Current no: 89
Current no: 29
Current no: 29
Current no: 29
Current no: 29
There are better ways to do it but I want to know what is wrong with this implementation.
#include <string.h>
#include <stdio.h>
int main(int argc, char * argv[]){
char temp[100];
char op[3];
char *buf = "add 56 89 29";
int offset = 0;
int rcount = 0;
int lastno = -999;
int currno;
bzero(&temp, sizeof(temp));
sscanf(buf, "%s", op); // Get the operator (add)
if(!strcmp(op, "add")){
while(1){
sscanf(buf + offset + 4, "%s", temp); // strlen("add ") == 4
currno = atoi(temp);
offset += strlen(temp);
if(currno == lastno){
rcount++;
// Repeating numbers means string finished
if(rcount == 3){
break;
}
}
printf("Current no: %d\tOffset: %d\n", currno, offset + 4);
lastno = currno;
}
}
return 0;
}
Thanks in advance!
The "%n" specifier will record the number of characters used by a scan. The result can be added to the offset to advance through the string.
#include <string.h>
#include <stdio.h>
int main(int argc, char * argv[]){
char temp[100];
char op[4];
char *buf = "add 56 89 29";
int offset = 0;
int used = 0;
int rcount = 0;
int lastno = -999;
int currno;
bzero(&temp, sizeof(temp));
sscanf(buf, "%3s%n", op, &used); // Get the operator (add)
offset += used;
if(!strcmp(op, "add")){
while( ( sscanf(buf + offset, "%99s%n", temp, &used)) == 1) {
currno = atoi(temp);
offset += used;
printf("Current no: %d\tOffset: %d\n", currno, offset);
lastno = currno;
}
}
return 0;
}
There are a few things I can see that would cause your program to fail
It's unecessary to write a loop like while (1) and then check for the variable inside the loop to break, because there is do {} while ();, this makes the code hard to understand.
This initialization bzero(&temp, sizeof(temp)); is wrong, unecessary, and inefficient. And also, bzero() is deprecated use memset().
You have a very important mistake in scanf("%s", op); you allocate space for 3 characters and type add which requires 3 + 1 for the nul terminator. The correct way to do it would be
char op[4];
if (sscanf(buf, "%3s", op) != 1)
{
fprintf("unexpected problem while reading the operator.\n");
return -1;
}
sscanf(buf + offset + 4, "%s", temp) is very dangerous too, because you could easily overflow buf or temp, and besides it's much more readable like this
sscanf(&buf[offset + 4], "%s", temp)
This implementation would work better
#include <string.h>
#include <stdio.h>
int main(int argc, char * argv[])
{
char op[4];
const char *buffer;
int count;
int last;
int length;
int offset;
const char *pointer;
buffer = "add 56 89 29";
if (sscanf(buffer, "%3s%n", op, &length) != 1)
{
fprintf(stderr, "unexpected problem while reading the operator.\n");
return -1;
}
pointer = &buffer[length];
if (strcmp(op, "add") != 0)
{
fprintf(stderr, "sorry, I can't understand this operator `%s'.\n", op);
return -1;
}
count = 0;
last = -999;
offset = length;
do {
int number;
int length;
if (sscanf(pointer, "%d%n", &number, &length) != 1)
{
fprintf(stderr, "input format error, exiting.\n");
return -1;
}
pointer += length;
if (number == last)
++count;
printf("Current no: %d\tOffset: %d\n", number, offset);
last = number;
offset += length;
} while ((count < 3) && (*pointer != '\0'));
return 0;
}
read about the scanf() "%n" specifier.
You can also use strtol() like this
#include <string.h>
#include <stdio.h>
int main(int argc, char * argv[])
{
char op[4];
char buffer[] = "add 56 89 29";
int count;
int last;
int length;
int offset;
char *pointer;
if (sscanf(buffer, "%3s%n", op, &length) != 1)
{
fprintf(stderr, "unexpected problem while reading the operator.\n");
return -1;
}
pointer = &buffer[length];
if (strcmp(op, "add") != 0)
{
fprintf(stderr, "sorry, I can't understand this operator `%s'.\n", op);
return -1;
}
count = 0;
last = -999;
offset = length;
do {
int number;
char *previous;
previous = pointer;
number = strtol(pointer, &pointer, 10);
if (number == last)
++count;
printf("Current no: %d\tOffset: %d\n", number, offset);
last = number;
offset += pointer - previous;
} while ((count < 3) && (*pointer != '\0'));
return 0;
}
Hi I tried your code and the following worked for me. I am not a hardcore C programmer so please forgive me if I am used any non standard C functions here and but I love to work in C.
int main(int argc, const char * argv[])
{
char *buf = "add 56 89 29";
int sum = 0;
if(!strncmp(buf, "add", 3))
{
buf += 3;
while(*buf != '\0')
{
if(isdigit(*buf) == 0)
{
++buf;
continue;
}
int digit;
int num = 0;
while(isdigit(*buf))
{
digit = (int)*buf - 48;
num = (num * 10) + digit;
++buf;
}
sum += num;
printf("Current no: %d\t Sum: %d\n", num, sum);
}
}
return 0;
}
A much better and convenient way of doing this is with strtok which you can use to get tokens one after the other.
#include <stdio.h>
#include <string.h>
int main(int argc, char * argv[]){
char *buf = "add 56 89 29";
char *token;
int count = 0;
token = strtok(buf, " ");
while(token != NULL){
count++;
if(count == 1)
continue;
printf("%s\n", token)
token = strtok(NULL, " ");
}
}