I'm trying to convert character of a string to uppercase letters
int main (void)
{
int i = 0;
int n = 0;
static char *str[] = { "wow",
"RACEcar",
"No devil lived on.",
"rotor" };
for(i = 0; i < strlen(*str); i++)
{
if(str[i] != NULL)
{
n = function(str[i]);
}
}
return 0;
}
int function(char* x)
{
int i = 0;
int j = strlen(x);
char c;
for(i = 0; i < j; i++)
{
c = toupper(x[i]);
x[i] = c;
}
return 0;
}
I got an error saying exc bad access, code 2 at line where x[i] = c;
I'm not sure why I get this error, do I need to create another string and assign c to the new string?
toupper return the uppercase version of the character but didnt actually change the element itself, so I'm not sure what wrong with assigning the value return by toupper back to the element.
Your code attempts to modify a string literal , which causes undefined behaviour.
The string "No devil lived on." is non-modifiable. To help the compiler catch the error you should declare the array as:
static char const *str[] = { "wow", // etc.
For historical reasons, the compiler has to let it pass without breaking compilation if you forget to include the const. But it is still an error nonetheless, and some compilers will warn anyway.
For gcc you can use the flag -Wwrite-strings to disable support for the historical case; this will cause an error message to be generated for your code as-is.
Related
Hi I copied the following code from my linux machine with clion running. But in VS on Windows it seems to cause problems
entry_t* find_entry( char* n )
{
// TODO (2)
int x = strlen(n);
char str[x];
for (size_t i = 0; i < strlen(str); i++)
{
str[i] = toupper(n[i]);
}
n = &str;
for (size_t i = 0; i < list_length; i++)
{
if (strcmp(n, name_list[i].name) == 0)
{
return &name_list[i];
}
}
}
VS underlines the x in char str[x]; before the statement do find x was in the brackets of str. I thought finding the length first in another variable would solve the problem
VS give the following error
Schweregrad Code Beschreibung Projekt Datei Zeile Unterdrückungszustand
Fehler (aktiv) E0028 Der Ausdruck muss einen Konstantenwert aufweisen. Names.exe - x64-Debug C:\Users\Eyüp\source\repos\09\main.c 102
trying my best to translate it
-> Error(active) E0028 Statement needs to be a constant value
Variable-length arrays (i.e. arrays whose size is not known at compile-time) are not supported in MSVC because they don't care. Hence you need to use malloc and friends instead.
However that is not the only problem in your code: it has multiple undefined behaviours. Here is a suggested fix:
entry_t* find_entry( char* n )
{
// return value of strlen is of type size_t, not int
size_t x = strlen(n);
// [x] was wrong, it needs to be [x + 1] for the null terminator!
char *str = malloc(x + 1);
// do not use strlen again in the loop. In worst case it does need
// to go through the entire string looking for the null terminator every time.
// You must copy the null terminator, hence i <= x or i < x + 1
for (size_t i = 0; i <= x; i++)
{
// the argument of toupper needs to be *unsigned char*
str[i] = toupper((unsigned char)n[i]);
}
// why this did even exist? And it has type error anyway
// n = &str;
for (size_t i = 0; i < list_length; i++)
{
if (strcmp(str, name_list[i].name) == 0)
{
// need to free the str...
free(str);
return &name_list[i];
}
}
// in both paths...
free(str);
// add default return value
return NULL;
}
Your code invokes undefined behaviour:
as you do not null terminate the string
you call strlen on not null terminated (and initially not initialized string)
The logic is also wrong.
entry_t* find_entry( const char* n )
{
// TODO (2)
size_t x = strlen(n);
char str[x + 1];
for (size_t i = 0; i <= x; i++)
{
str[i] = toupper((unsigned char)n[i]);
}
str[x] = 0;
for (size_t i = 0; i < list_length; i++)
{
if (strcmp(str, name_list[i].name) == 0)
{
return &name_list[i];
}
}
return NULL;
}
You need to return something if the sting was not found.
To use VLAs in VS How to use Visual Studio as an IDE with variable length array(VLA) working?
trying to copy stuff from b into a but i get that error
someone told me it means i'm trying to access memory that i'm not allowed to, but i don't know what should i do to make it compile.
replace(txt , code);
string replace(string a , string b)
{
string alpha[26] = {"abcdefghijklmnopqurstuvwxyz"};
for (int i = 0; i < strlen(a); i++)
{
for(int n = 0; n < 26; n++)
{
if(a[i] == alpha[n])
{
a[i] = b[n];
i++;
}
}
}
return word;
}
i'm a beginner so no comments about clean coding or syntactic sugar or stuff like that just help me resolve this please
It looks like you have some problems with understending pointers, so I recommend you to read about them. Also consider reading about datatypes and types from STL you are using. (cause std::string is already an array of values so, when you are creating std::string[26], you actually are creating pointer to a pointer)
I guess you have are trying to do something like that:
std::string replace(string a , string b)
{
std::string alpha = {"abcdefghijklmnopqurstuvwxyz"};
for (size_t i = 0; i < a.size(); ++i)
{
for(size_t n = 0; n < alpha.size(); ++n)
{
if(a[i] == alpha[n])
{
a[i] = b[n];
i++; // Also, I think you doesnt need this line, cause you already incrementing i in for loop
}
}
}
return a;
}
Also you have used strlen() on your string, that also is not really correct, cause it is used on char values. If you whant to get length of a string it is better to use string.lenght()
Also, It is better to use size_t or unsigned int instead of int in this case, cause you don't need negative numbers in order to parce these strings. ()
(in C, using visual studio 2022 preview), I have to do a program that link two strings together. Here's what I did:
I wrote two for-loops to count characters of first string and second
string,
I checked (inside the link function if the pointers are null (first and second). If they are null, then "return NULL".
I created "char *result". this is a new string and this is the string to be returned. I allocated enough memory to store nprime, nsecond, and 1 more character (the zero terminator). I used a malloc.
then, I checked if result is null. if it's null then "return NULL".
then, I wrote 2 for-loops to perform the linking between the first string and the second string. And here I got a compiler warning (because I think it's in compile time not in debug time). buffer overrun, the writable size is
"nprime+nsecond+1" but 2 bytes might be written.
my theory is that the program is trying to write outside the result-array, so there could be a loss of data, I tried to edit my code, therefore I write "nprime+nsecond+2" instead but it doesn't work, and it keeps showing me the same buffer overrun error.
#include <stdlib.h>
char* link( const char* first, const char* second) {
size_t nprime = 0;
size_t nsecond = 0;
if (first == NULL) {
return NULL;
}
if (second == NULL) {
return NULL;
}
for (size_t i = 0; first[i] < '\0'; i++) {
nprime++;
}
for (size_t i = 0; second[i] < '\0'; i++) {
nsecond++;
}
char* result = malloc(nprime + nsecond + 1);
if (result == NULL) {
return NULL;
}
for (size_t i = 0; i < nprime; i++) {
result[i] = first[i];
}
for (size_t i = 0; i < nsecond; i++) {
result[nprime + i] = second[i];
}
result[nprime + nsecond] = 0;
return result;
}
this is the main:
int main(void) {
char s1[] = "this is a general string ";
char s2[] = "this is a general test.";
char* s;
s = link(s1, s2);
return 0;
}
The warning is given due to the wrong conditions you defined in the first 2 for loops. The right loops should be as follows:
for (size_t i = 0; first[i] != '\0'; i++) {
nprime++;
}
for (size_t i = 0; second[i] != '\0'; i++) {
nsecond++;
}
With the conditions you defined (i.e. first[i] < '\0') you are just counting how many chars in the given string have an ASCII code lower than the ASCII code of \0 and exit the loop as soon as you find a char not fulfilling such condition.
Since '\0' has ASCII value 0, your nprime and nsecond are never incremented, leading to a malloc with insufficient room for the chars you actually need.
This function is basically just supposed to compare 2 strings and return their ASCII difference if they are different. It works perfectly fine when I compile it with the GCC compiler, but when I run it through the online compiler that is used to upload our classes homework, I get this error message:
Error near line 98: Reading an uninitialized value from address 10290
Line 98 is marked in the below code. I am not quite sure what the problem is and how I'm supposed to fix it. Does anyone have an idea?
int stringCompare(char * pStr1, char * pStr2) {
int n = 100;
int difference;
for (int i = 0; i < n; i++) {
difference = pStr1[i] - pStr2[i]; // line 98
if (difference != 0) {
return difference;
}
}
return difference;
}
Your code can skip over EOLN, if string equals, and try to compare memory after end of lines. To fix this, you need instantly return, if both string equals, and you see EOLN char '\0' in both strings at position i. Try my fix:
int stringCompare(char * pStr1, char * pStr2) {
int n = 100;
int difference;
for (int i = 0; i < n; i++) {
difference = pStr1[i] - pStr2[i];
if (difference != 0 || pStr1[i] == '\0') {
return difference;
}
}
return difference;
}
The problem in your code is that you fail to check the real length of the strings before indexing them. You are iterating with i from 0 to 99, but you do not check for the NUL terminator (\0) that marks the end of a string and therefore your for loop goes beyond the end of the string resulting in undefined behavior accessing memory that is not supposed to (which is what the error is telling you).
The correct way to iterate over a string, is not to loop a fixed amount of cycles: you should start from index 0 and check each character of the string in the loop condition. When you find \0, you stop. See also How to iterate over a string in C?.
Here's a correct version of your code:
int stringCompare(char *pStr1, char *pStr2) {
size_t i;
for (i = 0; pStr1[i] != '\0' && pStr2[i] != '\0'; i++) {
if (pStr1[i] != pStr2[i])
break;
}
return pStr1[i] - pStr2[i];
}
You could even write this more concisely with a simple while loop:
int stringCompare(char *pStr1, char *pStr2) {
while (*pStr1 && *pStr1 == *pStr2) {
pStr1++;
pStr2++;
}
return *pStr1 - *pStr2;
}
Of course, both the above functions expect two valid pointers to be passed as arguments. If you also want to allow invalid pointers you should check them before starting the loop (though it does not seem like you want to do that from your code).
I am new to programming in C and am trying to write a simple function that will compare strings. I am coming from java so I apologize if I'm making mistakes that seem simple. I have the following code:
/* check if a query string ps (of length k) appears
in ts (of length n) as a substring
If so, return 1. Else return 0
*/
int
simple_substr_match(const unsigned char *ps, /* the query string */
int k, /* the length of the query string */
const unsigned char *ts, /* the document string (Y) */
int n /* the length of the document Y */)
{
int i;
for(i = 0;i < n;i+k){
char comp;
comp = ts->substring(i,k);
if (strncmp(comp, ps, k)) {
return 1;
}
}
return 0;
}
When trying to compile i get the error: request for member 'substring' in something not a structure or union.
The idea of the code is describe in the code comment but just to elaborate I am looking to see if ps occurs as a substring of ts in increments of k(length of ps).
What am I doing wrong and how can I fix it? Is there a better way of doing what I am trying to do?
Change
for(i = 0;i < n;i+k){
char comp;
comp = ts->substring(i,k);
if (strncmp(comp, ps, k)) {
return 1;
}
}
to
for(i = 0;i < n-k;i++){
if (!strncmp(ts+i, ps, k)) {
return 1;
}
}
ts is a char* not a class (and you're writing in C, not C++)
How about using the standard 'strstr' C function?
if (strstr(ts, ps) != NULL) {
return 1;
} else {
return 0;
}
C doesn't have member functions. and in c++ char doesn't have a member function substring.
you should use ts as an character array.
Something like this?
#define simple_substr_match(ps,ts) (strstr(ts,ps) != NULL)