How to read in string input from the user and allocate it? - c

So I've been working on this code for a while now and I can't figure out why it's not working. Basically I'm suppose to create a program using functions to read in string input from the user which is the filename for “data.txt”. I need a function to determine the number of rows that are in the file in order to allocate an array of character pointers. Then my program should print out the strings read from the file. Finally the program should free the allocated memory.
This is my non-working code.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_WIDTH 144
void getFileName(char* array1);
int getLineCount(FILE* data, int max);
char** createArryOfPtrs(int rows);
int main(void)
{
int max = 0;
int rows;
char array1[MAX_WIDTH];
FILE* data = fopen(array1, "r");
getFileName(array1);
getLineCount(data, max);
createArryOfPtrs(rows);
fclose(data);
return 0;
}
void getFileName(char* array1)
{
printf("Enter filename: ");
fscanf(stdin, "%144[^\t]", array1);
}
int getLineCount(FILE* data, int max)
{
int i = 4;
char *array1[MAX_WIDTH];
if(data != NULL)
{
while(fgets(*array1, MAX_WIDTH, data) != NULL)
{
i+=1;
}
}
return i;
}
char** createArryOfPtrs(int rows)
{
int r = 4, c = 9, i, j, count;
char *array1[r];
for(i =0; i < r; i++)
{
array1[i] = (char*)malloc(c * sizeof(char));
}
count = 0;
for(i = 0; i < r; i++)
{
for(j = 0; j < c; j++)
{
array1[i][j] = ++count;
}
}
for(i = 0; i < r; i++)
{
for(j = 0; j < c; j++)
{
printf("%c", array1[i][j]);
}
}
return 0;
}
This is the text file.
larry snedden 123 mocking bird lane
sponge bob 321 bikini bottom beach
mary fleece 978 pasture road
hairy whodunit 456 get out of here now lane
I'm still new to C so I'm very confused. Appreciate any help I can get.

Order matters! You get the name of the file to open after you call fopen. That means the data in array1 will be uninitialized and indeterminate (and seem random).
You need to read the name of the file first.
This issue should have been very clear if you did a little rubber duck debugging.

Related

Reading digits into an array and sorting it

The task is as follows: to fill the file with numbers using the generation() function - an array cannot be used here. Then read the digits into the array by the read_file() function into the array and sort it using the quick sort method. Output to the console.
I wrote the code as I logically understood it myself, but a set of values is output to the console after sorting, as it is output in case of an error with a lack of memory, random numbers with cons sometimes. Maybe it's worth filling in a dynamic array? And why, if I know a specific number of elements?
Please help me figure it out.
#include <stdio.h>
#include <stdlib.h>
#define N 10
#define A -25000
#define B 25000
void generation();
void read_file();
void method_simple_sort();
int main(void) {
generation();
method_simple_sort();
return EXIT_SUCCESS;
}
void generation() {
FILE *file;
int i;
file = fopen("index.txt", "w");
srand(time(0));
for (int i = 0; i < N; i++) {
fprintf(file, "%d\n", A + rand() % (A - B + 1));
}
fclose(file);
}
void read_file() {
FILE *file;
int i, a[N] = { 0 };
file = fopen("index.txt", "r");
for (i = 0; i < N; i++) {
fscanf(file, "%d ", &a[i]);
}
fclose(file);
for (int i = 0; i < N; i++)
printf("%d ", a[i]);
}
void method_simple_sort() {
int a[N], i = 0, k = 0, ind_max = 0, temp = 0;
read_file();
for (k = 0; k < N - 1; k++) {
ind_max = k;
for (i = 1 + k; i < N; i++) {
if (a[i] > a[ind_max]) {
ind_max = i;
}
}
temp = a[k];
a[k] = a[ind_max];
a[ind_max] = temp;
}
// вывод результатов в файл
printf("\n\nПростого выбора: ");
for (int i = 0; i < N; i++) {
printf("%d ", a[i]);
}
printf("\n\n\n\n");
}
The function method_simple_sort defines a local array variable int a[N].
It then calls read_file(), but read_file() does not fill this local array variable defined in method_simple_sort.
Instead it fill its own local array variable (called also int a[N], but it's a different one than the one in method_simple_sort).
The bottom line is that when method_simple_sort attempts to sort a it sorts an array containing uninitialized data.
Hence the "garbaged" values that you see printed at the end.
The array used by the methods read_file and method_simple_sort aren't the same. When you declare anything inside a function it is translated at low level in space to allocate on the stack when you call the function.
You should transform read_file(void) into read_file(int *a) without declaring another instance of an array inside read_file.
By doing that you can pass a reference to the array declared inside method_simple_sort.
In particular:
void read_file(int *a) {
FILE *file;
int i;
/* a[N] = { 0 };*/
...
}
void method_simple_sort() {
int a[N], i = 0, k = 0, ind_max = 0, temp = 0;
read_file(a);
...
}

C, Filling a 2D array by tokenizing string

I'm trying to fill a 2d array by comma seperated integers.
I have already allocated the space for a 3x3 array. Now, I'm trying to loop through each line of input text to grab integers and place them in the array.
Here is what I have so far:
char currLine[257];
char *token;
for(int i = 0; i < size; i++){
fgets(currLine, 257, inputFile);
for(int j = 0; j < size; j++){
}
}
The text is formatted as follows:
9,8,7
2,1,6
3,4,5
I can successfully grab each line, but from there I keep running into troubles. After I get each number, I of course want it to go into the [i][j] spot of the array. So the first line corresponds to [0] and the first value corresponds to [0][0].
Tokenizing the formatted text you provided is trivial. Take a look at the following code. You can change the code if your are targeting float numbers. In my code, I'm assuming integer numbers.
#include <stdio.h>
#include <string.h> /* strlen() & memset() */
#include <stdlib.h> /* atoi() */
void getNumbers(const char* ch, int *a, int *b, int *c)
{
int i;
int size = strlen(ch) + 1;
char ar[100];
int n[3];
int j = 0;
int k = 0;
for(i = 0; i < size; ++i){
if( ch[i] != ',' )
ar[j++] = ch[i];
if ( ch[i] == ',' || i == size-1) {
ar[j] = '\0';
n[k++] = atoi(ar);
memset(ar, 0, sizeof(ar));
j = 0;
}
}
*a = n[0];
*b = n[1];
*c = n[2];
}
int main()
{
char *num = "1256,524,765";
int n1,n2,n3;
getNumbers(num,&n1, &n2, &n3);
printf("%d %d %d\n", n1,n2,n3);
return 0;
}
The result is
1256 524 765

Search an array - replace values with values from another array in C

I am new to programming and I trying to build different kinds of fun little applications in order to understand the basics. I have started with C to really start out at the bottom, so the below refers to C.
So basically I have to arrays a[] and replace[], which are both 200 long filled with random numbers.
I want to search a[] for the value 32 (ele) and replace any occurrence of that value with the corresponding value in replace[].
E.g. if: a[22] = 32, replace[22] = 78 => a[22]=78
At the same time I would like it to 'record' the index number (22) and log that to a file.
I can't get it to go through a[] multiple times and replace every instance. It only replaces 1 instance and then breaks.
I have no error msg. for below code. Hope you can help a newbie out.
If you have the answer, please also take a minute to explain how/why.
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
FILE *ifp, *ofp;
int ix;
int ik;
int i;
int change;
int count = 0;
int ele = 32;
int num = 200;
int a[200];
int replace[200];
void swap(int a[], int replace[], int change)
{
int temp = replace[change];
a[change] = replace[change];
a[change] = temp;
ifp = fopen("/Users/kjaerolsen/tmp/ilog.txt", "a+");
fprintf(ifp, "%d\n", change);
fclose(ifp);
}
int main(int argc, char *argv[]) {
// creates array with random numbers to draw new numbers from.
srand(time(NULL));
for (int ik = 0; ik < 200; ik++)
{
rand();
replace[ik] = rand() % 200; // / rand_max;
}
for (int ik = 0; ik < 200; ik++)
{
fprintf(ifp, "%d\n", replace[ik]);
}
// creeates main array with random numbers.
srand(time(NULL));
for (int ix = 0; ix < 200; ix++)
{
rand();
a[ix] = rand() % 200; // / rand_max;
}
for (int ix = 0; ix < 200; ix++)
{
printf("plads %d i array: %d\n",ix, a[ix]);
}
// Looks for number 32 (ele) in array
i = 0;
for (int i =0; i < 200; i++)
{
change++;
swap(int a[], int replace[], int change)
count++;
}
if (count == 0)
printf("%d is not present in array.\n", ele);
else
printf("%d is present %d times in array.\n", ele, count);
// Opens the file and rewrites the new array.
ifp = fopen("file1.txt", "w+");
for (int ix = 0; ix < 200; ix++)
{
fprintf(ifp, "%d\n", a[ix]);
}
fclose(ifp);
printf("very done...");
return (0);
}
Must fopen ifp before the second loop and fclose it after. Your current code goes segmentation fault:
ifp = fopen( ... );
for (int ik = 0; ik < 200; ik++)
{
fprintf(ifp, "%d\n", replace[ik]);
}
fclose( ifp );
Also, you can swap with three XOR:
a ^= b;
b ^= a;
a ^= b;
and no temp variables;
A tremendous thanks for all your help. I finally succeeded in making it work - and it is beautiful. I moved it out of an actual function and in to the loop, since there was no reel need to call a function. Secondly, I was missing the top IF. But most important #micarelli your suggestions with XOR did the trick.
Maybe not much for a couple of hardcore coders like yourself, but it was really satisfying.
I posted the final snippet of code below.
i = 0;
for (int i =0; i < 200; i++)
if (a[i] == ele)
{
a[i] ^= replace[i];
count++;
}
if ( count == 0 )
printf("%d is not present in array.\n", ele);
else
printf("%d is present %d times in array.\n", ele, count);
// Opens the file and rewrites the new array.
ifp = fopen("/Users/kjaerolsen/tmp/file1.txt", "w+");
for (int ix = 0; ix < 200; ix++)
{
fprintf(ifp, "%d\n", a[ix]);
}
fclose(ifp);

Allocating memory dynamically to a 2-d array of strings

int ReadNames(char ***Names, int *r,int *c)
{
int i, j, k;
char name[100];
printf("Number of Rows: ");
scanf("%d", r);
printf("Number of Columns: ");
scanf("%d", c);
Names=(char ***)malloc(sizeof(char **)*(*r));
for(i=0;i<(*r);i++)
*(Names+i)=(char **)malloc(sizeof(char *)*(*c));
for(i=0;i<(*r);i++)
for(j=0;j<(*c);j++)
{
fflush(stdin);
gets(name);
strcpy(*(*(Names+i)+j),name);
}
return 1;
}
I am trying to allocate the memory to a 2-D array of strings. Later on i want to sort them row wise and column wise, but while allocating the memory , the program is not responding. Is there something i am doing in my code.
in main function readname is called as
ReadNames(&p,&r,&c)
where r and c are the no. of rows and columns.
You need:
*Names = (char **)malloc(sizeof(char **) * (*r));
and consequential changes.
You're passing a triple-pointer in order to be able to return a double-pointer. What you're doing is losing the information about where to store the double-pointer.
There is some truth to the struck out comment; there is also a miscue. A 2D array of strings means that you have three levels of pointer in the basic data. And you need a fourth level of pointer to pass into the function.
Also, using gets() is a recipe for disaster. Don't ever (as in never, as in never ever) use the the gets() function. Not even in toy programs. It gets you into bad habits. The first Internet worm propagated through a program that used gets() (Google search 'morris internet worm').
On Unix and other POSIX-based systems, using fflush(stdin) leads to undefined behaviour. On Windows, the behaviour is defined by Microsoft. If you're running on Windows, then you're OK; if not, you're not.
And I thought Three-Star Programming was bad!
This probably isn't the way I'd do it, but it is a pretty direct translation of what you wrote into something that works, along with a main() program that tests it and frees all the allocated memory. It assumes strdup() is available; if not, it is trivial to write it.
Sample output:
Number of Rows: 2
Number of Columns: 3
R0C0: Row 1, Column 1.
R0C1: Ambidextrous Armless Individual.
R0C2: Data for the third column of the first row.
R1C0: Row 2, Column 1.
R1C1: Row 2, Column 2.
R1C2: Given that the number of rows is 2 and the number of columns is 3, this should be the last input!
Rows = 2, cols = 3.
[0,0] = <<Row 1, Column 1.>>
[0,1] = <<Ambidextrous Armless Individual.>>
[0,2] = <<Data for the third column of the first row.>>
[1,0] = <<Row 2, Column 1.>>
[1,1] = <<Row 2, Column 2.>>
[1,2] = <<Given that the number of rows is 2 and the number of columns is 3, this should be the last input!>>
Working 4-star code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
static void ReadNames(char ****Names, int *rows, int *cols)
{
char name[100];
printf("Number of Rows: ");
scanf("%d", rows);
printf("Number of Columns: ");
scanf("%d", cols);
int c;
while ((c = getchar()) != EOF && c != '\n')
;
*Names = (char ***)malloc(sizeof(char ***)*(*rows));
for (int i = 0; i < (*rows); i++)
(*Names)[i] = (char **)malloc(sizeof(char **)*(*cols));
for (int i = 0; i < (*rows); i++)
{
for (int j = 0; j < (*cols); j++)
{
printf("R%dC%d: ", i, j);
if (fgets(name, sizeof(name), stdin) == 0)
{
fprintf(stderr, "Unexpected EOF\n");
exit(1);
}
name[strlen(name)-1] = '\0'; // Zap newline
(*Names)[i][j] = strdup(name);
}
}
}
int main(void)
{
int rows;
int cols;
char ***data = 0;
ReadNames(&data, &rows, &cols);
printf("Rows = %d, cols = %d.\n", rows, cols);
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
printf("[%d,%d] = <<%s>>\n", i, j, data[i][j]);
}
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
free(data[i][j]);
free(data[i]);
}
free(data);
return 0;
}
Alternative 3-star code
Using three levels of pointer is bad enough; four is horrid. This code restricts itself to three levels of pointer. I assume C99 compatibility, so variables can be declared when convenient in a function. The changes to work with C89/C90 compilers (which are 14 years retrograde now) are simple enough.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static char ***ReadNames(int *r, int *c)
{
int i, j;
char name[100];
printf("Number of Rows: ");
scanf("%d", r);
printf("Number of Columns: ");
scanf("%d", c);
int x;
while ((x = getchar()) != EOF && x != '\n')
;
char ***Names = (char ***)malloc(sizeof(char ***)*(*r));
for (i = 0; i < (*r); i++)
Names[i] = (char **)malloc(sizeof(char **)*(*c));
for (i = 0; i < (*r); i++)
{
for (j = 0; j < (*c); j++)
{
if (fgets(name, sizeof(name), stdin) == 0)
{
fprintf(stderr, "Unexpected EOF\n");
exit(1);
}
name[strlen(name)-1] = '\0';
Names[i][j] = strdup(name);
}
}
return Names;
}
static void PrintNames(char ***Names, int r, int c)
{
int i, j;
for (i = 0; i < r; i++)
{
for (j = 0; j < c; j++)
printf("%s ", Names[i][j]);
printf("\n");
}
}
int main(void)
{
int rows;
int cols;
char ***data = ReadNames(&rows, &cols);
PrintNames(data, rows, cols);
printf("Rows = %d, cols = %d.\n", rows, cols);
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
printf("[%d,%d] = <<%s>>\n", i, j, data[i][j]);
}
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
free(data[i][j]);
free(data[i]);
}
free(data);
return 0;
}
Example output
Number of Rows: 3
Number of Columns: 4
R1C1
R1C2
R1C3
R1C4-EOR
R2C1
R2C2
R2C3
R2C4-EOR
R3C1
R3C2
R3C3
R3C4-EOR
R1C1 R1C2 R1C3 R1C4-EOR
R2C1 R2C2 R2C3 R2C4-EOR
R3C1 R3C2 R3C3 R3C4-EOR
Rows = 3, cols = 4.
[0,0] = <<R1C1>>
[0,1] = <<R1C2>>
[0,2] = <<R1C3>>
[0,3] = <<R1C4-EOR>>
[1,0] = <<R2C1>>
[1,1] = <<R2C2>>
[1,2] = <<R2C3>>
[1,3] = <<R2C4-EOR>>
[2,0] = <<R3C1>>
[2,1] = <<R3C2>>
[2,2] = <<R3C3>>
[2,3] = <<R3C4-EOR>>
Both programs run clean under valgrind.
So, this is the code working...
*Names=(char **)malloc(sizeof(char **)*(*r));
for(i=0;i<(*r);i++)
*(*Names+i)=(char*)malloc(sizeof(char *)*(*c));
for(i=0;i<(*r);i++)
for(j=0;j<(*c);j++)
{
fflush(stdin);
gets(name);
strcpy((*(*Names+i)+j),name);
}
but while printing those names stored...i have a function provided..
int PrintNames(char **Names, int r, int c)
{
int i,j;
for(i=0;i<r;i++)
{ printf("\n");
for(j=0;j<c;j++)
printf("%s ",*(*(Names+i)+j));
}
return 1;
}
Now this PrintNames is also called through main...as "PrintNames(p, r, c);"....but program stops while printing...What could be wrong?

How to change every second elements of array in c using for loop?

I'm using a for loop to create an 100 element array of char. I on the first run, I want to change all of its values to 1, the second run, I want its every second values to 0
char array[ 100 ] = { 0 };
int toggle_swith(char a[]) {
for (i = 0; i < 100; i++) {
printf(array[i] + "1 ");
}
}
int main( void ) {
int i;
for (i = 0; i < 100; i++) {
printf(array[i] + "0 ");
toggle_switch();
}
}
You need a function which initializes the array:
void InitializeArray(char Array[], int Length) {
int i;
for (i = 0; i < Length; i++) {
Array[i] = '1';
}
}
You need a function which changes every 2nd element:
void ChangeEverySecondElement(char Array[], int Length) {
int i;
for (i = 1; i < Length; i += 2) {
Array[i] = '0';
}
}
You need a function to print the array :
void PrintArray(char Array[], int Length) {
int i;
for (i = 0; i < Length; i++) {
putchar(Array[i]);
putchar(' ');
}
putchar('\n');
}
Then you need to put them together
int main() {
char Array[100];
InitializeArray(Array, 100);
PrintArray(Array, 100);
ChangeEverySecondElement(Array, 100);
PrintArray(Array, 100);
return 0;
}
If you are trying to learn C, I recommend the book I learned it from, C by Example written by Greg Perry.
you can do it all at once
for (i=0; i<100; i++) array[i]=(i%2)+'0';
a typical attempt at optimization could look like:
#define BUFSZ 100
int main(){
char buf[BUFSZ];
int *bp=(int *)&buf, i=(BUFSZ/sizeof(int));
/* handle aligned words 4 bytes at a time */
while (i) bp[--i]='0101'; /* for 64 bit use '0101'|('0101' <<32) */
/* handle unaligned bytes */
for(i=(BUFSZ/sizeof(int))*sizeof(int);i<BUFSZ;i++)buf[i]=1-i%2+'0';
write(1,buf,BUFSZ);
}
Initially you want to make all your array elements as 1
You can use memset
memset(array,1,100)
This will clear all elements. But if you insist on using a loop then,
#define ARRAY_SIZE 100
char array[ARRAY_SIZE] = {0};
for(int count = 0; count < ARRAY_SIZE; count++)
{
array[count] = 1;
//If you want to print it, use:
printf("%d",array[count]; // You can also use %c
}
To make alternate element 0,
for(int count = 0; count < ARRAY_SIZE; (count = count + 2)) //Count + 2 will hop every alternate element
{
array[count] = 0;
}
Again, You can add printf() if you want.
Print statement should look something like this.
printf("%c0",array[i]);
I suggest you look up Beginner C tutorial for more info.

Resources