This question already has answers here:
How should character arrays be used as strings?
(4 answers)
Closed 3 years ago.
I want to write a C program that stores a bunch of sentences while it's running and prints them out at the end of the program.
Here's what I wrote:
#include<string.h>
#include<stdio.h>
int main(){
int counter = 0;
char state[100][200];
char stroo[3] = "yes";
sprintf(state[counter], "%s", stroo);
counter++;
char poo[2] = "44";
sprintf(state[counter], "%s", poo);
counter++;
for (int i=0; i<counter; i++) {
printf("%s\n", state[i]);
}
return 0;
}
For the output, the first line prints "yes" which is what I expected. The second line, however, prints "44yes". Why is it printing "yes" as well as "44"?
That's because your strings aren't correctly null-terminated, so you run into undefined behavior at the sprintf. This is because the buffer is too small to hold the null-terminator. For instance here:
char stroo[3] = "yes";
You need memory for four chars, the 'y', 'e', 's' and the null-terminator. Change it to
char stroo[4] = "yes";
Likewise char poo[2] needs to be char poo[3].
See here (emphasis mine):
Successive bytes of the string literal or wide characters of the wide string literal, including the terminating null byte/character, initialize the elements of the array [...] If the size of the array is known, it may be one less than the size of the string literal, in which case the terminating null character is ignored:
If you want the size to automatically be big enough to exactly fit the string, you can just leave out the size specification:
char stroo[] = "yes";
And of course, for this example, you don't even need to copy the string to the stack:
char *stroo = "yes";
#define STRINGS 5
#define STRING_SIZE 50
char arr[STRINGS][STRING_SIZE] =
{ "Hi",
"Hello world",
"Good morning",
"ASDF",
"QWERTY"
};
for (int i=0; i<STRINGS; i++) {
printf("%s\n", arr[i]);
}
Related
This question already has answers here:
Does printf terminate every string with null character?
(3 answers)
What's the rationale for null terminated strings?
(20 answers)
Closed 24 days ago.
I would like to understand why this code works:
void open_image(const char *filename)
{
char *ImageName = filename;
printf("%s", ImageName);
}
const char image_name[] = "image.jpg";
open_image(image_name);
it prints "image.jpg" as wanted, but I don't know how the program knows the length of the string.
The program knows the size of the string image_name as it is computed during compilation.
But in the open_image function, how does the printf function knows the length of this string as it is only given the pointer ImageName created at runtime?
Thank you.
In C a string (array of char) is always terminated by the "terminator" character '\0', so you can get the length of the array by checking each character until you find it.
Here's a simple solution:
int i = 0;
char ch;
do
{
ch = arr[i];
i++;
} while(ch != '\0');
printf("String length: %d\n", i-1); // This will give the string length
printf("Total length of the array: %d\n", i); // This will give the array full length, including the terminator character.
Probably the best way to get a char array length is to import the string.h library which exposes the strlen() function.
However, it's always useful to learn how things actually work at low-level, especially when learning C). :-)
This question already has answers here:
Given a starting and ending indices, how can I copy part of a string in C?
(3 answers)
Closed 4 years ago.
I have a string
str = "hello"
I want to make a new string which is the first two digits of str "he".
How do I do this in C?
Use strncpy(), like this:
#include <stdio.h>
#include <string.h>
int main(void) {
char src[] = "hello";
char dest[3]; // Two characters plus the null terminator
strncpy(dest, &src[0], 2); // Copy two chars, starting from first character
dest[2] = '\0';
printf("%s\n", dest);
return 0;
}
Output:
he
This question already has answers here:
Why do I get a segmentation fault when writing to a "char *s" initialized with a string literal, but not "char s[]"?
(19 answers)
Closed 5 years ago.
I keep getting a segmentation error when I try to add a character to the string test. I have tried multiple iterations and can't figure out why I get the error. I tried having the test set to \0. I can't figure out how I am accessing outside test.
#include <stdio.h>
#include <cs50.h>
#include <ctype.h>
#include <string.h>
#define _XOPEN_SOURCE
#include <unistd.h>
#include <crypt.h>
//this intializes the argument count and argument vector
int main(int argc, string argv[]) {
//this makes sure it is a string
if (argv[1] != NULL) {
//this makes sure that the user typed 2 arguments,
// the second being the keyword
if (argc != 2) {
printf("no hash inputed\n");
return 1;
}
//main program once the keyword has been verified
int h_len = strlen(argv[1]);
string hash = argv[1];
string test = "A";
int p_len = 0;
printf("H len is %i and P len is %i\n", h_len, p_len);
printf("%s and test: %s\n", hash, test);
//this will iterate through the 1st space and test the charachters
for (int j = 0; j < 4; j++) {
//iterates through the characters that can be used in the password
//for (int i = A; i < z; i++)
//for (char ch = 'A' ; ch <= 'z' ; ch == 'Z' ? ch = 'a' : ++ch )
for (char i = 'A'; i <= 'z'; i++) {
//this skips the ASCII inbetween Z and a
if (i > 'Z' && i < 'a') {
i = 'a';
}
printf("%c", i);
//test[j] = test[j] + (char)i;
test = strncat(test, &i, 1);
printf(" test is %s\n", test);
...
In this declaration
string test = "A";
there is declared the pointer test to the string literal "A". You may not change string literals.
According to the C Standard (6.4.5 String literals)
7 It is unspecified whether these arrays are distinct provided their
elements have the appropriate values. If the program attempts to
modify such an array, the behavior is undefined
However in this statement
test = strncat(test, &i,1);
there is an attempt to modify the string literal pointed to by the pointer test.
You should declare a character array that has enough space to store additional characters.
Moreover if you are using the function strncat to copy n characters from the source string you should reserve memory in the destination array for n + 1 characters because the function always appends the terminating zero.
That is (The C Standard, 7.23.3.2 The strncat function, footnote 302)
302) Thus, the maximum number of characters that can end up in the
array pointed to by s1 is strlen(s1)+n+1.
Note that in this horrible cs50, string is defined as char *, so string test = "A"; is equivalent to char *test = "A"; which will make test point to a constant string of length 1 plus a null!
So even if it would be long enough to concatenate anything, you can't because it is read-only, and even if it was not read-only, you can't because it is not long enough.
You have a string with one character in it (test="A") so it has a length of 2 (A + null char) and are trying to append other characters to it, so it WILL access outside of test.
everything is wrong here
you cant strcat char * and the address of the char as you never know if there is zero after that character. Your string is too short to accomodate anything longer than one character string. Next - you try to do something with RO memory as your test points to the string literal.
Buy a good book about C
This question already has answers here:
scanf() leaves the newline character in the buffer
(7 answers)
Closed 6 years ago.
We created this program in university that creates an array of characters by address in language c.
but the first element (char* str) output a weird space.
I saw some tutorials about arrays of characters where the first element is the first character we typed.
so why is this happening ? is their some situations where this happens ? if so how can i know if my string starts from the first or second element without using printf everytime ?
This is my program
#include<stdio.h>
#include<stdlib.h>
char* newStr(int n);
int length(char* str);
int main() {
int n,i;
printf("Number of characters \n");
scanf("%d",&n);
char* str = newStr(n);
char* c = malloc(n*sizeof(char)+1);
c=str;
// check that c[0]=' ' and c[n+1]=\0
for(i=0;i<=n+1;i++) printf("*(str+%d) = %c \n",i,*(c+i));
return 0;
}
char* newStr(int n) {
int i;
char* c;
c=malloc(n*sizeof(char)+1);
printf("Enter a word of %d characters \n",n);
for(i=0;i<=n;i++) {scanf("%c",(c+i));}
*(c+n+1)='\0';
return c;
}
int length(char* str) {
int i=0;
while(*(str+i)!='\0'){i++;}
return i-1;
}
and this is the output
Number of characters
5
Enter a word of 5 characters
hello
*(str+0) =
*(str+1) = h
*(str+2) = e
*(str+3) = l
*(str+4) = l
*(str+5) = o
*(str+6) =
The length of your string is 5
can someone explain it to me in simple termes as i'm quite new to c.
thanks in advance
Someone already answered in the comments that the scanf() function does not consume the trailing newline char.
So if the user presses "Enter" in their keyboard, and then a scanf() occurs in your code, that Enter press will be recorded.
Also I want to focus your attention in the newStr() function.
There you allocate space for a new string and store it in a dynamic array of characters, your char *c, and then return that pointer.
But in your main() you save the return value in str and, for some reason trying to copy it to another pointer(and doing it wrong by the way)?
char* str = newStr(n);
char* c = malloc(n*sizeof(char)+1);
c=str;
str is ALREADY a string you can use, no need to make another malloc on char *c. And when you write
c=str;
You are actually assigning to the char *c the address of str, not the values pointed by str, thus making this line of code:
char* c = malloc(n*sizeof(char)+1);
Completely useless, and error prone, because you will not be able to free that pointer anymore, having lost the address.
I don't know if I was clear...
As already mentioned, scanf("%d",&n) does not consume the new line character, but scanf("%d\n",&n) will.
BTW, just to present a short (but probably hacky) approach, which uses scanf("%20s",...), yet with variable width specifier instead of hardcoded 20:
int n;
char format[20];
scanf("%d\n",&n);
char *result = malloc((n+1) * sizeof(char));
sprintf(format, "%%%ds", n);
scanf(format, result);
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I've been trying to learn C programming by reading a textbook, but am confused about how strings and substrings work.
I have an idea of what strings and substrings are from java, but can't figure out the syntax in C.
Here's a question from the book that I thought might be easy, but I can't get it.
Write and test a function hydroxide that returns a 1 for true if its string argument ends in the substring OH.
It recommends testing the function with KOH and NaCl.
Also, how would I remove and add letters at the end of the string?
Like, if for some reason I wanted to change NaCl to NaOH?
Any help and explanations would be really appreciated.
ETA:
I guess what I'm most confused on is how to make the program look at the last two letters in the string and compared them to OH.
I'm also not sure how to pass strings to functions.
String is a sequence of characters that ends with special null-terminated character '\0'. If there is no \0, functions that work with string won't stop until the \0 symbol is found. This character may happen in any place after the end of pseudo string (I mean a string without \0) and only then stop.
The following example shows the necessity of this null-terminated character:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char string[] = "Hello!";
printf("original string:\n%s\n\n", string);
memset(string, '-', 5);
printf("memset doesn't affect the last two symbols: '!' and '\\0':\n%s", string);
memset(string, '-', 6);
printf("\n\nmemset doesn't affect the last symbol: '\\0':\n%s\n\n", string);
memset(string, '-', 7);
printf("memset affects all symbols including null-terminated one:\n%s", string);
return 0;
}
/* OUTPUT:
original string:
Hello!
memset doesn't affect the last two characters: '!' and '\0':
-----!
memset doesn't affect the last character: '\0':
------
memset affects all characters including null-terminated one:
-------#↓#
*/
Substring is a char sequence that is in a string. It may be less or equal to the string.
Suppose, "NaOH" is a string. Then substring may be: "N", "a", "O", "H", "Na", "aO", "OH", "NaO", "aOH", "NaOH". To find whether substring is in the string or not you can use strstr function. It's prototype is char * strstr ( char * str1, const char * str2 );.
This code shows this function's results:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *ptrCh = NULL;
ptrCh = strstr("hello", "h");
printf("ptrCh: %p\n", ptrCh);
printf("%s\n\n", ptrCh);
ptrCh = strstr("hello", "z");
printf("ptrCh: %p\n", ptrCh);
printf("%s\n\n", ptrCh);
return 0;
}
/* OUTPUT:
ptrCh: 00403024
hello
ptrCh: 00000000
(null)
*/
As for the first printf, it prints characters beginning from the position of 'h' and when it reaches null-terminated character, which is next after 'o', it stops, exactly as in previous program.
To make your program more interactive, you can declare array and then a pointer to it. Array size must be enough to store the longest formula. Suppose, 100 will be enough:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char buf[100] = {0};
char *ptr = &buf[0];
scanf("%s", ptr);
// printf() gets a pointer as argument
printf("%s\n", ptr);
// printf() gets also a pointer as argument.
// When you pass arrays name without index to a function,
// you pass a pointer to array's first element.
printf("%s", buf);
return 0;
}
And as for rewriting letters in the end of the string. Here is a small program that does it. Pay attention at comments:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char buf[100] = {0};
char formula[100] = {0};
char compound[100] = {0};
char *ptr = &buf[0];
char *pFormula = &formula[0];
char *pCompound = &compound[0];
printf("Enter formula: ");
scanf("%s", pFormula);
printf("Enter chemical compound: ");
scanf("%s", pCompound);
// Copying the first chemical elements without the last
// several that will be replaced by another elements.
strncpy(ptr, pFormula, strlen(pFormula) - strlen(pCompound));
// Adding new compound to the first elements.
// Function also adds a null-terminated character to the end.
strncat(ptr, pCompound, strlen(pCompound));
printf("The new chemical compound is: ");
printf("%s", ptr);
return 0;
}
/* OUTPUT:
Enter formula: NaOH
Enter chemical compound: Cl
The new chemical compound is: NaCl
*/
In C, we use null-terminated strings. That is the "invisible", 0 value. Not ASCII "0", but the zero value, like 8-bit 0x00. You can represent it in literal text with '\0' or "\0" or unquoted 0, however, in a literal string it is redundant because most functions like strcmp() or strstr() or strcat() all expect and work with null terminated strings. Null char is the stops sign for the C standard string functions.
One easy way to implement this with C library calls is to test for existence of the substring and then test that substring's length, which verify it is at end of string.
Assume buf is some big string buffer, char buf[1024] and char *temp is a temporary variable.
temp = strstr(buf, "OH") returns the pointer to "OH" if exists in buf at any offset.
strlen(temp) Get length of temp, if at end of string, it will be 2 (doesn't include null terminator), so if the original string is "OHIO" or "SOHO" it wont match because it'll be 4 and 3 respectively.
The above is the core of the code, not the full robust implementation. You need to check for valid return values, etc.
char buf[1024];
char *temp;
strcpy(buf, "NaOH");
if((temp = strstr(buf, "OH")) != 0)
{
// At this point we know temp points to something that starts with "OH"
// Now see if it is at the end of the string
if(strlen(temp) == 2)
return true; // For C99 include stdbool.h
return false;
}
You could get obscure, and check for the null terminator directly, will be a smidge quicker. This code is safe as long as it is inside the if() for strstr(), otherwise never do this if you don't know a string is a least N characters long.
if(temp[2] == '\0')
return true; // For C99 include stdbool.h
As far as appending to a string, read the docs on strcat. Keep in mind with strcat, you must have enough space already in the buffer you are appending into. It isn't like C++ std::string or Java/C# string where those will dynamically resize as needed. In C, you get to do all of that yourself.