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*).
Related
So I'm doing a few practice questions for a final exam coming up. and I'm having a lot of trouble with dynamic memory.
So the question wants to basically parse through 2 different sources and compare them to find the similar words. (one from a csv file and one from a cgi input)
so I figured I'd use malloc/calloc to put a string in each array slot and then compare each slot. but I'm having some issues with my code:
char buffer[100],buffer2[100],tmp[100],line[100];
char *token,*tok,*input;
int main()
{
char s[100]="search=cat+or+dog+store";
char *search=(char*)calloc(10,sizeof(char));
strcpy(buffer,s);
sscanf(buffer,"search=%s",buffer);
int k=0;
tok=strtok(buffer,"+");
while(tok!=NULL)
{
strcpy(&search[k],tok);
k++;
tok=strtok(NULL,"+");
}
printf("%d\n",k);
strcpy(&search[k],"\0");
***printf("%s",&search[0]);
printf("%s",&search[1]);
printf("%s",&search[2]);
printf("%s",&search[3]);***
char* csv=(char*)calloc(10,sizeof(char));
char tmp2[100];
FILE *fp;
fp=fopen("web.csv","r");
while(fgets(line,sizeof(line),fp)!=NULL)
{
strcpy(buffer2,line);
token=strtok(buffer2,",");
while(token!=NULL)
{
strcpy(csv,token);
csv++;
token=strtok(NULL,",");
}
strcpy(csv,"\0");
free(csv);
free(search);
return(0);
}
the part i put between * * i put in order to test if the strings were put inside the calloc. but nothing prints out or smt weird prints out. the same code was used for the latter bottom part and they are both either empty or only printing out weird fragmented part of the code.
when i put the free(csv) and free(search), it says that "pointer being freed was not allocated". i looked it up but I can't seem to find a answer to why it does this?
thank you!
You seem to be trying to create an array of pointers. So let me show you what that looks like
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXT 10
int main( void )
{
char s[100]="search=cat+or+dog+store";
char buffer[100];
char **search = calloc( MAXT, sizeof(char *) );
if ( sscanf( s, "search=%s", buffer ) != 1 )
return 1;
int t = 0;
char *token = strtok( buffer, "+" );
while ( token != NULL && t < MAXT )
{
search[t++] = token;
token = strtok( NULL, "+" );
}
for ( int i = 0; i < t; i++ )
printf( "%s\n", search[i] );
free( search );
}
Things to look for
search is declared as a char ** meaning pointer to a char pointer, which can be used like an array of char pointers
in the calloc, the allocation is for 10 items of type char *, i.e. an array of 10 pointers
in the sscanf, the input and output strings must not be the same string. I changed the arguments so that s is the input, and buffer is the output. Also, you should always check that the return value from sscanf is equal to the number of items requested.
in the while loop, I've added a check t < MAXT to avoid running past the end of the pointer array
search is an array of pointers, and strtok returns a pointer, so the line search[t++]=token; stores the pointer in the array. The string itself is still in the buffer.
This line here:
strcpy(&search[k],"\0");
What you are doing is adding the string literal "\0" to the k'th position in memory (which works... but gross). I believe you are trying to do this:
search[k] = '\0'
Notice the single quotes ('') that is a character rather than a string literal.
You should also not be casting a malloc: char *search = (char *)malloc(...)
MAINLY:
You should also consider that printf("%s", string) only prints up until the nearest terminator ('\0') in 'string'. Reference here.
So check what you are buffering, and see if you can build any new conclusions...
And, when you print your string, you only need to printf("%s", search)
I highly suggest you use malloc(), especially for strings. Because calloc() initiates all values to zero. And '\0' == 0, so you could be making it more difficult for yourself to diagnose.
I wrote a function that cuts all the left space of an inputted string. These two functions give the same output "haha" when input is " haha".
My question are:
1) Why the 1st one need return but the 2nd one doesn't. I added "return s" and it made a syntax error.
2) Are there any different in these if I use it in another situation?
3) Many said that 2nd one return a character not a string, how about my output ?
char *LTrim(char s[])
{
int i=0;
while(s[i]==' ')i++;
if (i>0) strcpy(&s[0],&s[i]);
return s;
}
and
char LTrim(char s[])
{
int i=0;
while(s[i]==' ')i++;
if (i>0) strcpy(&s[0],&s[i]);
}
This is my main():
int main()
{
char s[100];
printf("input string ");
gets(s);
LTrim(s);
puts(s);
return 0;
}
Your second code segment doesn't seem to have a return statement, please correct that for getting the correct answer.
The first function is returning a character pointer, which will be memory pointing to the starting location of your character array s, whereas the second function is returning a single character.
What you do with the values returned is what will make the difference, both the codes seem to be performing the same operation on the character array(string) passed to them, so if you are only looking at the initial and final string, it will be same.
On the other hand, if you actually use the returned value for some purpose, then you will get a different result for both functions.
char *LTrim(char s[]){} is a function of character array / string which returns character pointer i.e. returns reference / memory address.
While char LTrim(char s[]) is a function of character array / string, which return character only.
char is a single character.
char * is a pointer to a char.
char * are mostly used to point to the first character of a string (like sin your example).
In the first example you return your modified svariable, and in the second you return nothing so it's best to change the return value to void instead of char.
I found this program on-line, that claims to split a string on the format "firstName/lastName". I tested, and it works:
char *splitString(char* ptrS, char c){
while( *ptrS != c ){
if( *ptrS == '\0'){
return NULL;
}
ptrS++;
}
return ptrS;
}
int main(){
char word[100];
char* firstName;
char* lastName;
printf("Please insert a word : ");
fgets(word, sizeof(word), stdin);
word[strlen(word)-1] = '\0';
firstName = word;
lastName = splitString(word, '/');
if(lastName == NULL ){
printf("Error: / not found in string\n");
exit(-1);
}
*lastName = '\0';
lastName++;
printf("First name %s, Last name %s\n",firstName, lastName);
return(0);
}
What I'm seeing here however, is only one char array being created, and the firstName and lastName pointers being placed properly.Maybe it is because I'm a little confused about the relation between pointers and arrays but I have a few questions about this program:
How many strings -as char arrays- are produced after the program is executed?
Are the char pointers used in this program the same as strings?
Why I can use those char pointers used as strings in printf? I can use char pointers as strings on every C program?
As a corollary, what's the relationship between pointers and arrays? Can they be used interchangeably?
How many strings -as char arrays- are produced after the program is executed?
You have one char[], of size 100. However, at the end of the program's execution, you actually have two strings stored in it.
A string is a set of chars stored contiguously in memory terminated with '\0' (null/0).
In this program we take the input, and search for the '/' character. When found, it is replaced with the string terminator:
"John/Smith\0"
"John\0Smith\0"
The pointer to the beginning of the array will allow us to access the first string ("John"), and the pointer that previously pointed to the '/' character is incremented, so that it now points to "Smith"
initialisation:
"John/Smith\0"
^
|
word/firstname
after lastName = splitString(word, '/');:
"John/Smith\0"
^ ^
| lastname
word/firstname
after *lastName = '\0'; lastName++;:
"John\0Smith\0"
^ ^
| lastname
word/firstname
So there is still only one array (word) but you have two pointers (firstname &lastname) to the strings within.
Are the char pointers used in this program the same as strings?
The char* pointers are not strings, but they point to them. You can pass the pointers to any function that is expecting a string (I expand a bit below)
Why I can use those char pointers used as strings in printf? I can use char pointers as strings on every C program?
In C (and C++) functions cannot pass arrays of data. A function like this:
int func(char string[]){}
will not actually be passed the array itself, but instead, it will be passed a pointer to the beginning of the array.
It is often the case that the [] notation is used where the function will be operating on an array (in function headers char* str and char str[] are equivalent) as it removes any ambiguity that the pointer isn't there to reference a single char (or int etc).
Printf() takes pointers to the string, and knowing that it is a string (thanks to the %s identifier in the format string) it will print out each char from the memory location that the pointer identifies until it hits the '\0' character.
A valid string always has this terminator, and so when working with strings, this is safe.
You will often see functions that take an array, and an additional parameter to denote the size of the array:
int do_something_with_array(int array[], size_t array_length){}
This is because without a terminating value or knowing the size of the array, there is no way to know that you have left the array and started processing out of bounds which isn't allowed and can cause memory corruption or cause the runtime to kill your program (crash).
It is a common misconception that pointers and arrays are the same.
In most cases you handle arrays via pointers, so that handling the data is the same whether you have an array or a pointer to one. There are some things to keep in mind however; this as an example.
How many strings -as char arrays- are produced after the program is executed?
There are 1 char array in this program, namely word[100], others like firstName and last Name are just char pointers..
Are the char pointers used in this program the same as strings?
Char pointers are very different to Strings, Char pointers are something you can use to point at a char or a string. In this program firstName and lastName are only char pointers that are used to point at different places of the character array word[] to split the array
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.
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.