Access string's characters from array of pointers to strings - c

I am new to programming and have faced this particular problem:
int *FindLine(char *lines[100],int line_number) {
char **pointer=lines;
int i,*stack,counter=0;
stack=(int*)calloc(30,sizeof(int));
for (i=0;i<line_number;i++)
if (*pointer[i]=='{') {
stack[counter]=i+1;
counter++;
}
return stack;
}
main(){
char *line[100];
FILE *fp;
char FileName[20];
char Buffer[100];
fp=fopen(FileName,"r");
while(fgets(Buffer,100,fp)!=NULL) {
line[i]=strdup(Buffer);
i++;
}
NumOfLines=i;
Stack=FindLine(line,NumOfLines);
system("PAUSE");
}
stack is supposed to have stored the number of the line each '{' appears in , instead it only stores it if '{' is the first char on the line. is there a way on C to access every single individual character of the strings pointed by the pointers in the array of pointers to strings ?

Change
if (*pointer[i]=='{')
to
if (!strchr(pointer[i],'{'))
You may need to add
#include <string.h>
at the beginning.
pointer[i] points to the string (array of chars).
*pointer[i] gives you the first character of the string.
So your if condition checks only the first character.
So you have to use strchr
strchr checks if the '{' char is there anywhere in the string. returns the pointer to first occurance if found or 0/NULL if not found.

Related

How to read part of string into smaller string

I am reading a line from a .txt file. My goal right now is to read the first word of the line. I have the line stored in a string declared char *text. Then I have a double pointer to that string char** charReader which will read the letters of the string. I am trying to read the characters in one by one into a new string char* word, and stop when I hit a space, however I have gotten a segmentation fault in doing so.
Here is my code to perform that function:
while(isalpha(**charReader) != 0){
word[i] = **charReader;
charReader++;
i++;
}
My goal is to output the value of word. But my code seems to be giving me a segmentation fault.
The variable charReader is a pointer to a pointer to char (you can think of it as being an array of strings or a matrix of chars), while the variable word is a string (an array of chars). Therefore, when you do:
word[i] = **charReader;
you are trying to make an assignment involving incompatible types (treating a double pointer to char as if it was a char). That's why you are getting an error.
To copy the first word of a string into another string, you can try something like this:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main()
{
char text[] = "This is a string with multiple words.";
int i = 0;
while(i++ < strlen(text) && text[i] != ' '); //seek for the index of the first space character in "text"
char *word = malloc((i + 1) * sizeof(char));
strncpy(word, text, i); //"word" now stores the first word of "text"
printf("%s\n", word);
free(word);
return 0;
}

fscanf Issue-Not able to extract string from file

the program is working when i am using getc but it is not working with this code.
I tried printing random text inside while loop it got printed with NULL.
void main()
{
FILE *fp;
char *str=NULL;
char s;
fp=fopen("text.txt","r");
if(fp==NULL)
{
printf("\nCAN NOT OPEN FILE");
exit(EXIT_FAILURE);
}
while(fscanf(fp,"%s",str)!=EOF)
{
printf("%s",str); //not taking any values in str,prints NULL
}
fclose(fp);
}
The problem is with this statement:
char *str=NULL;
Since you are using fscanf to read words which are character arrays, you have to read them into a valid memory location. So str should be a char array whose length should be equal to the longest word in your file plus 1 (for null termination).
So change the above to:
char str[256];
7.21.6.2 The fscanf function
...
12 The conversion specifiers and their meanings are:
s - Matches a sequence of non-white-space characters.
If no l length modifier is present, the corresponding argument shall be a
pointer to the initial element of a character array large enough to accept the
sequence and a terminating null character, which will be added automatically.
Here
char *str=NULL;
str is a pointer variable & it's initialized with NULL that's very fine but to store something into str i.e to read the word from file, and store into str it should have valid memory. So either allocate memory dynamically for str
str = malloc(SIZE); /* define SIZE */
Or use array of characters like
char str[100]; /* let say each word of file is less than 100 char's */
For e.g
char str[100];
while(fscanf(fp,"%s",str)!=EOF) {
printf("%s",str);
}
Also instead of void main() { } use
int main(void) {
/* some_code */
return 0;
}
as you can see from C Standard 5.1.2.2.1 Program startup.

How do I assign a string from an array to a variable in C (from a function)?

So, all I am trying to do is return a string from an array in a function to a variable in the main() function. Below is my function. It basically searches some files for a word, and returns the string name of the file that contains "START_ROOM":
char startPrompt()
{
//array of files
char* arrayFiles[7]={"Room1.txt", "Room2.txt", "Room3.txt", "Room4.txt", "Room5.txt", "Room6.txt", "Room7.txt"};
//used to store file that has START_FILE in it
char startFile;
int i;
for(i=0;i<7;i++)
{
//pointer to files
FILE *fPointer;
//prints files to output
char loadScreenOutput[800];
char* response[256];
fPointer=fopen(arrayFiles[i], "r");
//checks if the file doesn't exist
if(fPointer== NULL)
{
printf("Unable to open the file!\n");
}
//if file exists, do this.
else
{
while(!feof(fPointer))
{
fgets(loadScreenOutput, 800, fPointer);
if(strstr(loadScreenOutput, "START_ROOM"))
{
return *arrayFiles[i];
}
}
fclose(fPointer);
}
}
The main function is here:
int main()
{
char fileName;
//start the game with the start file
fileName=startPrompt();
printf("%s", fileName)
return 0;
}
Yet, the above leads to a segmentation fault.
If I change the printf to printf("%c", fileName), I will get the first letter of the file, which will be "R".
So, how can I simply get it to return "Room1.txt" and store it in fileName? I am willing to change the variable type of fileName, as I can guess that may be the issue. Or change the return type of the function, as I am guessing that is the issue.
Overwise, I know this code works because if I printf() inside the function, it will print "Room7.txt".
The code is a bit weird, but the main issue is that you expect a single character (i.e. char) to hold a "string", i.e. a sequence of characters. Strings in C are a sequence of characters terminated by special value 0; they are often used with pointers to string literals, written as char* someStringValue = "ABC":
char* str = "ABC"; // str will point to a sequence of characters {'A','B','C',0 }
char c = 'X'; // c will hold a single character 'X';
printf("%s",str); // will print ABC
printf("%s",c); // will probably segfault because c is not a pointer to a sequence of characters, i.e. is NOT A POINTER
printf("%c",c); // prints X
c = *str; // assignes the first character of the sequence to which str points
printf("%c",c); // prints A
To correct your program, write:
char* startPrompt() // char* instead of char; char would be a single character
{
// static; otherwise the variable and its values go out of scope and become invalid once startPrompt has finished
static char* arrayFiles[7]={"Room1.txt", "Room2.txt", "Room3.txt", "Room4.txt", "Room5.txt", "Room6.txt", "Room7.txt"};
...
return arrayFiles[i]; // not *arrayFiles[i], which would be a single character
...
int main() {
char* fileName; // char*, not char
fileName=startPrompt();
printf("%s", fileName)
return 0;
}
A string is actually an array of chars (which is also a pointer to a contiguous group of chars in memory). You need to make the function return a pointer to the first char in you array. Also "*" is not needed in the char array declaration (doing that creates a pointer to the pointer to the first char in the array).

Error in strcmp() when I use a structure as a parameter

My program needs these functionalities:
NOTE: I did not include the codes for the numbers 1,2 & 4 since I already finished them. The 3rd one is my problem.
The program should continuously allow input from the user as long the user still wants to. (Dynamically)
Get the final grade of a student (average of frst_grade, scnd_grade, fnl_grade)
Get the number of students per college.
Get student name by inputting s_id.
My problem is how to compare the search input to the user input in s_college to get the number of students. The only way I know is by using strcmp() but it gives me this error: invalid conversion from 'char' to 'const char*' [-fpermissive]
So how do I compare these two to get the number of students per college?
#include<stdio.h>
#include<string.h>
#include<conio.h>
int i,n,sum,search,num=0,ctr=0;
char answer,choice,choice2,search2;
struct record{
int s_id;
char s_name[100];
char s_course;
char s_college[5];
int s_scoress;
}id[100],name[100],course,college[100],scores;
struct s_scores{
int frst_grade;
int scnd_grade;
int fnl_grade;
}first,second,final;
void ADD();
void COLLEGE();
void ID();
void COLLEGE(){
printf("Enter college (abbreviation only)");
scanf("%s",&search2);
for(i=0;i<num;i++){
if(strcmp(college[i].s_college,search2)==0);
ctr++;
}
printf("The number of students in %s is %d",search2,ctr);
Lets take a look at these (partial) lines:
char ..., search2;
...
scanf("%s",&search2);
...
...strcmp(college[i].s_college,search2)...
The variable search2 is a single character. Trying to put a string into it will write at least two character: The string you read plus the string terminator. That means you will write out of bounds.
You then use the character variable as an argument to strcmp which converts the contents of search2 into a pointer and uses that pointer as a pointer to a string.
Both of these problems will lead to undefined behavior.
Is search2 supposed to be a string? Then declare it as an array, like
char ..., search2[100];
If search2 is supposed to be a single character then first you need to read a single character
scanf("%c", &search2); // Note the changed format to read a single character
And then you need to change your comparison to not use strcmp.
You cannot use strcmp with what is not a null-terminated string. You can write
if(college[i].s_college[0] == search2 && college[i].s_college[1] == '\0')
Don't forget to remove the junk semicolon to have the if statement work.
Your search2 is just a character. You need a string
Perhaps declare search2 as follows:
char search2[50];
Also read up about scanf to prevent buffer overruns:
scanf("%49s", search2); // Do not go past the end of search2[50]
Well compiler tells you error: Variable search2 is char while s_college[5]; is array of chars. Function strcmp requires two arrays/pointers in order to work.
If search2 is only one byte then you can create: char Search2[2]; that would hold that one char and terminal null. But this would work only if search2 is one byte. If you however have to compare two array of chars where search2 is more then one byte, then you should probably think about dynamic allocation or create a static array char search2[some_length];.
this is not a complete 'answer', however, it does fix some of the major problems in the code:
Define your struct's like this;
struct s_scores
{
int frst_grade;
int scnd_grade;
int fnl_grade;
};
struct record
{
int s_id;
char s_name[100];
char s_course;
char s_college[5];
struct s_scores s_scoress;
};
struct record records[100];
Then access the individual fields similar to:
if( 1 != scanf( "%4s", records[i].s_college ) )
{
perror( "scanf for college abbreviation failed" );
exit( EXIT_FAILURE )
}
// implied else, scanf successful
// validate the college abbreviation
for( size_t j=0; j< (sizeof(collegesAbbrevationsTable)/(sizeof( *collegeAbbreviationsTable ); i++ )
{
if( strncmp( collegeAbbreviationsTable[j], records[i].s_college, 4)
{ // then found matching abbreviation
break; // exit 'validation' loop
}
}
Note: perror() found in stdio.h. exit() and EXIT_FAILURE found in stdlib.h.
Note: In C, when referencing an array, the result is a pointer to the first byte of that array, so in the call to scanf() must not use & when referencing the array s_college[].
`
declae search2 as char search2[10]; or char * search2;
Reason : string2 is a character variable and college is a null terminating char array.
Signature of stncmp id int strcmp(const char* s1, const char*s2);
So the function to properly you need to passs char* or char array(which is again a char*).

Splitting a string with strtok() goes wrong

I'm trying to get input from the user while allocating it dynamically and then "split" it using strtok.
Main Questions:
Im getting an infinite loop of "a{\300_\377" and ",".
Why do i get a warning of "Implicitly declaring library function "malloc"/"realoc" with type void"
Other less important questions:
3.i want to break, if the input includes "-1", how do i check it? As you can see it breaks now if its 1.
4.In the getsWordsArray() i want to return a pointer to an array of strings. Since i dont know how many strings there are do i also need to dynamically allocate it like in the getInput(). (I dont know how many chars are there in each string)
int main(int argc, const char * argv[])
{
char input = getInput();
getWordsArray(&input);
}
char getInput()
{
char *data,*temp;
data=malloc(sizeof(char));
char c; /* c is the current character */
int i; /* i is the counter */
printf ("\n Enter chars and to finish push new line:\n");
for (i=0;;i++) {
c=getchar(); /* put input character into c */
if (c== '1') // need to find a way to change it to -1
break;
data[i]=c; /* put the character into the data array */
temp=realloc(data,(i+1)*sizeof(char)); /* give the pointer some memory */
if ( temp != NULL ) {
data=temp;
} else {
free(data);
printf("Error allocating memory!\n");
return 0 ;
}
}
printf("list is: %s\n",data); // for checking
return *data;
}
void getWordsArray(char *input)
{
char *token;
char *search = " ,";
token = strtok (input,search);
while (token != NULL ) {
printf("%s\n",token);
token = strtok(NULL,search);
}
}
EDIT:
i noticed i forgot to "strtok" command so i changed it to token = strtok(NULL,search);
I still get wierd output on the printf:
\327{\300_\377
Change:
int main(int argc, const char * argv[])
{
char input = getInput();
getWordsArray(&input);
}
to:
int main(int argc, const char * argv[])
{
char *input = getInput();
getWordsArray(input);
}
with a similar to the return value of getInput():
char *getInput()
{
// ...
return data;
}
In your code, you were only saving the first character of the input string, and then passing mostly garbage to getWordsArray().
For your malloc() question, man malloc starts with:
SYNOPSIS
#include <stdlib.h>
For your getchar() question, perhaps see I'm trying to understand getchar() != EOF, etc.
Joseph answered Q1.
Q2: malloc and realoc returns type void *. You need to explicitly convert that to char *. Try this:
data = (char *) malloc(sizeof(char));
Q3: 1 can be interpreted as one character. -1, while converting to characters, is equivalent to string "-1" which has character '-' and '1'. In order to check against -1, you need to use strcmp or strncmp to compare against the string "-1".
Q4: If you are going to return a different copy, yes, dynamically allocate memory is a good idea. Alternatively, you can put all pointers to each token into a data structure like a linked list for future reference. This way, you avoid making copies and just allow access to each token in the string.
Things that are wrong:
Strings in C are null-terminated. The %s argument to printf means "just keep printing characters until you hit a '\0'". Since you don't null-terminate data before printing it, printf is running off the end of data and just printing your heap (which happens to not contain any null bytes to stop it).
What headers did you #include? Missing <stdlib.h> is the most obvious reason for an implicit declaration of malloc.
getInput returns the first char of data by value. This is not what you want. (getWordsArray will never work. Also see 1.)
Suggestions:
Here's one idea for breaking on -1: if ((c == '1') && (data[i-1] == '-'))
To get an array of the strings you would indeed need a dynamic array of char *. You could either malloc a new string to copy each token that strtok returns, or just save each token directly as a pointer into input.

Resources