I am working on a initials project where you enter a name and it prints the initials. When I try and combine the strings it returns Segmentation fault instead of the initials.
#include <stdio.h>
#include <stdlib.h>
#include <cs50.h>
#include <string.h>
#include <ctype.h>
int main(void) {
printf("Name: ");
string name = GetString();
printf("\n");
int length = strlen(name);
string initials = "";
int arraylength = length + 1;
char string[arraylength];
string[0] = toupper(name[0]);
int count = 1;
for(int l = 1;l<=length;l++) {
if(name[l] == ' ') {
l++;
count++;
string[l] = toupper(name[l]);
}
}
count++;
string[count] = '\0';
for(int c = 0;c<=count;c++) {
strcat(initials, &string[c]);
}
printf("%s\n", initials);
}
That's why a string type would cause confusion, you make a pointer to a single char. And you then pass it to strcat() that's simply wrong.
A string, as expected by strlen() or strcat() or all str* functions, is not simple a char pointer which is what the type string in your code is.
In c a c-string is actually a sequence of bytes with the last byte being '\0', and it's not optional. You create a pointer to a single char and that is not the same as a string that I just described.
Any of the str* functions will try to find the '\0' but since you passed the address of a stack variable which is not an array, the behavior is undefined when any of these functions try to increment and dereference the passed pointer.
When you do understand how strings work in c you would see that using strcat() for the concatenation of many chunks of a large string together is not very efficient, you would also know that you just need to append a single char and that you can by simply using index notation, like
char string[8];
string[0] = 'E';
string[1] = 'x';
string[2] = 'a';
string[3] = 'm';
string[4] = 'p';
string[5] = 'l';
string[6] = 'e';
string[7] = '\0'; // The very necessary terminator
Related
I'm trying to write a program that uses Caesar's algorithm to cipher a string input. I'm a beginner to C but I can understand basic codes. So to cipher the text I wrote this code, but when I enter the input, I get an error that says
Segmentation fault (core dumped)
I tried to do some debugging by removing the else condition at the end and the program kind of worked for short inputs of 2-3 letters
Can someone please help me with this issue?
I'm using the CS50's header only to get the string in the first place.
#include <stdio.h>
#include <cs50.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
int main(int argc, char * argv[])
{
char name[] = "";
strcat(name, argv[1]);
int key = atoi(name);
string plaintext = get_string("plaintext: ");
int length = strlen(plaintext);
char ciphertext[] = "";
for(int i = 0; i < length; i++)
{
int skipCount = 0;
if(isalpha(plaintext[i]))
{
while(skipCount < key)
{
char tmp = (char) ((int) plaintext[i] + 1);
if(isalpha(tmp))
{
ciphertext[i] = tmp;
skipCount++;
}
else
{
if (isupper(plaintext[i]))
{
tmp = 'A';
skipCount++;
}
if (islower(plaintext[i]))
{
tmp = 'a';
skipCount++;
}
}
}
}
else ciphertext[i] = plaintext[i];
}
printf("%s\n", ciphertext);
}
What you need to understand about C, is that it does not automatically allocate memory.
You have to it your self!
This line:
char name[] = "";
creates an array of size 1, which holds a single character - the "null" character = '\0';
It signifies an empty string.
You can not copy any larger string in to it, because all strings in C must have a null character at the end, so there isn't enough room for even a single readable character.
As a beginner, you would need to decide what the maximum length of the string you want will be, and declare the array to be of proper size:
char name[255];
This is one example that can hold up to 254 characters, plus the terminating null character.
I am currently trying to handle string in C and I am having trouble placing the split values of a string into an array. Bellow is the code I have created in an attempt to achieve this.
#include <stdio.h>
#include <string.h>
int main(){
char str[]="titanic.txt";
char parts[2][5];
char *name = strtok(str, ".");
for (int i = 0; i < 2; i++){
parts[i][5] = name;
char name = strtok(NULL, ".");
}
printf("%c\n", str[0]);
return 0;
}
The output I would be expecting from this would hopefully look something like this.
char part[2][10]{
{'t', 'i', 't', 'a', 'n', 'i', 'c'},
{'t', 'x', 't'}
};
alternatively, I have tried something like this using string copy as such.
#include <stdio.h>
#include <string.h>
int main(){
char str[]="titanic.txt";
char parts[2][10];
char *name = strtok(str, ".");
for (int i = 0; i < 2; i++){
strcpy(parts[i], name);
name = strtok(NULL, ".");
}
printf("%s\n", parts[1]);
return 0;
}
Which, did what I want it to, but I would like to try and achieve this without string copy because I feel it will help me understand strings, characters, and arrays better. I do not want to reinvent the wheel I just want a deeper understanding.
The parts array should be an array of pointers, not a 2-dimensional array of characters:
char *parts[2];
Then you assign:
parts[i] = name;
If you want to copy from the input string to parts, you need to declare the 2nd dimension large enough for the largest possible string:
char parts[2][10];
and then you should use strcpy() rather than assignment to copy it.
strcpy(parts[i], name);
Notice that you don't give a second index to parts when doing this, that's only used to access specific characters of the string, not the string as a whole.
In case separating a file name from its extension is actually relevant to whatever you're trying to accomplish, I'll assume you're using Windows and point you to the documentation for the recommended Windows API library for this, <pathcch.h>.
With regard to your actual question, your first code doesn't work because:
You're assigning to a single character in the line parts[i][5] = name;. You're also overflowing since parts[i] has the type char [5], which only has positions 0 to 4.
You redeclare name as a single char rather than a char * pointer, which is the correct type, and was declared as such (correctly) outside the loop scope. Your new variable char name overwrites the existing char *name variable.
You cannot get around using strcpy-family functions to assign to a character array for this (and most other) use cases. The only time the syntax char foo[] = "Hello World"; is valid is immediately on declaration. Also, string literals are stored in read-only memory.
Following your coding style, this is the solution:
#include <stdio.h>
#include <string.h>
int main()
{
char str[] = "titanic.txt";
char delim[] = ".";
char parts[2][10];
char *ptr = strtok(str, delim);
int i = 0;
for (i = 0; i < 2; i++){
if(ptr != NULL)
{
snprintf(parts[i], sizeof(parts[0]) ,"%s", ptr);
ptr = strtok(NULL, delim);
}
}
printf("'%s'\n", parts[0]);
printf("'%s'\n", parts[1]);
return 0;
}
I'm studying C. I came across with string arrays. I'm bit confused about the following codes. I was anticipating one kind of output; however, getting completely different kind of output or program crush due to read access violation.
I've run this code on visual studio 2017, with _CRT_SECURE_NO_WARNINGS
// case 1
char* name[2];
//name[0] = (char*)malloc(sizeof(char*) * 10);
//name[1] = (char*)malloc(sizeof(char*) * 10);
name[0] = "john";
name[1] = 'doe';
printf("%s\n", name[0]); // prints john
//printf("%s\n", name[1]); // gives read access violation exception, why??? even with dynamically allocated memory
// case 2
char* name2[2] = { "emma", "olsson" };
printf("%s\n", name2[0]); // prints emma
printf("%s\n", name2[1]); // prints olsson, why no error???
// case 3
for (int i = 0; i < 2; i++)
{
name[i] = name2[i];
}
printf("%s\n", name[0]); // prints emma
printf("%s\n", name[1]); // prints olsson, why no error???
// case 4
char inputName[10];
int i = 0;
while (i < 2)
{
fgets(inputName, sizeof(inputName), stdin); // first input: Max second input: Payne
char* pos = strchr(inputName, '\n');
if (pos != NULL)
*pos = '\0';
name[i++] = inputName;
}
printf("%s\n", name[0]); // prints Payne, why not Max???
printf("%s\n", name[1]); // prints Payne
For case 1, 'doe' is not a string.
Case 2 works because you are initializing you pointers with string literals.
Case 3 works too because you assign the same initialized pointer in case 2 to case 1 pointers. Your name array pointers are basically set to point to where name2 ones are pointing.
In case 4, you declared inputName which points to a set of 10 chars. Then each time you get a new input you are writing it to the same memory section. And by doing this:name[i++] = inputName;
you are not copying a new char array to name[i] as you might think. Instead, you are telling name[i] char pointer to point to inputName. So it is normal that name prints last input twice, because that's what inputName points to, as well as both name char pointers.
It is unclear whether OP's code runs within main() or a user-defined function and what kind of value returns. That said, after removing superfluous variable redeclarations, here's how I achieved working code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char * name[2];
char * name2[2]={ "emma", "olsson" };
char inputName[10];
char names[BUFSIZ];
int i = 0;
// case 1
name[0] = "john";
name[1] = "doe";
printf("%s %s\n", name[0],name[1]); //john doe
// case 2
printf("%s %s\n", name2[0],name2[1]);//emma olsson
// case 3
for (i = 0; i < 2; i++){
name[i] = name2[i];
}
printf("%s %s\n", name[0],name[1]);//emma olsson
// case 4
i=0;
while (fgets(inputName, sizeof(inputName), stdin) != NULL && (i < 2) ){
strcat(names,inputName);
i++;
}
printf("\n%s\n",names);
return 0;
}
See live code here
OP should replace the single quotes around doe with double quotes which denote a null-terminated string. Single quotes are meant for a single character, i.e. 'a' refers to a byte value while "a" signifies a string containing two characters, an 'a' and a '\0'.
Also, OP should include two other libraries to facilitate execution. In particular, string.h is needed for the built-in string functions to execute properly.
Case 2 and Case 3 work because strings are encompassed by double quotes instead of single quotes. Note that in each case the "%s" format specifier for the printf() indicates that a string needs to be displayed.
In last case, fgets() with respect to stdin, upon success returns user input as a string. But that input will be overridden in the while loop, unless in each iteration you concatenate the old input with the new. Otherwise, when the inputName element values change because its address remains constant, only the latest input string displays. Here's some code that illustrates this point:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char * name[2];
char inputName[10];
int i = 0;
while (fgets(inputName, sizeof(inputName), stdin) != NULL && (i < 2) ){
printf("inputName: %p points to: %s",inputName,inputName);
name[i++] = inputName;
}
printf("\n name[0]: %p points to: %s\n name[1]: %p points to: %s",name[0],name[0],name[1],name[1]);
return 0;
}
Output:
inputName: 0x7fff8a511a50 points to: Maxine
inputName: 0x7fff8a511a50 points to: Pauline
name[0]: 0x7fff8a511a50 points to: Pauline
name[1]: 0x7fff8a511a50 points to: Pauline
See live code.
Incidentally, you don't need an array to display the names and indeed one may display the names outside of the loop as long as within the loop the code concatenates user input.
I wrote a function that cuts the string "hello world" to "hell" if a 'o' is found.
I keep getting a segmentation fault. I don't know where the mistake could be.
Could anyone help?
Thank you in advance.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* cutString(char* str, char del){
char *newstring =(char*) str;
malloc(sizeof(char)*strlen(str));
int i= 0;
for(; newstring[i]!='\0'&&newstring[i]!=del;i++);
if(i==strlen(newstring))
printf("not found");
else
newstring[i]='\0';
return newstring;
}
int main(){
cutString("Hello World",'o');
return 0;
}
There are two major problems with your code:
char *newstring =(char*) str makes newstring point to the old str. And since you pass a literal string (which is read only) you will have undefined behavior attempting to modify it.
malloc(sizeof(char)*strlen(str)); is a memory leak. And doesn't allocate space for the terminator.
The crash is probably because point one, when you attempt to modify the read-only string literal.
There are a number of problems in your code. The main problem is that you don't assign the return value from malloc to newstring. Besides that you need to malloc an extra byte for the string termination.
Further, your loop must copy characters from str into newstring.
In main you must assign the return value from the function to a char pointer variable to get hold of the new string.
Something like:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* cutString(char* str, char del){
char *newstring = malloc(strlen(str) + 1); // malloc into newstring
int i= 0;
while (newstring[i]!='\0' && str[i] != del) // Stop when a) no more chars in str or b) "del" is found
{
newstring[i] = str[i]; // Copy character from str to newstring
++i;
}
newstring[i]='\0'; // Terminate the string
return newstring;
}
int main(){
char* newstring = cutString("Hello World",'o'); // Save the returned value
printf("%s\", newstring);
free(newstring);
return 0;
}
newstring[i]='\0';
This line is invalid. Modifying string literals is undefined behavior. I would suggest check this out :segmentation fault when using pointer
A better solution would be to use arrays instead of pointers
I would like to write a function in C that truncates an input string to 32 chars, but the code below gives me a segmentation fault. Could anyone explain why it is so?
void foo (char *value){
if (strlen(value)>32) {
printf("%c\n", value[31]); // This works
value[31] = '\0'; // This seg faults
}
}
If you call your function like this:
char str[] = "1234567890123456789012345678901234567890";
foo(str);
It will work fine. But if you call it like this:
char *str = "1234567890123456789012345678901234567890";
foo(str);
That can cause a segfault.
The difference here is that in the former case str is a char array, while in the latter case str is a pointer to a string constant. A string constant typically lives in a read only section of memory, so attempting to modify it causes the core dump.
Your program should be something like this :
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void foo(char **value) {
if (strlen(*value)>32) {
printf("%c\n", (*value)[32]);
(*value)[32] = '\0'; // You want the string length to be 32, so set 32th character to '\0' so 32 characters will be from 0 to 31
}
}
int main() {
char *str;
str = malloc(100); // Change 100 to max possible length of string user can enter
printf("Enter string : ");
scanf("%s", str);
foo(&str);
printf("Truncated string is %s\n", str);
free(str);
return 0;
}