2016-08-23 8 views
-1

В моей программе я пытаюсь скопировать каждый argv [i] на ключевое слово [i], но моя программа не работает с ошибкой сегментации. Что я делаю не так?Ошибка сегментации при попытке объявить массив строк

#include <stdio.h> 
#include <cs50.h> 
#include <ctype.h> 
#include <string.h> 

int main(int argc, string argv[])  
{ 
    //prototype 
    string keyword = ""; 
    //int j; 

    for (int i = 0, n = strlen(argv[1]); i < n; i++) 
    { 
     keyword[i] = toupper(argv[1][i]); 
     printf("%i-- printing letters\n", keyword[i]); 
    } 
} 
+0

'string keyword =" ";' вы выделили нулевое пространство для строки, которая будет скопирована, и когда у вас будет достаточно большое пространство, вы также должны написать терминатор строки 'nul', прежде чем вы сможете называть его строкой ». –

+1

Что такое строка? Это C или C++? –

+2

@IshayPeled: "*' string' * "most likes приходит из" * '# include ' * "и кажется строкой' typedef char *; '...: -/ – alk

ответ

4

Как отмечают другие, инициализации переменной keyword либо как пустая строка или указатель на пустую строку буквального, в зависимости от определения типа string. В любом случае, тогда справедливо оценить keyword[i] только для i, равного нулю; любое другое значение - для чтения или записи - выходит за пределы. Кроме того, в последнем случае (указатель на строковый литерал) вы не должны пытаться изменить массив keyword пунктов.

Обратите внимание, в частности, что C не автоматически расширяет строки, если вы пытаетесь получить доступ к элементу без границ. Вместо этого попытка сделать это создает «неопределенное поведение», и общий способ проявления в таких случаях заключается в виде ошибки сегментации. Вы можете просмотреть ошибку сегментации, поскольку система ударяет по вашей программе, пытаясь получить доступ к памяти, которая ей не принадлежит.

Поскольку вы не знаете, априори как долго аргумент строка будет, прежде чем скопировать его, наиболее жизнеспособным типом для keyword является char *. Я буду использовать этот тип вместо string в дальнейшем, для ясности.

Если вы действительно хотите, чтобы сделать копию аргумента, то самым простым способом сделать это является через для-цели функции strdup():

char *keyword = strdup(argv[1]); 

Это выделяет достаточно памяти для копии его аргумент, включая терминатор, копирует его и возвращает указатель на результат. Затем вы обязаны освободить полученную память через функцию free(), когда закончите с ней. Сделав копию таким образом, вы можете UPCASE каждый элемент на месте:

for (int i = 0, n = strlen(keyword); i < n; i++) 
    { 
     keyword[i] = toupper(keyword[i]); 
     printf("%c-- printing letters\n", keyword[i]); 
    } 

Note, кстати, что дескриптор формата printf() для одного символа является %c, не %i. Вы должны использовать это для печати символов как символов, а не их целых значений.

Это один из простейших способов написать код C для того, что вы пытаетесь сделать, хотя есть много вариантов.Единственный один я предлагаю вашему вниманию, чтобы не копию Аргумент у всех:

char *keyword = argv[1]; 

Если инициализировать keyword таким образом, то вы не выделять какой-либо памяти или сделать копию; вместо этого вы установите keyword, чтобы указать на ту же строку, что и argv[1]. Вы можете изменить эту строку на месте (хотя вы не можете ее удлинить), при условии, что вам не нужно сохранять исходное содержимое.

Прежде чем я завершу это, я также должен заметить, что ваша программа не проверяет, действительно ли есть аргумент. В случае отсутствия (, т. Е.argc < 2), argv[1] либо содержит нулевой указатель (argc == 1), либо не определен (argc == 0; вы вряд ли когда-либо столкнетесь с этим). В любом случае ваша программа создает неопределенное поведение в этом случае, если она пытается использовать argv[1], как если бы это был указатель на допустимую строку. Сначала вы должны сначала проверить этот случай и завершить диагностическое сообщение, если нет аргументов программы.

+0

большое спасибо! – olafironfoot

-2

Ваша главная проблема: вы не выделять память для новой строки (string keyword = "").

В C каждый размер, который неизвестен во время компиляции, должен быть динамически распределен во время выполнения.

Кроме того, вы никогда не проверяете отсутствие параметров, которые могут привести к сбою вашей программы.

См ниже код для обоих исправлений

#include <cs50.h> 
#include <stdio.h> 
#include <ctype.h> 
#include <string.h> 
#include <stdlib.h> 

int main(int argc, string argv[]) 

{ 
    if (argc != 2) 
    { 
     printf("Usage: %s <word>\n", argv[0]); 
     return 1; 
    } 
    int length = strlen(argv[1]); 
    string keyword = malloc(length+1); 

    for(int i = 0, n = strlen(argv[1]); i < n; i++) 
    { 
     keyword[i] = toupper(argv[1][i]); 
     printf("%i-- printing letters\n", keyword[i]); 

    } 
    keyword[length]=0; 
    free(keyword); 
} 
+1

'Ваша главная проблема: вы не выделяете память для своей новой строки ... и вы не' free() 'it. – Michi

+2

Этот код вызовет проблему, если после этого попытается получить доступ к 'keyword' как строке, так как он не завершен нулем ... –

+0

' for (int i = 0, n = strlen' должен быть 'size_t i' not 'int'. То же самое происходит здесь' keyword [i] = toupper' преобразование между 'char' и' int' – Michi