How can I store a list of strings in an array in c. cause usually the a string e.g:'string' is stored as s|t|r|i|g in array(?). now if i have an array that has 10 index and want to store string in each one of those indexes, how do i do it? if not doable, what other data structure can i use for it.
e.g: array = 'string1'|'string2'|..
i have done something, but its not working:
// Array for name of alphabets, and name of states
35 char *nameOfStates[numStates];
36 char buffer[3];
37
38 // Read the nameOfStates
39 int i;
40 for(i=0;i<numStates;i++){
41 printf("Name of STATES:");
42
43 int z=0;
44 char *buffer2;
45 while(z<2 && fgets(buffer,2,stdin) != NULL){
46
47 buffer2 = strndup(buffer,2);
48 z++;
49 }// End while-loop
50 nameOfStates[i] = buffer2;
51
52 }// End of for-loop to read nameOfStates
EDIT: I realized that array[size] doesn't actually work! I did it cause of my java backgroun d and i thought it might work. so i changed the program but it still is throwing segmentation fault. I post the full(edited) program below:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
// Function declaration
void analyze(char *string);
void clearNewLines(void);
int main(int argc, char *argv[]){
// Number of states and number of alphabets of DFA
int numStates;
int numAlphabets;
// Read numStates
printf("Enter the number of STATES:");
scanf("%d",&numStates);
// Flush STDIN
clearNewLines();
// Array for name of alphabets, and name of states
char **nameOfStates = malloc(numStates*sizeof(char*));
char *buffer = NULL;
// Read the nameOfStates
int i;
for(i=0;i<numStates;i++){
printf("Name of STATES:");
fgets(nameOfStates[i],2*sizeof(char),stdin);
}// End of for-loop to read nameOfStates
clearNewLines();
// Read numAlphabets
printf("Enter the number of ALPHABETS: ");
scanf("%d", &numAlphabets);
// Flush STDIN
clearNewLines();
// Array for name of alphabets, and name of states
char nameOfAlphabets[numAlphabets];
// Saving transition table
char *transitionTable[numStates][numAlphabets];
// Read name of alphabets
int j;
for(j=0;j<numAlphabets;j++){
printf("Name of ALPHABETS:");
nameOfAlphabets[j] = getchar();
// Flush STDIN
clearNewLines();
}// End for-loop to read alphabets
// Get the transitionTable[states][alphabets]
int row;
for(row=0;row<numStates;row++){
int col;
for(col=0;col<numAlphabets;col++){
printf("Enter Transition From %s to %c: ",nameOfStates[row],nameOfAlphabets[col]);
printf("\n");
}
}
return 0;
}// End of main function
/*
*
* clearNewLines - clear any newline character present at the STDIN
*/
void clearNewLines(void)
{
int c;
do
{
c = getchar();
} while (c != '\n' && c != EOF);
}
First: you cannot define an array size with a variable. I mean: char buf[variable]; doesn't work.
You have to do like this:
char **buf;
buf = malloc(sizeof(char) * number_of_strings);
if (buf == NULL)
return (MALLOC_ERROR);
Or with a macro like this:
// in your header file
#define BUF_SIZE 12
// in your .c file
char *buf[BUF_SIZE];
Then you also have to malloc the 2nd dimension of your array.
For example :
int i;
i = 0
while (buf[i])
{
buf[i] = malloc(sizeof(char) * string_length);
if (buf[i] == NULL)
return (MALLOC_ERROR);
i++;
}
And don't forget to free all dimensions of your array.
An array of arrays is the way to go.
// Array of size 5 (Don't forget to free!)
char **arrayOfStrings = malloc(5*sizeof(char*));
char *aString = "Hi";
arrayOfStrings[0] = aString;
//Literals work too
arrayOfStrings[1] = "Hallo";
aString = "Ahoy";
arrayOfStrings[2] = aString;
ArrayOfStrings values at end: Hi | Hallo | Ahoy | | |
Related
So, I need to use the stdin to read a file that has two columns, the first one is a char, the second is an integer.
The input file is something like this:
i 10
i 20
i 30
i 40
i 50
i 45
r 48
My code currently:
int main(){
char line[MAX];
int n = 0;
while(fgets(line, MAX, stdin)){
printf("string is: %s\n",line);
}
return 0;
The output results in:
string is: i 10
string is: i 20
string is: i 30
string is: i 40
string is: i 50
string is: i 45
string is: r 48
So, what i need to do now is to assign an char array with the first column and an integer array with the second. Something like int V[size] = [10,20,30,40,50,45,48] and char W[size] = [i,i,i,i,i,i,r]. How can I do that?
Use sscanf() to parse the string and extract the data you want.
#include <stdio.h>
#include <stdlib.h>
#define MAX 500
int main(void)
{
int num[MAX] = {0}, lines = 0;
char line[MAX] = {0}, sym[MAX] = {0};
while (fgets(line, MAX, stdin))
{
if (lines >= MAX) /* alternative check comments */
{
fprintf(stderr, "arrays full\n");
break; /* break or exit */
}
if (sscanf(line, "%c %d", &sym[lines], &num[lines]) != 2) /* check return value for input error */
{
/* handle error */
exit(EXIT_FAILURE);
}
lines++;
}
for (int i = 0; i < lines; i++)
{
printf("char: %c | num: %d\n", sym[i], num[i]);
}
exit(EXIT_SUCCESS);
}
You may also use feof() and ferror() to determine if fgets() failed or you reached EOF .
I am able to read chars, words, sentences and integers from separate files but I am struggling to read words and integers from the same file. Let's say my file contains the following:
Patrice 95
Rio 96
Marcus 78
Wayne 69
Alex 67
Chris 100
Nemanja 78
My partial solution (to read in strings) so far was to use fgetc() and check for spaces and or carriage returns in my text file to separate the name from the number.
The main issue with fgetc is that it reads in character by character, and so integers are not meant to be read in like this. As a workaround, I am converting the character to an integer whenever a number is read in.
This is the main code structure:
typedef struct person {
char name[10][10];
char surname[10][10];
int age [10];
} person_t;
FILE *inp; /* pointer to input file */
char c;
int word_count = 0;
int char_count = 0;
int i = 0;
int x;
person_t my_person;
while ((c = fgetc(inp)) != EOF) {
if (c == ' ' || c == '\r') {
printf("\n");
my_person.name[word_count][char_count] = '\0'; //Terminate the string
char_count = 0; //Reset the counter.
word_count++;
}
else {
if (c >= '0' && c <= '9') {
x = c - '0'; //converting to int
my_person.age[i] = x;
printf("%d", my_person.age[i]);
i++;
}
else {
my_person.name[word_count][char_count] = c;
printf("%c",my_person.name[word_count][char_count]);
if (char_count < 19) {
char_count++;
}
else {
char_count = 0;
}
}
}
}
}
for (int i = 0; i<7; i++) {
printf("ages: %d \n",my_person.age[i] ); //never executes
}
Sample Output:
Patrice
95
Rio
96
Marcus
78
Wayne
69
Alex
67
Chris
Full code can be found on pastebin.
Why is the for loop never executing? Any suggestions on what I can improve to read the columns of strings and integers?
Use fgets() to read a whole line.
char line[100];
while (fgets(line, sizeof line, inp)) {
// got a line, need to isolate parts
}
Then, depending on whether the words can have embedded spaces choose one of the strategies below.
a) sscanf() to isolate name and age
while (fgets(line, sizeof line, inp)) {
char name[30];
int age;
if (sscanf(line, "%29s%d", name, &age) != 2) /* error, bad line */;
// ...
}
b) strrchr() to find the last space, then string manipulation to extract name and age.
while (fgets(line, sizeof line, inp)) {
char name[30];
int age;
char *space = strrchr(line, ' ');
if (!space) /* error, bad line */;
if (space - line >= 30) /* error, name too long */;
sprintf(name, "%.*s", space - line, line);
age = strtol(space, NULL, 10); // needs error checking
// ...
}
strategy b) on https://ideone.com/ZOLie9
I'm having a harsh time achieving this. I read a string of integer, extract them from that chain and put them in an array. I wanted to try something new because a used to read character by character with getChar in the past, but now I find sscanf which handle the job.
From Doc (sscanf) :
On success, the function returns the number of items in the argument list successfully filled. This count can match the expected number of items or be less (even zero) in the case of a matching failure.
In the case of an input failure before any data could be successfully interpreted, EOF is returned.
line : char line[] = "100 185 20 11 1000"; // number of int is unknown, it can differ
Problem: How to make diffrence between end of line and a whatever error
Eg: char line[] = "100 185 abc(not int) 11 1000";
Code :
int main(int argc, char** argv) {
char line[] = "100 185 20 11 1000";
int arrOfInt[10];
char *data = line;
int track, number, index = 0;
while ((sscanf(data, " %d%n", &number, &track)) == 1)
{
arrOfInt[index] = number;
data += track;
index++;
}
return 0;
}
#BLUEPIXY mentioned the correct answer. Just formalizing it here.
If the return value of scanf is EOF that means an EOF is seen. If it is 0 that means some other error has occurred and the value set via %n is undefined(eg. the input does not match the format specified).
The following approach works as long as there are no tokens with mixed alphabets and letter like "hey45hey2".
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv) {
char line[] = "100 185 20 11 1000 sdf 342 hey45hey2";
int arrOfInt[10];
char *data = line;
int track, status = 0, number, index = 0;
// read until an EOF is found
while ((status = sscanf(data, " %d%n", &number, &track)) != EOF)
{
// store only if status is non-zero i.e. sscanf has read according to the format specified
if(status != 0){
arrOfInt[index] = number;
index++;
}
else
track=1;
data += track;
}
// print the array back to check if we read correctly
int i;
for(i=0;i<index;i++)
printf("%d ", arrOfInt[i]);
return 0;
}
The output of this code is:
100 185 20 11 1000 342 45 2
If you want to exclude strings like "hey45hey2" from the output, then use the following.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv) {
char line[] = " egsdfgfd rgege 100 185 20 11 hey45hey2 0d0 00 sddbrsdtbrtsdbrsf 342";
int arrOfInt[10];
char *data = line;
int track, status = 0, index = 0;
char str[100]; // will fail for tokens of length more than 100
// read until an EOF is found
while ((status = sscanf(data, "%s%n", str, &track)) != EOF)
{
// store only if status is non-zero
if(status != 0){
// check if str is all zeros
int num=(int)strtol(str,0,10);
char *i = str;
if(num == 0){
while(*i){
if(*i != '0') break;
i++;
}
}
if(*i == 0 || num != 0){
// if *i is zero, then num is also zero
arrOfInt[index] = num;
index++;
}
}
else
track = 1;
data += track;
}
// print the array back to check if we read correctly
int i;
for(i=0;i<index;i++)
printf("%d ", arrOfInt[i]);
return 0;
}
Output is 100 185 20 11 0 342
How to make diffrence between end of line and a whatever error
Sorry to say this, but the answer is: Drop sscanf, and do the parsing yourself.
If, for what ever reasons, you need/want to stick to sscanf you could always do a test on the "string" after sscanf is done, to see if there is more after the last token read, as you know the number of tokens parsed. You would do this for example by tokenizing the string beforehand using strtok on whitespaces, if you scanned in few, then you'd advance the string pointer behind the last+1 token and continue using sscanf. But is this sane? ;-)
I achieved what I really wanted to do by using your advice. Just to mention that when I find undesired character I have to leave my loop and show error.
Code(can be useful for others)
int main(int argc, char** argv) {
char line[] = "100 185 20 11 1000"; // or "100 185 abc 11 1000"
int arrOfInt[10];
char *data = line;
int track, number, index = 0;
int statutLine;
while ((statutLine = sscanf(data, " %d%n", &number, &track)) == 1)
{
arrOfInt[index] = number;
data += track;
index++;
}
if(statutLine == 0){
printf("Line invalide");
}
if(statutLine == EOF){
printf("Line valide");
}
return 0;
}
The input is
name number number
like the example
bank 1 10
I need to read input into a matrix n lines by 3 columns like the next example
{ bank, 1, 10,
bank2, 2, 15,
bank3, 3, 20 }
My main difficulty is reading the name and storing into the matrix. The name can vary from 1 to 41 characters.
I tried doing it the following way but I don't know a way to ignore the blank spaces in the input and how to make the for loop only count until the word is read.
for (b=0; b<41;b++) {
scanf("%s ",&nome[i]);
}
scanf("%d %d",&rating,&ref);
n[i][0] = *nome;
n[i][1] = rating;
n[i][2] = ref;
I just started learning programming in C so I can't use advanced things in my code.
You are trying to read a string one character at a time, but using the edit descriptor for reading a whole string. You're trying to make it harder than it needs to be.
Also, the term "matrix" is normally understood to mean a 2-dimensional array of elements all the same type, whereas it sounds like you want a 1-dimensional array of structs containing members of different types. For example:
#define MAX_BANKS 10
struct bank {
char nome[42];
int rating;
int ref;
};
struct bank banks[MAX_BANKS];
int num_banks = 0;
/* ... */
void read_banks(void) {
while (num_banks < MAX_BANKS) {
int fields;
fields = scanf("%41s %d %d", banks[num_banks].nome,
&banks[num_banks].rating, &banks[num_banks].ref);
if (fields != 3) {
/* handle error */
break;
} else {
num_banks += 1;
}
/* ... */
}
}
In this example I have interpreted your "matrix" requirement, such that each line of the input fills in a struct having different field types, so we end up with a 1-D array of the struct instead of a 2-D array of differing data types.
And instead of entering the data from the keyboard, which is so boring every time you test the program, I have put your data in a file and read from that - although the technique is quite similar.
Also, because your input format is not consistent, I have skipped any chars that don't form part of the data, see delims.
The program is possibly rather more complicated than you would have liked, but I hope it can help you do what you want. The complexity level rose when I decide not to use a fixed length string in the struct but a pointer to string memory, allocated for a variable length string.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char *nome;
int rating;
int ref;
} customer;
void fatal(char *msg) {
printf("%s\n", msg);
exit (1);
}
int main()
{
FILE *fp; // for fopen
char line[1000]; // for fgets
char *delims = ", {}\t\r\n"; // for strtok
char *sptr; // for strtok
customer *mark = NULL; // an empty array
int marks = 0; // number of customers
int len; // length of input string
fp = fopen("input.txt", "r"); // open the file
if (fp == NULL) // did it open?
fatal("Cannot open file");
while (fgets(line, 1000, fp) != NULL) { // each line of file
mark = realloc(mark, sizeof(customer) * (marks+1)); // extend
if (mark == NULL)
fatal("Cannot extend array"); // failed extend the array
sptr = strtok(line, delims); // split first field
if (sptr == NULL)
fatal("Cannot get first field");
len = strlen(sptr); // length of bank name
mark[marks].nome = malloc(len+1); // memory for the string
if (mark[marks].nome == NULL)
fatal("Cannot allocate string array");
strcpy(mark[marks].nome, sptr); // copy string to struct
sptr = strtok(NULL, delims); // split second field
if (sptr == NULL)
fatal("Cannot get second field");
mark[marks].rating = atoi(sptr); // extract number
sptr = strtok(NULL, delims); // split third field
if (sptr == NULL)
fatal("Cannot get third field");
mark[marks].ref = atoi(sptr); // extract number
marks++; // one more record
}
fclose (fp);
// print the results (re-using len for convenience)
for (len=0; len<marks; len++)
printf("%s %d %d\n", mark[len].nome, mark[len].rating, mark[len].ref);
// release the data array
for (len=0; len<marks; len++)
free(mark[len].nome);
free(mark);
return 0;
}
Input file:
{ bank, 1, 10,
bank2, 2, 15,
bank3, 3, 20 }
Program output:
bank 1 10
bank2 2 15
bank3 3 20
Since you are working with a collection of different types of information (e.g. char*, int, int), the proper way to collect this information is in a structure (or struct). You have two choices on how to create space for any array or array of struct, (1) statically allocate on stack, or (2) dynamically allocate on heap. Given your question requirement, static allocation is the most basic. However, it is not as flexible as dynamically allocating the data, and you are limited to the initial size you choose.
Just as with storing the data, you have choices on how you read the data from stdin. As a general proposition, when reading from stdin, the preferred way is to read a line-at-a-time into a buffer and then parse the buffer for the desired content. Just as above, line input is more flexible than squeezing the data into a scanf format string, but is a bit more involved. For purposes here, we will use scanf, but know that line-input with getline or fgets provide certain advantages.
Next, you can just declare the number of structs you need, or you can take the time to initialize all the values in each of the structs. (this has advantages as you will see below). Aside for allowing some iteration tricks, the primary reason you initialize all your variables is to prevent the possibility of reading from them uninitialized. Reading an uninitialized variable results in Undefined Behavior (bad). So take the time to learn how to initialize each of your variable types.
With that said, you can tell there are a number of valid ways to approach any problem. How you do it is up to you, as long as you do it correctly. Here is another approach to meet your requirements. Note that the maximum name length MAXNM and maximum number of lines to read MAXLN are defined at the top of the code. This allows you to easily adjust the values later on. Let me know if you have any questions:
#include <stdio.h>
#define MAXNM 41
#define MAXLN 100
typedef struct mix {
char name[MAXNM + 1];
int num1;
int num2;
} mix;
int main (void) {
/* initialize array of structs & variables */
mix array[MAXLN] = {{ {0}, 0, 0 }};
size_t i = 0;
size_t read = 0;
/* read array of struct contents from stdin */
while (scanf ("%s %d %d", array[i].name, &array[i].num1, &array[i].num2) == 3) {
i++;
/* check if lines > MAXLN allowed */
if (i >= MAXLN) {
fprintf (stderr, "warning: lines read from stdin exceed MAXLN.\n");
break;
}
}
/* set the number of elements read to i */
read = i;
/* iterate over elements using 'read' */
printf ("\nIterating array using 'while (i < read)'\n\n");
i = 0;
while (i < read) {
printf (" array[%zu] %-41s %4d %4d\n", i, array[i].name, array[i].num1, array[i].num2);
i++;
}
/* iterate over array by virtue of initization of name to 0/null */
i = 0;
printf ("\nIterating array using 'while (array[i].name[0])'\n\n");
while (array[i].name[0]) {
printf (" array[%zu] %-41s %4d %4d\n", i, array[i].name, array[i].num1, array[i].num2);
i++;
}
printf ("\n");
return 0;
}
Input
$ cat dat/staticstruct.txt
TheNamesofVaryingWidth 123 456
SomeOtherName 234 567
Bank_1 12 34
Bank_2 23 45
Bank_3 34 56
OneLastNameThatHasCloseToTheMaximumChars 777 9999
Output
$ ./bin/ptrarraystatic < dat/staticstruct.txt
Iterating array using 'while (i < read)'
array[0] TheNamesofVaryingWidth 123 456
array[1] SomeOtherName 234 567
array[2] Bank_1 12 34
array[3] Bank_2 23 45
array[4] Bank_3 34 56
array[5] OneLastNameThatHasCloseToTheMaximumChars 777 9999
Iterating array using 'while (array[i].name[0])'
array[0] TheNamesofVaryingWidth 123 456
array[1] SomeOtherName 234 567
array[2] Bank_1 12 34
array[3] Bank_2 23 45
array[4] Bank_3 34 56
array[5] OneLastNameThatHasCloseToTheMaximumChars 777 9999
How can I create an array of unique strings without knowing how many strings there are until I process the input file? There can be as many as 2 million strings, max length of 50.
My program is something like this. This works for 51 items then overwrites other data. I don't know how to add an element to the array, if possible.
main() {
char *DB_NAMES[51]; // i thought this gave me ptrs to chunks of 51
// but it's 51 pointers!
char *word;
while not eof {
...function to read big string
...function to separate big sting into words
...
processWord(ctr, DB_NAMES, word);
...
}
}
processWord(int ndx, char *array1[], char *word){
...function to find if word already exists...
//if word is new, store in array
array1[ndx]= (char *)malloc(sizeof(51)); // isn't this giving me a char[51]?
strcpy(array1[ndx],word);
...
}
You can first get the number of words in your file using the below logic and when you get the number of words in the file you can initialize the array size with the word count.
#include<stdio.h>
#define FILE_READ "file.txt"
int main()
{
FILE * filp;
int count = 1;
char c;
filp = fopen(FILE_READ, "r");
if(filp == NULL)
printf("file not found\n");
while((c = fgetc(filp)) != EOF) {
if(c == ' ')
count++;
}
printf("worrds = %d\n", count);
return 0;
}
Regards,
yanivx
Better not use a fixed string length; save memory space.
char **DB_NAMES = 0; // pointer to first char * ("string") in array; initially 0
Pass pointer by reference so that it can be altered. Moreover, you'll want the new ctr value in case a new word has been stored.
ctr = processWord(ctr, &DB_NAMES, word);
Change function processWord accordingly.
int processWord(int ndx, char ***array1a, char *word)
{ char **array1 = *array1a;
...function to find if word already exists...
// if word is new, store in array
{
array1 = realloc(array1, (ndx+1)*sizeof*array1); // one more string
if (!array1) exit(1); // out of memory
array1[ndx++] = strdup(word); // store word's copy
*array1a = array1; // return new array
}
return ndx; // return count
}