Issue printing strings from struct in c - arrays

I am trying to write a program that takes first names and last names from stdin separated by newline and stores them in char arrays inside of a struct array. Everything seems to be working fine until I want to print them in a certain way. I need the names to be formatted like this on the output:
<lastName>, <firstName> That is why I added a function to remove the trailing newline from the end of each line when parsing the values. It however does not return anything when doing this:
printf("%s, %s",people[0].lastName, people[0].firstName);
However when printing the values on seperate lines like
printf("%s\n",people[0].lastName);
printf("%s\n",people[0].firstName);
or using puts
puts(people[0].lastName);
it works just fine.
When I comment out the removeNewline() function it seems to get rid of the problem. But with the newline at the end I cannot format the output the way I desribed.
Here is my full code:
#include <stdio.h>
#include <string.h>
#define MAX_STRING_LENGTH 100
#define MAX_PEOPLE 42
struct Person{
char firstName [MAX_STRING_LENGTH];
char lastName[MAX_STRING_LENGTH];
};
void removeNewline(char * string){
for(int i = 0; string[i] != '\0'; i++){
if(string[i] == '\n'){
string[i] = '\0';
}
}
}
int parseData(struct Person * people){
int peopleCounter;
for(peopleCounter = 0; peopleCounter < MAX_PEOPLE; peopleCounter++){
char firstName[MAX_STRING_LENGTH];
char lastName[MAX_STRING_LENGTH];
if(fgets(firstName,MAX_STRING_LENGTH,stdin) == NULL){
break;
}
fgets(lastName,MAX_STRING_LENGTH,stdin);
removeNewline(firstName);
removeNewline(lastName);
strcpy(people[peopleCounter].firstName,firstName);
strcpy(people[peopleCounter].lastName,lastName);
}
return peopleCounter;
}
int main(int argc, char *argv[]){
struct Person people [MAX_PEOPLE];
parseData(people);
//PROBLEM
printf("%s, %s",people[0].firstName, people[0].lastName);
for(int i = 0; i < 2; i++){
printperson(people, i);
}
}
I am giving the values from a text file through redirection like so:
./main <people.txt
people.txt example:
George
Washington
Thomas
Jefferson
desired output:
Washington, George
Jefferson, Thomas

I am not able to reproduce the issue. Here are the minor changes:
removeNewline(): return after we process the first newline. Streamlined it a bit.
parseData(): store directly in struct instead of temporary variables. Renamed peopleCounter to i as it was it unnecessary long. Check return value of 2nd fgets(), too.
main(): Removed call to printperson() and looped over the returned values with the two arguments variables switched in the printf() statement for the expected order.
#include <stdio.h>
#include <string.h>
#define MAX_STRING_LENGTH 100
#define MAX_PEOPLE 42
struct Person{
char firstName[MAX_STRING_LENGTH];
char lastName[MAX_STRING_LENGTH];
};
void removeNewline(char *s) {
for(;;) {
*s *= (*s != '\n');
if(!*s++) return;
}
}
int parseData(struct Person *people){
int i = 0;
for(; i < MAX_PEOPLE; i++){
if(!fgets((people + i)->firstName,MAX_STRING_LENGTH,stdin))
break;
removeNewline((people + i)->firstName);
if(!fgets((people + i)->lastName,MAX_STRING_LENGTH,stdin))
break;
removeNewline((people + i)->lastName);
}
return i;
}
int main(int argc, char *argv[]) {
struct Person people[MAX_PEOPLE];
int n = parseData(people);
for(int i = 0; i < n; i++) {
printf("%s, %s\n", people[i].lastName, people[i].firstName);
}
}
and the output is:
Washington, George
Jefferson, Thomas

Related

I am doing an assignment that asks me to make a function that creates an acronym from a string, then return the acronym

The prompt that I'm given is: An acronym is a word formed from the initial letters of words in a set phrase. Write a program whose input is a phrase and whose output is an acronym of the input. If a word begins with a lower case letter, don't include that letter in the acronym. Assume there will be at least one upper case letter in the input.
Also, I am given the following function to use: void CreateAcronym(char userPhrase[], char userAcronym[]).
My problem with the code is that only the first letter is being saved to the userAcronym variable.
For example, when the string is Institute of Electrical and Electronics Engineers. The output I'm getting is just I. What do I need to change to get the remaining letters?
Thank you for the help.
My code so far is:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define MAX 60
void CreateAcronym(char userPhrase[], char userAcronym[]){
int i;
int j=0;
for(i = 0; i < strlen(userPhrase); ++i){
if(isupper(userPhrase[i])){
userAcronym[j]=userPhrase[i];
}
j++;
}
printf("%s", userAcronym);
}
int main(void) {
char phrase[MAX];
char acronym[10];
fgets(phrase, MAX, stdin);
CreateAcronym(phrase, acronym);
return 0;
}
For starters the function CreateAcronym should be declared at least like
void CreateAcronym( const char userPhrase[], char userAcronym[]);
because the passed string that contains a phrase is not being changed within the function.
But it will be even better to declare the function like
char * CreateAcronym( const char userPhrase[], char userAcronym[]);
The function should not output anything. It is the caller of the function that decides whether to output the acronym formed within the function.
The function invokes undefined behavior because the array acronym does not get a string.
Moreover there is another bug in the for loop
for(i = 0; i < strlen(userPhrase); ++i){
if(isupper(userPhrase[i])){
userAcronym[j]=userPhrase[i];
}
j++;
}
where the variable j is incremented in each iteration of the loop.
And calling the function strlen in the condition of the loop is inefficient.
Also the function does not copy only initial upper case letters of words to the destination array. It tries to copy any upper case letter. So the for loop in any case does not make a sense.
The function can be defined the following way as it is shown in the demonstrative program below.
#include <stdio.h>
#include <ctype.h>
char * CreateAcronym( const char userPhrase[], char userAcronym[] )
{
char *p = userAcronym;
while ( *userPhrase )
{
while ( isspace( ( unsigned char )*userPhrase ) ) ++userPhrase;
if ( isupper( ( unsigned char )*userPhrase ) ) *p++ = *userPhrase;
while ( *userPhrase && !isspace( ( unsigned char )*userPhrase ) ) ++userPhrase;
}
*p = '\0';
return userAcronym;
}
int main(void)
{
const char *phrase = "Institute of Electrical and Electronics Engineers";
char acronym[10];
puts( CreateAcronym( phrase, acronym ) );
return 0;
}
The program output is
IEEE
Try it. First, you used j++ not in "if". And second, you didnt put '\0' in your userAcronym string. '\0' means that your string end here and all string will be printed before this symbol.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define MAX 60
void CreateAcronym(char userPhrase[], char userAcronym[]){
int i;
int j = 0;
for(i = 0; i < strlen(userPhrase); i++){
if(isupper(userPhrase[i])){
userAcronym[j] = userPhrase[i];
j++;
}
}
userAcronym[j] = '\0';
printf("%s", userAcronym);
}
int main(){
char phrase[MAX];
char acronym[10];
fgets(phrase, MAX, stdin);
CreateAcronym(phrase, acronym);
return 0;
}

How to print a variable length string of a single character

I have a need to print a variable number of a given character in conjunction with my formatted output. I was looking for something similar or equivalent to the VBA function String(num, char), but haven't been able to find any. I've written a function to do the job but if there is something built-in that does it I'd love to know. Here's what I have. For the purpose of testing I'm using a sloppy implementation of argv[].
What I want to is print out something like this;
Here's the rough implementation I've come up with;
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const char * make_string(int num, char character)
{
char *strchars = malloc(num);
for (int i = 0; i < num; i++)
strchars[i] = character;
return strchars;
}
int main(int argc, char *argv[])
{
for (int i = 1; i < argc; i++) {
printf("%s\n", make_string(strlen(argv[i]),'_'));
printf("%s%c %s\n", make_string(strlen(argv[i]),'_'),'|', argv[i]);
}
}
Is there a library function for printing strings of repeating characters like this?
Credit for this answer goes to UmamaheshP for pointing me in the right direction with a comment. This is what I was looking for and was adapted from an example he linked to.
#include <stdio.h>
#include <string.h>
int main (int argc, char *argv[]) {
int i;
char *pad = "________________";
for (i = 1; i < argc; i++)
printf ("%.*s\n%.*s%c %s\n", strlen(argv[i]),
pad,strlen(argv[i]), pad, '|', argv[i]);
}

Searching for string in char array of strings in C

char names [MAX_CLASS_SIZE][MAX_NAME_SIZE+1]={"Julias Hoffman","Dianne Conner","Mitchell Cooper","Johnnie Greene","Johanna Mason","Kevin Adkins","Brandi Spencer","Marian Tyler","Chester Cross","Martin Lawrence","Jane Smith","Sara Jones"};
char specificName[]="";
int search(char names[][MAX_NAME_SIZE+1],char specificName[])
for(i=0;i<MAX_CLASS_SIZE;i++){
if (strcmp(names[i],specificName)==0)
{
printf("Found %s",names[i]);
return i;
}
}
This function receives an array of strings, called name and an array of characters that represents a specific name. This function searches through the array name for the specific name and returns the index of the specific name if it is found, -1 if it is not found.
In main() I ask the user for a name and store it in the specificName char array using scanf("%s",specificName);. Then in the search() function I am attempting to search the array of names for the user given name and return a certain value based on if the name is found. I have included the necessary libraries. I am trying to do this using strcmp, but search() doesn't find the matching name.
You could try the following approach:
#include <stdio.h>
#include <stdlib.h>
#include<string.h>
int search(char **names,char *specificName, size_t length){
size_t i,found=0;
for(i=0;i<length;i++){
if (strcmp(*(names + i),specificName)==0){
found = 1;
}
}
return found == 1 ? 0 : 1;
}
int main(void) {
size_t length;
char specificName[100];
char *names[12]={"Julias Hoffman","Dianne Conner","Mitchell Cooper","Johnnie Greene",
"Johanna Mason","Kevin Adkins","Brandi Spencer","Marian Tyler",
"Chester Cross","Martin Lawrence","Jane Smith","Sara Jones"};
length = sizeof names / sizeof *(names + 0);
printf("Type a name to be searched:> ");
if( fgets (specificName, 100, stdin) == NULL){
printf("Error!\n");
}
specificName[strcspn(specificName, "\n")] = 0;
if((search(names,specificName,length)) == 0){
printf("Found %s",specificName);
}else{
printf("There was no Record Found.\n");
}
return 0;
}
Output:
Type a name to be searched:> Sara Jones
Found Sara Jones
Took a quick look and it seems to work fine. Your i needs to be declared as an int but otherwise, the following works:
#include <stdio.h>
#include <stdlib.h>
#define MAX_CLASS_SIZE 100
#define MAX_NAME_SIZE 100
int strcmp(const char *, const char *);
int main(int argc, const char * argv[]) {
char names [MAX_CLASS_SIZE][MAX_NAME_SIZE+1]={"Julias Hoffman","Dianne Conner","Mitchell Cooper","Johnnie Greene","Johanna Mason","Kevin Adkins","Brandi Spencer","Marian Tyler","Chester Cross","Martin Lawrence","Jane Smith","Sara Jones"};
char specificName[]="Brandi Spencer";
int search(char names[][MAX_NAME_SIZE+1],char specificName[]);
for(int i=0;i<MAX_CLASS_SIZE;i++){
if (strcmp(names[i],specificName)==0){
printf("Found %s",names[i]);
return i;
}
}
return 0;
}
Output
Found Brandi Spencer
My guess would be is that you are not passing the user input correctly. Check specificName[] prior to strcmp().

returning 2d array in C…

I'm a total noob in C. I can't make the connect between this function and main. I'm trying to print out a 2d array and I keep getting segmentation fault. Any help would be greatly appreciated.
EDIT: When I changed the last line 'printf("%d:[%s]\n",i,*(p+i))' from %s to %c, I get the first word in the file i'm reading from. So turns out that something is in fact being returned from my function. Now just need to figure out how to get it to return words from other lines in the file.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define num_strings 20
#define size_strings 20
int *read_file(){
int j = 0;
static char text[num_strings][size_strings];
FILE *fp;
int x;
fp = fopen("dictionary2.txt", "r");
char s[100];
while(!feof(fp)) {
x = fscanf(fp,"%[^\n]",s);
fgetc(fp);
if (x==1) {
strcpy(text[j],s);
j++;
}
}
return text;
}
int main() {
int *p;
p = read_file();
int i;
for(i = 0; i < 10; i++) {
printf("%d:[%s]\n",i,*(p+i));
}
return(0);
}
In general, you should be creating your array in main() and passing it in, this kind of behavior is very unorthodox. However, if you do insist on doing it this way, you have to return a pointer to your array, since you cannot return arrays in C.
This is the kind of thing you'll need:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define num_strings 20
#define size_strings 20
typedef char (*PARR)[num_strings][size_strings];
PARR read_file(int * wordsread)
{
static char text[num_strings][size_strings];
FILE *fp;
if ( (fp = fopen("dictionary2.txt", "r")) == NULL ) {
fprintf(stderr, "Couldn't open file for reading\n");
exit(EXIT_FAILURE);
}
char s[100];
int j = 0;
while ( j < num_strings && fgets(s, sizeof s, fp) ) {
const size_t sl = strlen(s);
if ( s[sl - 1] == '\n' ) {
s[sl - 1] = 0;
}
if ( (strlen(s) + 1) > size_strings ) {
fprintf(stderr, "String [%s] too long!\n", s);
exit(EXIT_FAILURE);
}
strcpy(text[j++], s);
}
fclose(fp);
*wordsread = j;
return &text;
}
int main(void)
{
int wordsread = 0;
PARR p = read_file(&wordsread);
for ( int i = 0; i < wordsread; ++i ) {
printf("%d:[%s]\n", i, (*p)[i]);
}
return 0;
}
which, with a suitable input file, outputs:
paul#horus:~/src/sandbox$ ./twoarr
0:[these]
1:[are]
2:[some]
3:[words]
4:[and]
5:[here]
6:[are]
7:[some]
8:[more]
9:[the]
10:[total]
11:[number]
12:[of]
13:[words]
14:[in]
15:[this]
16:[file]
17:[is]
18:[twenty]
19:[s'right]
paul#horus:~/src/sandbox$
Note this only works because you declared your array in read_file() as static - don't return pointers to local variables with automatic storage duration in this way.
Try moving your #defines back and changing your function header to return a pointer to arrays of size_strings characters, as follows:
#define num_strings 20
#define size_strings 20
char (*read_file())[size_strings] {
Or alternately, with a typedef:
#define num_strings 20
#define size_strings 20
typedef char (*PCharArr)[size_strings];
PCharArr read_file() {
...and change the type of p in main accordingly:
char (*p)[size_strings];
That will return (a pointer to the first element of) an array of character arrays, which is more or less equivalent to a 2D array of char.
Update, oh I see, you pasted the code from main to the function, I know what happened here, you assumed p[20][20] is the same as a p* or maybe a p**, that's not correct, since now if you do *(p+1), the compiler doesn't know each element in p is 20 wide instead of 1 wide. You approach here should be to declare a pointer to an array of strings in read_file and return that instead:
static char text[num_strings][size_strings];
static char *texts[num_strings]
...
while....
....
if (x==1)
{strcpy(text[j],s);texts[j]=text[j];j++;}
return texts;
your p should be char* not int*. You also need to terminate the loop if 20 items have been read in.

Whats wrong with this basic shell program? it will run fine for the first few commands but results always ends in a seg fault

I have to build a simple shell program using lex and c code. The lex portion is for breaking down the input. It has been provided for me and I'm not expected to change it. I'm in the process of getting my code to run basic commands like "ls". It seems to work the first few times I run the command but eventually always seg faults. Here is the lex code provided:
%{
int _numargs = 10;
char *_args[10];
int _argcount = 0;
%}
WORD [a-zA-Z0-9\/\.-]+
SPECIAL [()><|&;*]
%%
_argcount=0;
_args[0]=NULL;
{WORD}|{SPECIAL} {
if(_argcount < _numargs-1) {
_args[_argcount++]= (char *)strdup(yytext);
_args[_argcount]= NULL;
}
}
\n return (int)_args;
[ \t]+
.
%%
char **getln() {
return (char **)yylex();
}
This is the C code:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
extern char **getln();
int main() {
int i;
char **args;
int child1;
int status1;
int counter=0;
int argCount = 1;
char **array = (char **)malloc(1500 * sizeof(char *));
for (i = 0; i < 1500; ++i) {
array[i] = (char *)malloc(500);
}
strcpy(array[0],"ls\0");
array[1] = NULL;
while(1) {
args = getln();
printf("is error here?");
strcpy(array[0], args[counter]);
for(i = (counter+1); args[i] != NULL; i++) {
printf("\nRight before copying to subarray");
strcpy(array[argCount], args[i]);
argCount++;
}
array[argCount] = NULL;
if (strcmp(args[counter],"exit")==0) exit(0);
child1 = fork();
if(child1==0){
execvp(array[0], array);
printf("Unknown command, please try again.");
exit(1);
}
else{
while (wait(&status1) != child1);
}
for(i = 0; args[i] != NULL; i++) {
printf("Argument %d: %s\n argCount: %d", i, args[i], argCount);
}
argCount = 1;
counter++;
}
}
Thanks in advance for any advice. If there is some simple way to adjust the getln() function to overwrite the args array each time it is called that might be easier than what I am attempting but I have no idea how to go about that.
It seems like you have put
_argcount=0;
_args[0]=NULL;
at the top of the rules section in hopes that these statements would be executed at the beginning of yylex(). And you've noticed that they aren't executed (it keeps appending to the previous values because _argcount never goes back to 0).
The obvious thing to do is move those statements into getln() just before the yylex().
What you have now is a lexer that will ignore the string _argcount=0; in the input because it will match that pattern and there's no action to go with it. The second line is even cooler since the [0] is a character class. It makes the lexer ignore the string _args0=NULL;

Resources