concatenating strings in C without the use of library functions - c

I need to write a simple program (no fancy pointer stuff, no library functions. It's for educational purposes) that reads the first and second names from a user and prints them out in a single line separated by a space. I am not getting the result and I am not sure why:
# include <stdio.h>
//the program loosely simulates the behaviour of strcpy
main(){
char fname[16], sname[16], cat[31];
int i, j;
printf("Please enter your first name: ");
scanf("%s", fname);
printf("Please enter your second name: ");
scanf("%s", sname);
for (i=0; fname[i] != '\0'; cat[i++] = fname[i++])
;
cat[i+1] = ' '; //adds a space between the tokens
for (j=i+1; sname[j] != '\0'; cat[j++] = sname[j++])
;
printf("The final result is:\n%s", cat);
return 0;
}

You have several problems. First, since cat has to be big enough to hold the first two strings and a space between them, it should be declared cat[32] -- 15 characters of first name, 15 characters of surname, 1 space, and 1 trailing null byte.
You're putting the space between the words in the wrong place. The first loop left i holding the next position in cat, so it should be:
cat[i] = ' ';
Next, your array indexes in the second loop are incorrect. The positions in cat are correct, because they start from where you left off the previous loop. But you need to start from 0 in sname. So this loop should be:
for (j = i+1, k = 0; sname[k] != 0; cat[j++] = sname[k++])
;
Finally, after concatenating the two strings, you need to append a null byte to the result, to indicate the end.
cat[j] = 0;
Another problem is that you're incrementing i twice each time through the first loop, since you use cat[i++] = fname[i++]. Each of those i++ will increment the variable. You need to separate the assignment from the increments:
for (i=0; fname[i] != '\0'; i++) {
cat[i] = fname[i];
}
Here's a final version of the script that works:
# include <stdio.h>
//the program loosely simulates the behaviour of strcpy
int main() {
char fname[16], sname[16], cat[32];
int i, j, k;
printf("Please enter your first name: ");
scanf("%s", fname);
printf("Please enter your second name: ");
scanf("%s", sname);
for (i=0; fname[i] != '\0'; i++) {
cat[i] = fname[i];
}
cat[i] = ' ';
for (j = i+1, k = 0; sname[k] != 0; cat[j++] = sname[k++]) {
}
cat[j] = 0;
printf("The final result is: %s\n", cat);
return 0;
}

I realize you set yourself a challenge to try to learn how to do something specific (and I see you are making progress towards your goal). But I always like to keep in mind there are lots of ways to get the job done -- especially in C. You know you could just do this with printf, right?
char fname[16], sname[16];
int i, j;
printf("Please enter your first name: ");
scanf("%s", fname);
printf("Please enter your second name: ");
scanf("%s", sname);
printf("%s %s\n", fname, sname);

Watch the index you use :
cat[i++] = fname[i++] and cat[j++] = sname[j++]
try to increment 'i' and 'j' at the end of your loop :
for (i=0; fname[i] != '\0'; ++i)
cat[i] = fname[i];
// ...
for (j=0; sname[j] != '\0';++j)
cat[j+i+1] = sname[j];

Related

Fixing output to make it read properly instead of running a segmentation fail

Write a C program to split an input string (variable “name”) into two output strings (variables “first”
and “last”). Assume that the user provides input containing only the characters ‘a’ through ‘z’ and ‘A’
through ‘Z’. Assume there are exactly two capital letters in the input, one at the beginning of the first
name, and one at the beginning of the last name. For example, given the input “JoeSmith”, your code
should split it into “Joe” and “Smith”. If the given input contains only the first name example “Joe”
then it should print ‘only the first name is provided’ and print that first name.
int main() {
char name[20], first[20], last[20];
printf("Enter FirstLast name or enter First: ");
scanf("%s", name);
int i, j, index;
for (i = 0; i <= 20; i++) {
if (i == 0) {
first[i] = name[i];
} else {
if (name[i] >= 'A' && name[i] <= 'Z') {
index = i;
break;
}
first[i] = name[i];
}
}
for (j = index, i = 0; i <= 20 - index; j++, i++) {
last[i] = name[j];
}
first[i + 1] = '\0';
last[j + 1] = '\0';
if (first[i]) printf("Only first name printed%s\n", first);
printf("first name:%s\nlast name:%s", first, last);
return 0;
}
how would I get the code to print out "only first name printed" and print the first name beneath it? having trouble figuring this out. Also keeping the FirstLast name aswell.
When I input BobJoe
it prints
First name:Bob
Last name:Joe
Which is one of the two things I need^^
When I input
Bob
it prints
zsh: segmentation fault ./run
Trying out your code with regard to the comments made above, I offer up a revised version of your code utilizing the "string.h" include file to provide a bit better control.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char name[20], first[20], last[20];
int i = 0, j = 0, caps = 0, index;
printf("Enter FirstLast name or enter First: ");
scanf("%s", name);
for (index = 0; index < 20; index++) /* Initialize the first and last name arrays to avoid unknown character data */
{
first[index] = '\0';
last[index] = '\0';
}
for (index = 0; index < strlen(name); index++)
{
if (name[index] >= 'A' && name[index] <= 'Z')
{
caps++;
}
if (caps <= 1)
{
first[i] = name[index];
i++;
}
else
{
last[j] = name[index];
j++;
}
}
if (last[0] == '\0')
printf("Only first name printed: %s\n", first);
else
printf("first name: %s\nlast name: %s\n", first, last);
return 0;
}
To ensure that the resulting first and last name arrays do not have uninitialized data, these are initialized prior to usage. Then, in the program the "strlen" function is utilized to ensure that testing and copying does not run past the end of your input character array.
The result in testing these changes are as follows in the terminal output.
#Una:~/C_Programs/Console/FirstLast/bin/Release$ ./FirstLast
Enter FirstLast name or enter First: JoeSmith
first name: Joe
last name: Smith
#Una:~/C_Programs/Console/FirstLast/bin/Release$ ./FirstLast
Enter FirstLast name or enter First: Joe
Only first name printed: Joe
#Una:~/C_Programs/Console/FirstLast/bin/Release$ ./FirstLast
Enter FirstLast name or enter First: joeSmith
Only first name printed: joeSmith
Give that a try to see if this meets the spirit of your project.

CS50 initials.c spacing bug?

The code is suppose to print the initials of the users but the code has a bug instead it prints out the whole name with spaces between each letter. I know the bug lies in the for loop but im not sure how to debug this issue. Suggestions?
int main(void)
{
printf("Enter full name: ");
string name = get_string();
{
printf("%c", toupper(name[0]));
}
for(int i = 0, n = strlen(name); i < n; i++)
{
printf(" ");
printf("%c", toupper(name[i + 1]));
}
}
I think that you mean to test to see if the next char is a space, and if it is, then print the char following the space:
if (name[i] == ' ')
{
printf("%c", toupper(name[i + 1]));
}
Of course, before the for loop, you need to print the first initial since there won't be a space before it:
// print the first initial before the loop
cout << static_cast<unsigned char>(toupper(name[0]));
You are correctly printing the characters, but you have printf(" "); so no wonder why there are spaces here.

convert 2d array to pointer?

I'm trying to teach myself C, so I wrote a program to keep records for a gradebook! In my effort to learn pointers, I'm trying to convert one of my beginning projects of arrays to pointers. I want to convert my 2d array to pointers. Below is my original program to with the 2d array, and below that is my attempt to convert it to 2d pointer array.
ORIGINAL PROGRAM
int numberPeople, choice, i, j;
char people[15][3][100];
printf("Please indicate number of records you want to enter (min %d, max %d): ", 5, 15);
scanf("%d", &numberPeople);
while ((numberPeople < 5) || (numberPeople > 15)) {
printf("\nNumber not in specified range, try again.\n");
printf("Please indicate number of records you want to enter (min %d, max %d): ", 5, 15);
scanf("%d", &numberPeople);
}
printf("\n");
while ((getchar()) != '\n'); // flush the return (and anything else) after the number input above
printf("Enter the first name, last name, and grade (put a space in between each): \n");
for (i = 0; i < numberPeople; i++) {
char tempArr[MAXIMUM_LINE_LENGTH];
fgets(tempArr, MAXIMUM_LINE_LENGTH, stdin);
char *token = strtok(tempArr, " ");
for (j = 0; j < DATA_FIELDS && token != NULL; j++) {
strncpy(people[i][j], token, MAXIMUM_DATA_LENGTH);
token = strtok(NULL, " \r\n");
}
}
ATTEMPT AT 2D ARRAY -> POINTER
int numberPeople, choice, i, j;
char* people;
printf("Please indicate number of records you want to enter (min %d, max %d): ", 5, 15);
scanf("%d", &numberPeople);
people = (char*)(malloc(numberPeople*DATA_FIELDS*sizeof(char)));
while ((numberPeople < 5) || (numberPeople > 15)) {
printf("\nNumber not in specified range, try again.\n");
printf("Please indicate number of records you want to enter (min %d, max %d): ", 5, 15);
scanf("%d", &numberPeople);
}
printf("\n");
while ((getchar()) != '\n'); // flush the return (and anything else) after the number input above
printf("Enter the first name, last name, and grade (put a space in between each): \n");
for (i = 0; i < numberPeople; i++) {
char* tempArr;
fgets(tempArr, 100, stdin); // Thread 1: EXC_BAD_ACCESS code=1 address=0x0
char *token = strtok(tempArr, " ");
for (j = 0; j < 3 && token != NULL; j++) {
strncpy(people, token, 50);
token = strtok(NULL, " \r\n");
}
}
During the person input step is when it breaks. It works for the first entry, but then it hits a breakpoint (I'm using Xcode), and it reads "EXC_BAD_ACCESS", and I'm not too sure what this means, any tips would help, thanks!
Yes, you can convert to all pointers but I wouldn't recommend it. Here's an example:
char ***people = malloc(sizeof(*people) * 15);
for (int i = 0; i < 15; i++) {
people[i] = malloc(sizeof(*people[i]) * 3);
for (int j = 0; j < 3; j++) {
people[i][j] = malloc(sizeof(*people[i][j]) * 100);
}
}
This would re-create the array char people[15][3][100];. As you can see, it's messy. Plus, you have to free all that mem when you are done.
I cleaner way would be to use a struct:
struct Student {
char firstName[100];
char lastName[100];
char grade[100];
};
struct Student people[15];
This will set aside as much memory as the array. You could also dynamically allocate as many students as needed:
struct Student *people = malloc(sizeof(*people) * 20);
That will get 20 students. You can access them using array notation:
printf("%s %s %s", people[0].firstName, people[0].lastName, people[0].grade);
And you only need to call free once.
this pair of lines is not correct:
char* tempArr;
fgets(tempArr, 100, stdin);
the declaration of the pointer: tempArr is not allocating any actual memory to contain the line read by the the call to fgets() Suggest:
#define MAX_INPUT_LEN (100)
...
char tempArr[MAX_INPUT_LEN];
fgets( tempArr, MAX_INPUT_LEN, stdin );
Also, the returned value from the call to fgets() should be checked (!=NULL) to assure the operation was successful.

scanf and strtok not working properly for me

I'm trying to write a small menu based program to maintain records.
The user inputs a number to be used for the total amount of people to be stored (first name, last name, score). User enters info all on one line, separated by spaces, and I split them up into 3 columns (first name, last name, score), then presses enter and continues to enter more info until the max people is hit.
My problem being, when I run it, it doesn't work properly; it runs and accepts user input, but only for two students (even though I've been using numbers greater than 5 for test cases), then the program immediately ends (no error codes, just ends...) and it doesn't even make it to the menu. Can someone tell me what is wrong with my code?
int i, j, count, numberPeople, temp, choice;
char people[15][3], tempArr[20];
char *token;
printf("Please indicate number of records you want to enter (min 5, max 15): ");
scanf("%d", &temp);
while ((temp > 15) || (temp < 5)) {
printf("\nNumber not in specified range, try again.\n");
printf("Please indicate number of records you want to enter (min 5, max 15): ");
scanf("%d", &temp);
}
numberPeople = temp;
printf("\nEnter the first name, last name, and grade (put a space in between each): ");
for (i = 0; i < numberPeople; i++) {
fgets(tempArr, 20, stdin);
token = strtok(tempArr, " ");
for (j = 0; j < 3; j++) {
while (token != NULL) {
people[i][j] = *token;
printf("%s\n", token); // this is here to as a test case to see if my data was being stored.
token = strtok(NULL, " ");
}
}
}
EDITED: changed scanf to fgets
OUTPUT
Please indicate number of records you want to enter (min 5, max 15): 5
Enter the first name, last name, and grade (put a space in between each): firstname1 lastname1 85
firstname1
lastname1
85
firstname2 lastname2 84
firstname2
lastname2
Program ended with exit code: 0
One problem is you're using scanf() to read in the entire input line which has spaces between the first name, last name and grade:
for (i = 0; i < numberPeople; i++) {
scanf("%s", tempArr);
}
scanf("%s", tempArr) quits reading as soon as it hits the first space. For this loop you want to use fgets():
for (i = 0; i < numberPeople; i++) {
fgets(tempArr, 20, stdin);
}
But as #Pooya notes, this string size is too small for what you're doing. Although you allocate the two dimensional array of students and information fields, you never allocate the string space to hold their names and grades:
char people[15][3]
If you're doing this on the stack, it becomes conceptually a third dimension:
char people[15][3][24]
After this scanf(), there's still a return character left in the buffer:
scanf("%d", &temp);
it probably should be cleared out. #KevinDTimm and #bruceg hint at a problem here:
for (j = 0; j < 3; j++) {
while (token != NULL) {
people[i][j] = *token;
But I don't think Kevin's suggestion accounts for the index j. #Weather_Vane suggests adding \r\n to the strtok() separator string:
token = strtok(NULL, " ")
Otherwise your grade string (last field) will have a dangling newline. Also, you need to make a copy of the token returned by strtok(), you shouldn't store it directly.
Putting all these suggestions together and cleaning/fixing anything else I ran into, I offer the following rework:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MINIMUM_STUDENTS 5
#define MAXIMUM_STUDENTS 15
#define DATA_FIELDS 3
#define MAXIMUM_LINE_LENGTH 100
#define MAXIMUM_DATA_LENGTH 50
int main(int argc, char **argv) {
int numberPeople;
char people[MAXIMUM_STUDENTS][DATA_FIELDS][MAXIMUM_DATA_LENGTH];
printf("Please indicate number of records you want to enter (min %d, max %d): ", MINIMUM_STUDENTS, MAXIMUM_STUDENTS);
scanf("%d", &numberPeople);
while ((numberPeople < MINIMUM_STUDENTS) || (numberPeople > MAXIMUM_STUDENTS)) {
printf("\nNumber not in specified range, try again.\n");
printf("Please indicate number of records you want to enter (min %d, max %d): ", MINIMUM_STUDENTS, MAXIMUM_STUDENTS);
scanf("%d", &numberPeople);
}
printf("\n");
while ((getchar()) != '\n'); // flush the return (and anything else) after the number input above
printf("Enter the first name, last name, and grade (put a space in between each): \n");
for (int i = 0; i < numberPeople; i++) {
char tempArr[MAXIMUM_LINE_LENGTH];
fgets(tempArr, MAXIMUM_LINE_LENGTH, stdin);
char *token = strtok(tempArr, " ");
for (int j = 0; j < DATA_FIELDS && token != NULL; j++) {
strncpy(people[i][j], token, MAXIMUM_DATA_LENGTH);
// this is here to as a test case to see if my data was being stored.
printf("%s\n", people[i][j]);
token = strtok(NULL, " \r\n");
}
}
// do what you need to do with the data here!
return 0;
}
First off, use fgets() not scanf()
Next, you don't need the for (j=0; j<3; j++) part, that's handled by strtok. Instead use the following:
token = strtok(tempArr, " ");
while (token != NULL) {
people[i][j] = *token;
printf("%s\n", token); // this is here to as a test case to see if my data was being stored.
token = strtok(NULL, " ");
}
According to your sample, your input takes about 24 character but you defined tempArr[20]. because you overwrite something else in memory if you scan something more than 20 characters, it is better to have tempArr[100] or any number that makes sense for your tests.

How can I replace getchar();?

#include <stdio.h>
int main (void)
{
int n;
printf("Give the number of words you want to input.");
scanf("%d",&n);
int letters[n],i,j,count,key,k;
char str[100];
//Scans each word, counts it's letters and stores it in the next available
//position in "letters" array.
for (i=0;i<n;i++)
{
j=0;
printf("Give the next word.");
do{
str[j] = getchar();
j++;
}while (str[j-1]!='\n');
str[j-1] = '\0';
letters[i] = j;
}
//Compacts the data by figuring out which cells have the same number of letters
for (i=0;i<n;i++)
{
key = letters[i];
count = 0;
for (j=i+1;j<=n;j++)
{
if (key==letters[j])
{
count += 1;
letters[j] = 0;
}
}
letters[i] = count;
}
//creates a histogram
i=0;
do{
printf("%d|",i);
for (j=1;j<=letters[i];j++)
{
printf("*");
}
printf("\n");
i++;
}while ((i<=n));
return 0;
}
I understand that getchar(); reads, the first enter (\n) , user hits, to give the amount of words he wants to input, and thus expects one less word.
Also, I get an infite loop for some reason at the end. Any help and ideas would be appreciated. Thanks in advance.
Change the first block of your code to look like this:
(test the output of getchar, and continues only if not EOF)
for (i=0;i<n;i++)
{
j=0;
printf("Give the next word.");
do{
a = getchar();
if(a >= 0)
{
str[j] = a;
j++;
}
else break;
}while (str[j-1]!='\n');
str[j-1] = '\0';
letters[i] = j;
}
But regarding your question: How can I replace getchar();? Have you considered using scanf()?
EDIT
Here is a simple example of using scanf() and printf() to prompt for input and then display input. It will allow user to input entire words or sentences (up to 80 characters) until 'q' is entered. Not exactly what you are doing, but you should be able to adapt it to your code... (run this)
int main(void)
{
char buf[80]={""};
while( strcmp(buf, "q") != 0) //enter a 'q' to quit
{
buf[0]=0;
printf("enter string:\n");
scanf("%s", buf);
printf("%s\n", buf);
}
}
Wouldn't it be easier to update the letter count in the first loop?
memset(letters, 0, n);
for (i=0;i<n;i++)
{
char* s = str;
int j=0;
printf("Give the next word.");
do{
*s = getchar();
++j;
}while (*(s++)!='\n');
s[-1] = '\0';
letters[j-1]++;
}
As a result the second loop will be unnecessary.
The following two lines have the wrong end condition; should be <n, not <=n. Currently they retrieve an uninitialized array element. Since you declared str as a local variable, that element is typically populated with garbage, i.e. a very big random number. That might explain why it takes extreme long (but possibly not forever) for the last loop to finish.
for (j=i+1;j<=n;j++)
}while ((i<=n));
Also, I assume line n of the histogram should contain the number of words that have n letters? That's not what you're doing right now.
letters[i] = count;
That line should have been:
letters[key] = count;
But to make that work, you should not overwrite the same array letters; you must declare a new array for your histogram, otherwise the second loop will destroy its own input.
By the way, str seems totally redundant. Is it there for debugging purposes?

Resources